|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
PropertyBag and settingsconvenient way to save program settings. I'm wondering if anyone has done this and might have comments or thoughts about it: Write a DLL with a window for changing settings. The main program would call a function in the DLL public class to show the settings window. Include a PublicNotCreatable class ("CSets") that stores those settings. The CSets state gets retrieved as a byte array, which is saved to disk, when the DLL unloads. Likewise, the persisted CSets class gets created with that byte array at load. The gist of that is that a PropertyBag is created with a single property, the value of which is the CSets class itself. The persisted class is then restored by reading back the byte array from disk, assigning that byte array as the Contents of a PropertyBag, then setting a new instance of CSets as PropetyBag.Contents. The main program creates the DLL public class when it loads and asks for an instance of CSets, gettings all of the saved program settings in one call without needing to parse XML, INI, or read the Registry. The public class has an event Changed that fires whenever settings are changed, at which point the main program sets its CSets instance to Nothing and gets a new copy. On the downside, the class CSets will have to be fairly verbose. All of the persisted values have to be maintained with wordy calls to ReadProperty, WriteProperty, and PropertyChanged. Another disadvantage is that it adds a DLL that must be registered during install. But from inside the main program there's very little to do -- just load the DLL at launch and store an up-to-date copy of CSets in order to apply program settings while running. Make sense? Don't know why you make it so complicated, at least
concerning window settings. To save and reload window settings I simply use a little bit of code in the form_load and unload event, precisely a simple call to a public save and to a restore sub., like "SaveSettings Me" and "LoadSettings Me". To save additional form specific data you could pack them into a string, something like "Par1=xxx;Par2=xxx;Par3=xxx" and pass this string as second parameter. That's quite fast enough and bullet proof, and each other code which needs it can it read out, edit, and store in the same way. Not sure I totally understand what you are asking but!
The PropertyBag is only available to write to within the IDE, not to the compiled exe, it dosn't exist in it, or anywhere really. It's a UserControl Method for storing settings and info at exe design time The bag does one of two things with the data it wants to save, it will either store short strings in the frm file, or any other info it stores in a frx file. When you say program, do you mean IDE or EXE? Ivar "Ivar" <Ivar.ekstromer***@ntlworld.com> wrote in Actually, that is incorrect. The property bag *is* available at runtime. news:22Ynl.20347$Dz4.14442@newsfe20.ams2: > Not sure I totally understand what you are asking but! > The PropertyBag is only available to write to within the IDE, not to > the compiled exe, it dosn't exist in it, or anywhere really. I use it to store icons, and you can add and remove stored 'properties' at will. It's could be a bit of a PITA depending on wwhat you want to store, but it works as advertised. For x = 1 To ilMenu.ListImages.Count picHidden.Picture = ilMenu.ListImages(x).Picture picHidden.Picture = picHidden.Image pb.WriteProperty "" & iCount & "KEY", ilMenu.ListImages(x).key pb.WriteProperty "" & iCount & "ICON", picHidden.Image iCount = iCount + 1 Next x pb.WriteProperty "ICOUNT", iCount - 1 I then have a couple of more groups of things stored as text. I then save the PropBag to disk....... 'finally, write the contents of the PB to a file. pbC = pb.Contents Open appPath & "menus\" & mName & ".DDTmenu" For Binary As #1 Put #1, , pbC Close #1 Set pb = Nothing And then to restore, the process is done in reverse..... '// Set the file handle fFile = FreeFile Open menuPath For Binary As #fFile Get #fFile, , pbC pb.Contents = pbC Close #fFile Now the PB holds evrthing it did before it was saved to the HD. Regards, DanS Show quoteHide quote > It's a > UserControl Method for storing settings and info at exe design time > The bag does one of two things with the data it wants to save, it will > either store short strings in the frm file, or any other info it > stores in a frx file. > When you say program, do you mean IDE or EXE? > "mayayana" <mayayaX***@rcXXn.com> wrote in news:#I6bDXElJHA.6124 @TK2MSFTNGP02.phx.gbl:> I've just been looking into an idea for a (Near-top posted for brevity...)> convenient way to save program settings. > I'm wondering if anyone has done this and > might have comments or thoughts about it: Comments....why so involved ? Why not just save/restore setting's in your main program, why in a DLL ? But otherwise, it will work. See my post to Ivar for some more details, but it seems like you've got them down....save the contents (binary) to a file to save..read the file in one binary chunk and set the PB contents to it. Regards, DanS Show quoteHide quote > > Write a DLL with a window for changing settings. > The main program would call a function in the DLL > public class to show the settings window. > > Include a PublicNotCreatable class ("CSets") that > stores those settings. > > The CSets state gets retrieved as a byte array, > which is saved to disk, when the DLL unloads. > Likewise, the persisted CSets class gets created > with that byte array at load. > The gist of that is that a PropertyBag is created > with a single property, the value of which is the > CSets class itself. The persisted class is then restored > by reading back the byte array from disk, assigning that > byte array as the Contents of a PropertyBag, then > setting a new instance of CSets as PropetyBag.Contents. > > The main program creates the DLL public class > when it loads and asks for an instance of CSets, > gettings all of the saved program settings in one > call without needing to parse XML, INI, or read > the Registry. > > The public class has an event Changed that fires > whenever settings are changed, at which point the > main program sets its CSets instance to Nothing > and gets a new copy. > > On the downside, the class CSets will have to be fairly > verbose. All of the persisted values have to be maintained > with wordy calls to ReadProperty, WriteProperty, and > PropertyChanged. Another disadvantage is that it adds > a DLL that must be registered during install. But from inside > the main program there's very little to do -- just load the > DLL at launch and store an up-to-date copy of CSets in > order to apply program settings while running. > > Make sense? > > > > > Thanks. I was thinking of using it in the way> Comments....why so involved ? Why not just save/restore setting's in your > main program, why in a DLL ? > > But otherwise, it will work. > > See my post to Ivar for some more details, but it seems like you've got > them down....save the contents (binary) to a file to save..read the file > in one binary chunk and set the PB contents to it. > you described. I don't particularly need a DLL. I was just dealing with a sprawling program and the settings window alone is fairly involved. So I'm thinking about splitting things up. The Settings menu would create an instance of the DLL, which would then load the last class state, configure the settings window accordingly, and show the settings window. Then if there have been changes when the window closes, the main EXE retrieves a new copy of the settings class, the DLL saves the class state, and the DLL is unloaded. It's a bit confusing. Somehow it doesn't seem quite right that I can hold onto a settings class after the DLL is unloaded, but it seems to work OK. There's a reference set to the DLL, so the main EXE knows what a "CSets" class is. (I'm creating the DLL instance via a main class, which then passes me a CSets class and sets its own CSets instance to Nothing. I then set the main DLL instance class to nothing and am left with just a lightweight class holding all of the latest settings.) "mayayana" <mayayaX***@rcXXn.com> wrote If all your settings are simple data types (not> I've just been looking into an idea for a > convenient way to save program settings. > I'm wondering if anyone has done this and > might have comments or thoughts about it: objects or pictures, etc) then a very simple method is to use a User Defined Type which can be loaded or saved to disk in one easy operation.... LFS > That seemed like it might be a good idea, but the> If all your settings are simple data types (not > objects or pictures, etc) then a very simple > method is to use a User Defined Type which > can be loaded or saved to disk in one easy > operation.... > result of testing it was ugly. :) I got some odd errors and crashes. I'm not so sure that I can use a property that's a UDT, anyway, but even if I could, the PropertyBag WriteProperty method can't take a UDT.
Show quote
Hide quote
"mayayana" <mayayaX***@rcXXn.com> wrote What were you doing with the Property Bag?> > > > If all your settings are simple data types (not > > objects or pictures, etc) then a very simple > > method is to use a User Defined Type which > > can be loaded or saved to disk in one easy > > operation.... > > > > That seemed like it might be a good idea, but the > result of testing it was ugly. :) I got some odd errors > and crashes. I'm not so sure that I can use a property > that's a UDT, anyway, but even if I could, the PropertyBag > WriteProperty method can't take a UDT. Private Type UserSettings A as long B as Long .. etc... End Type Dim us as UserSettings Sub Form_Load() SF = Freefile Open SettingsFile for binary as SF Get SF, , us Close SF End Sub The write operation is the same except for Put where Get is. I can't imagine how that could get ugly. The ONLY hard part is deciding where the settings file needs to go..... LFS I see what you mean. You're suggesting to use
the UDT as property storage to write to disk. That's fine. Or I could use an INI file like I've been using. That works well. But what I liked about this PropertyBag method is that I can essentially save a class to disk. I use a PropertyBag with a single property, and to that property I assign the class itself. The PropertyBag.Contents is then a byte stream, reflecting the state of the class, which gets written to a file. So it's easy to populate the class on load. VB does it for me. I just read in the byte stream, assign it to the Contents of anoyher PropertyBag, then "read" the single property into a class object variable. Then I can pass that class to the main EXE and it won't need to have any settings variables of its own. It can just work straight out of the class. For instance, if I used to save a text color in the Registry or in an INI file, I'd need to retrieve it at startup, store it in a variable, and then do something like: Ob.SelColor = TColor With the PropertyBag approach I can save all of the settings as a class "snapshot" that gets loaded again on next run. So there's no retrieval work and no variables. I can just do: Ob.SelColor = ClassSettings.TColor And when someone changes settings I can just set my class to nothing and get a new copy. I had hoped that I could take a snapshot of the whole class using this method, just capturing the memory it inhabits, but it turns out that it can't work that way. If I don't use the Class_ReadProperties and Class_WriteProperties subs, as well as using PropertyChanged when a property is changed, then the values don't get written to disk. So it seems like this method should work well but if I have, say, 50 program settings then it's rather verbose. I'll need 100 Properties ( Get/Let * 50) plus very long Class_ReadProperties and Class_WriteProperties subs. I'm thinking that I might try to somehow use some arrays to store multiple values. I don't know yet whether the PropertyBag can handle that. Show quoteHide quote > > What were you doing with the Property Bag? > > Private Type UserSettings > A as long > B as Long > .. etc... > End Type > > Dim us as UserSettings > > Sub Form_Load() > SF = Freefile > Open SettingsFile for binary as SF > Get SF, , us > Close SF > End Sub > > > The write operation is the same except for Put where > Get is. I can't imagine how that could get ugly. > The ONLY hard part is deciding where the settings > file needs to go..... > > LFS > > "mayayana" <mayayaX***@rcXXn.com> wrote That would certainly have its uses in some> I see what you mean. You're suggesting to use > the UDT as property storage to write to disk. > That's fine. Or I could use an INI file like I've > been using. That works well. But what I liked > about this PropertyBag method is that I can > essentially save a class to disk. situations, but I would suggest its overkill for this task. Does all the extra overhead justify the means? <...> > For instance, if I used to save a text color Where is that different from using the Type, which> in the Registry or in an INI file, I'd need to retrieve > it at startup, store it in a variable, and then do > something like: > Ob.SelColor = TColor > With the PropertyBag approach I can save all of the > settings as a class "snapshot" that gets loaded again > on next run. So there's no retrieval work and no > variables. I can just do: > Ob.SelColor = ClassSettings.TColor after being read from the disk is nearly the exact same syntax? Ob.SelColor = US.TColor > And when someone changes settings I can just set Similarly with the Type, you need only call a function> my class to nothing and get a new copy. to clear out all variables, or to set them to defaults: Function BlankSettings() As UserSettings ' Erases all settings ex: US = BlankSettings End Function Function DefaultSettings() As UserSettings ' Set defaults ex: US = DefaultSettings With DefaultSettings A = 1 B = "Two" ' ... etc ... End With End Function It is usually the case where 'settings' are specific to the application they reside in. Sure, window positions, and a few other common courtesy settings are often included, but there are usually going to be a majority of values specifically used and named for each app you write. So my question is, with all that overhead of property Lets and Gets in the class, added to the code required to use the Propertybag, are you going to want to go through that every time you need a settings class? If you instead put a settings type declaration in a standard module, along with the Read and Save functions, you have a module template that needs only adjustments to the type variable names to adapt to each new project. So, excluding the 'cool' factor of saving the entire class, is it really going to be worth the effort? That is, (again,) if all your data is held by intrinsic data types, or arrays of instrinsic types..... LFS > Does all the extra overhead justify the means? I'm not sure. That's why I'm inviting comments> and criticism. It is a clunky method "under the covers". It "feels" like saving the class whole, in it's current state, but what it really entails is just using a custom .FRX-type file that stores byte data, strings and objects. (I've discovered that I can save an array, but only dynamic byte arrays. So to save a Long array I have to quadruple the UBound and add a CopyMemory call to the Get/Let Properties.) > There's no difference there. And it's not different from> Where is that different from using the Type, which > after being read from the disk is nearly the exact same > syntax? > my usual method of just storing global settings variables: Ob.SelColor = TColor > I like your idea of the UDT better than just using> If you instead put a settings type declaration in a > standard module, along with the Read and Save > functions, you have a module template that needs > only adjustments to the type variable names to > adapt to each new project. > > So, excluding the 'cool' factor of saving the entire > class, is it really going to be worth the effort? > global variables. And the class may not be worth it. But it's not just a "cool factor". (It's certainly not very cool to write all those properties. :) I guess the potential appeal of the class boils down to two things: 1) I don't have to parse out all of the settings (INI/DAT storage), or make numerous Registry calls (Registry storage). And I never have to rewrite the values to disk or Registry. VB has to do it, and it's not pretty, but my code can skip that step. I just have to have a short function at load time to read the settings file into a byte array, and a short function whenever settings are changed to save the new byte array to disk and update my copy of the class. Aside from those I can treat the settings class as self-populating, self-updating. 2) #2 is specific to the idea of having a separate settings DLL. I'm in a situation where a program has become large and complex, and I'm thinking of breaking out some parts. One of those is the settings window. Using the PropertyBag/ Class allows me to put the settings window and settings values storage into a DLL that can pass all of the settings as a piece by passing a class instance. I don't actually need the PropertyBag for that. I could use a DLL and just save settings to disk or Registry as usual. But I'd still need to use a class to hold all the settings if I want to be able to pass them all in a piece to the main EXE and avoid calling an external library in the middle of functions, to retrieve values that should be locally stored. I don't think I can use a UDT, though maybe that's possible with early binding. (?) Maybe I could use a Collection, but that seems somewhat awkward, and Collections are slow. So if I *do* decide to use a class, then at that point it seems I'd be crazy not to use the PropertyBag method to make the class self-updating. At that point I run into another question: If I'm going to use this DLL, is it better to load the DLL only at startup and when someone wants to change settings, since settings are likely to mostly stay the same once they've been selected? Or is it better to just run the DLL for the life of the main EXE? I've noticed that on Win98, at least, there seems to be a limit to how much VB software can be running. Maybe it has to do with an hWnd limit. NT seems to be much more sturdy and strong in that regard. Nevertheless, I like the idea of keeping all of those buttons, textboxes, etc. that are loaded in the settings window, out of memory most of the time. It would notably decrease the footprint of the program. "mayayana" <mayayaX***@rcXXn.com> wrote You're missing Intellisense.....> > > > Where is that different from using the Type, which > > after being read from the disk is nearly the exact same > > syntax? > > There's no difference there. And it's not different from > my usual method of just storing global settings variables: > > Ob.SelColor = TColor Show quoteHide quote > > If you instead put a settings type declaration in a You saw the IO used to get the UDT, it was 3 lines> > standard module, along with the Read and Save > > functions, you have a module template that needs > > only adjustments to the type variable names to > > adapt to each new project. > 1) I don't have to parse out all of the settings > (INI/DAT storage), or make numerous Registry calls > (Registry storage). And I never have to rewrite the > values to disk or Registry. > VB has to do it, and it's not pretty, but my > code can skip that step. I just have to have a short > function at load time to read the settings file into a > byte array, and a short function whenever settings > are changed to save the new byte array to disk and > update my copy of the class. of code (Open, Get, Close). From that you get all the settings, no re-creating a class and whatever else for the PropertyBag.... > 2) #2 is specific to the idea of having a separate settings The last part is the key to whole design. You typically use> DLL. I'm in a situation where a program has become large > and complex, and I'm thinking of breaking out some parts. > One of those is the settings window. Using the PropertyBag/ > Class allows me to put the settings window and settings values > storage into a DLL that can pass all of the settings as a piece > by passing a class instance. I don't actually need the > PropertyBag for that. I could use a DLL and just save settings > to disk or Registry as usual. But I'd still need to use a class > to hold all the settings if I want to be able to pass them all in > a piece to the main EXE and avoid calling an external library in > the middle of functions, to retrieve values that should be > locally stored. settings in diverse places in your main EXE, so they need to be globally available. If you have several forms, you either have to declare the class gobally, or you have to pass the class between forms, to those that need it. Most will say using global variables should be avoided, but this is one case where it is the more robust option. Passing an object between forms could get to be a hard to maintain tangled mess. Whereas declared globally, it becomes available to all forms within the application. > I don't think I can use a UDT, though maybe You can't access a UDT late bound, its always early bound,> that's possible with early binding. (?) so to speak. The only real advantage to using a class in this instance is that a class has Initialize and Terminate events you could use to access the disk, and the ability to validate input in the Property Let events. With a UDT, you'd have to decide when to access the disk, and would need to validate the input where needed. But other than that, accessing the properties would be exactly the same. The advantage of the UDT is in it reduced code requirement. > At that point I run into another question: If I'm going to Windows pretty much handles the loading and unloading of> use this DLL, is it better to load the DLL only at startup and > when someone wants to change settings, since settings are > likely to mostly stay the same once they've been selected? > Or is it better to just run the DLL for the life of the main EXE? such code modules. Even if you set your class to nothing that does not ensure the DLL will be removed from memory. I guess the best teacher here is experience. Try it both ways and see which you prefer.... I just don't see the comparison myself. There is so little code needed when using the UDT, (even while it provides most of the benefits of class like access,) that it seems obvious which to use for typical applications. If you need to store complex data types, then a PropertyBag may be put to use, but for simple data types, why add major effort for little gain? As far as the smaller footprint, you still need to show the settings window, but you should already know how to control when that is moved into and out of memory. Right? Consider the code below as if it were added to a Standard module. To use it you need only assign the SettingsFile file name and call the Settings routine. To re-use it in another application you need only change the variables in the UDT if need be, and its ready to go.... ??? LFS Option Explicit Public Type UserSettings A As Long B As String C() As Byte End Type Public Enum SettingsOptions usWrite = -1 usDefault = 0 usRead = 1 End Enum Public US As UserSettings Public SettingsFile As String Public Sub Settings(ByVal Mode As SettingsOptions) Dim sf As Long If Mode = usDefault Then US = DefaultSettings Else sf = FreeFile On Error GoTo Handler Open SettingsFile For Binary As sf If Mode < usDefault Then Put sf, , US Else Get sf, , US End If Close sf On Error GoTo 0 End If Handler: If Err.Number <> 0 Then Close MsgBox Err.Description, vbOKOnly, "User Settings Disk Access" End If End Sub Public Function DefaultSettings() As UserSettings ' reset settings End Function Aha! That's very nice. Thank you. I had no
idea that so many data types could be stored. I assumed that you were just recommending the UDT for holding settings but were populating it by reading out the settings file and filling the UDT. What you've got is really just what I had "hoped" the PropertyBag was: A way to essentially just write the memory of a data structure to disk. I didn't think it would be possible to write the content of pointer variables to disk. I tried a UDT with a string array and a long array. Both work fine. The only limitation seems to be that one can't assign the member to a fixed array. But that's no problem, since it can be assigned to an empty dynamic array. I can either do: Dim A() as string A = US.D s1 = a(0) Or: s1 = US.D(0) And I have no trouble passing the UDT from an ActiveX DLL as long as there's an early-binding reference in the calling EXE. I also tried out some code from Matthew Curland for loading COM DLLs without registration. It's a fairly compact bit of code and seems to work well. I can't imagine that he would have put it into his book if it wasn't dependable. So that means I can have my settings window in a DLL, pass the UDT to the main EXE, and do it all without needing to register components. I think you're right that that's much better than the Class/PropertyBag method. "mayayana" <mayayaX***@rcXXn.com> wrote That's what I was saying from the start. Have a> Aha! That's very nice. Thank you. I had no > idea that so many data types could be stored. look at my first response in this thread.... > So that means I can have my settings window in So I'm curious, why someone would do that. Could you> a DLL, pass the UDT to the main EXE, and do it all > without needing to register components. list for me the advantages to the user such a DLL offers, and then the advantages to the programmer. It just seems to me you are trying to make an optimization that has little to no positive effect. The downside is that you'd unecessarily add a dependancy to your app. I assume you realize that VB loads modules on demand. If you don't call up your settings form, it doesn't load into memory. You could leave your settings window in the EXE and it would never be loaded, unless the user specifically asks for it. What gain are you expecting to realize from the move? LFS
Show quote
Hide quote
"Larry Serflaten" <serfla***@usinternet.com> wrote in message Yep. It sounds more like a response to poorly managed resources. If the news:e2OJVhUlJHA.3888@TK2MSFTNGP02.phx.gbl... > > "mayayana" <mayayaX***@rcXXn.com> wrote >> Aha! That's very nice. Thank you. I had no >> idea that so many data types could be stored. > > That's what I was saying from the start. Have a > look at my first response in this thread.... > > >> So that means I can have my settings window in >> a DLL, pass the UDT to the main EXE, and do it all >> without needing to register components. > > So I'm curious, why someone would do that. Could you > list for me the advantages to the user such a DLL offers, > and then the advantages to the programmer. > > It just seems to me you are trying to make an optimization > that has little to no positive effect. The downside is that > you'd unecessarily add a dependancy to your app. I assume > you realize that VB loads modules on demand. If you don't > call up your settings form, it doesn't load into memory. > You could leave your settings window in the EXE and it > would never be loaded, unless the user specifically asks > for it. > settings are fundamental to the application, then that should be part of the application. Even if dealing with localization, only the static default values would be in a resource only dll. > What gain are you expecting to realize from the move? It's true that I could just not load the form> when it's not needed, but as I said earlier, the whole thing has become unwieldy. It's at a point where I want to break out some of the pieces so that I can work on them separately.
How to embed a Manifest File?
Graphic Time Labeling how to reposition desktop icons ADO Recordset Find method Problem Test (yeah, I know) Visual Basic 6.0 on 64-Bit system Re: create pdf file in VB6 VB6 with SQLite: Is there a report generator/viewer? How to switch the monitor off through vb6 code? Shell Function: task ID |
|||||||||||||||||||||||