I want to port a VB6 app to VB2005 while simplifying as much as possible. The current program uses multiple random access files to store data, both for user options and individual companies that are independent projects. My question is about converting multiple complex user-defined types into structures and then saving them in two files-- user options and company-specific. This is what I intend doing but would appreciate suggestions on a better way.
1. Create structures for the types, combining as many as make sense into single structures. The user options will be one structure. These structures must be available throughout the entire application.
2. Create a collection of company-specific structures. There is one collection for each company project. There could be hundreds of company projects.
3. Binary serialize the collection and save it to the location for the company project(usually on a networked drive).
4. Serialize the user options and save it (usually on the local machine).
The persisted data would be de-serialized when the program starts (user options) and when the company information is loaded.

Need Help Simplifying
Gabyx
m.m.b.
Scott,
Thank you very much for your suggestion. I have used settings in VB6 but this way is much better. I have marked both your suggestion and the one about using XML as answers.
gafrank
I'd suggest that, at the very least, you look into storing this data as XML which can be validated with an appropriate schema. This gives you a lot more flexibility in terms of making changes to the "reader" code, allows you to import the data directly with the appropriate type, and allows you to manually edit the files if you absolutely must. Binary data files are a huge pain, and they're nearly always incomprehensible to anybody who isn't the developer.
harley_8006
Scott,
Thanks for pointing out the settings designer. I think it will do the settings quite nicely and will use it. Do you have an opinion you are willing to share about the company files
SnowJim
I solved the problem of serialization by moving the structures outside the class (e.g., immediately below the imports statements) and adding <Serializable> attribute. An error occurs when the structure is inside the class. I also found the reference to the SOAP formatter. All that works now.
I will implement both suggestions: Use XML and using the built-in settings for application and user. I want to accept both suggestions as the answer but am not sure how.
Many thanks to both of you for your excellent suggestions.
gudel
For storing user settings I would take a look at the settings designer.
It makes reading and writing user scoped configuration data very easy. In particular, with the settings designer the IDE will auotmatically generate the class that stores the settings values along with all the logic to read and write the values to and from your program. All you have to do is tell the deigner what you want your settings to be named and what type of data you are storing and it will handle the rest (make sure that you tell the settings designer to use "User Scope" settings as opposed to "Application Scope" settings).
You can access it by bringup your project's property dialog (right click on the project in the solution explorer and select properties) and clicking on the settings tab. You can then read and write these settings in code via My.Settings (setting "X" will be accessible via My.Settings.X). To load the settings from disk call My.Settings.Reload(). To save them call My.Settings.Save(). This will autoamtically save the settings to a an application specific file in the users "personal directory" (i.e. C:\documents and settings\Phantom208").
- Scott Wisniewski
brian_tsim
DMan1,
Not really. The database would be much more difficult than serializing the collection. Each of the files contains only one record which is very long and consists of strings and numeric arrays. I wrote the original program when I was just learning VB6 after years of programming in FORTRAN. Databases were pretty foreign to me then and I did not know how to handle the different types of structures in one file.
hotaruu
Duck Thing:
I will surely look at XML. Since I have never done either the serializing or XML, I have to learn whichever one I use. It will take a few days to study up on it and run some tests. I'll respond to this thread about my choice and why. Thanks for your thoughtful response.
Earl Hood
Duck Thing:
Here is my feeble attempt which has led to an error I cannot resolve. The easiest thing to do is create a hash table of structures. the following code has two structures which I put into a hash table, clear the structures, read the structures from the hash table and print to a message box to confirm the hash table and then try to persist the table via a binary serialization. (I used binary because I could not get the SOAP formatter to appear in my VB 2005 Express. Maybe when the professional version comes in a few days I can use SOAP. Oddly enough, the Word Frequencies project in Mastering Visual Basic 2005 uses SOAP and it worked fine. I can't figure out what the difference is. Maybe in a few days.)
The error appears in the attempt to serialize the hash table. I think it means that structures cannot be serialized. If that is so, I'm stuck. I would hate to have to use the individual elements of all the structures. The code followed by the error detail is:
****************************Code**********************************
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Public Class TestHashTable
Dim hTable As New Hashtable
Public Structure CompanyInformation
<VBFixedString(40)> Dim CompanyName As String
<VBFixedString(16)> Dim IntAudNbr As String
<VBFixedString(30)> Dim TypeAuditFile As String
Dim RecNo As Short
<VBFixedString(100)> Dim DataPath As String
End Structure
Public Structure AuditorInformation
Dim AuditorName As String
Dim AuditorPhone As String
Dim AuditorEMail As String
End Structure
Dim CompanyInfo As New CompanyInformation
Dim AuditorInfo As New AuditorInformation
Private Sub btnProcess_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProcess.Click
With CompanyInfo 'store values in the hash table
.CompanyName = txtInputCompanyName.Text
.IntAudNbr = txtInputAuditNumber.Text
.RecNo = txtInputRecordNbr.Text
.TypeAuditFile = txtInputAuditType.Text
.DataPath = txtInputDataPath.Text
End With
hTable.Add("CompanyInfo", CompanyInfo)
With AuditorInfo
.AuditorName = txtInputAuditorName.Text
.AuditorPhone = txtInputAuditorPhone.Text
.AuditorEMail = txtInputAuditorEMail.Text
End With
hTable.Add("AuditorInfo", AuditorInfo)
'Clear the structures
With CompanyInfo
.CompanyName = "Cleared"
.IntAudNbr = "Cleared"
.RecNo = 0
.TypeAuditFile = "Cleared"
.DataPath = "Cleared"
End With
With AuditorInfo
.AuditorName = "Cleared"
.AuditorPhone = "Cleared"
.AuditorEMail = "Cleared"
End With
ShowHashTableContents(hTable)
Dim savefile As FileStream
SaveFileDialog1.DefaultExt = "XML;"
If SaveFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
savefile = File.OpenWrite(SaveFileDialog1.FileName)
savefile.Seek(0, SeekOrigin.End)
Dim Formatter As BinaryFormatter = New BinaryFormatter
Formatter.Serialize(savefile, hTable) '******************Here is the error******************
savefile.Close()
MsgBox("File saved.")
End If
End Sub
Private Sub btnRead_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRead.Click
Dim readFile As FileStream
OpenFileDialog1.DefaultExt = "BIN"
If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
readFile = File.OpenRead(OpenFileDialog1.FileName)
Dim de As DictionaryEntry
Dim hTable2 As New Hashtable
Dim BFormatter As New BinaryFormatter
hTable2 = CType(BFormatter.Deserialize(readFile), Hashtable)
readFile.Close()
For Each de In hTable2
Select Case de.Key
Case "CompanyInfo"
CompanyInfo = de.Value
Case "AuditorInfo"
AuditorInfo = de.Value
End Select
Next
txtOutputCompanyName.Text = CompanyInfo.CompanyName
txtOutputAuditNbr.Text = CompanyInfo.IntAudNbr
txtOutputRecordNbr.Text = CompanyInfo.RecNo
txtOutputAuditType.Text = CompanyInfo.TypeAuditFile
txtOutputDataPath.Text = CompanyInfo.DataPath
txtOutputAuditorName.Text = AuditorInfo.AuditorName
txtOutputAuditorPhone.Text = AuditorInfo.AuditorPhone
txtOutputAuditorEmail.Text = AuditorInfo.AuditorEMail
End If
End Sub
Private Sub ShowHashTableContents(ByVal table As Hashtable)
Dim key As Object
Dim MsgLine As String = "hTable contains " & hTable.Count.ToString & " elements." & vbCrLf
For Each key In table.Keys
Select Case key
Case "CompanyInfo"
CompanyInfo = table.Item(key)
MsgLine = MsgLine & key.ToString & vbCrLf
MsgLine = MsgLine & CompanyInfo.CompanyName & vbCrLf
MsgLine = MsgLine & CompanyInfo.IntAudNbr & vbCrLf
MsgLine = MsgLine & CompanyInfo.RecNo.ToString & vbCrLf
MsgLine = MsgLine & CompanyInfo.TypeAuditFile & vbCrLf
Case "AuditorInfo"
AuditorInfo = table.Item(key)
MsgLine = MsgLine & key.ToString & vbCrLf
MsgLine = MsgLine & AuditorInfo.AuditorName & vbCrLf
MsgLine = MsgLine & AuditorInfo.AuditorPhone & vbCrLf
MsgLine = MsgLine & AuditorInfo.AuditorEMail & vbCrLf
End Select
Next
MsgBox(MsgLine)
End Sub
End Class
*********************Error Message*******************
System.Runtime.Serialization.SerializationException was unhandled
Message="Type 'TestHashTableXML.TestHashTable+AuditorInformation' in Assembly 'TestHashTableXML, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable."
Source="mscorlib"
StackTrace:
at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
at TestHashTableXML.TestHashTable.btnProcess_Click(Object sender, EventArgs e) in D:\VB2005 Testing Programs\TestHashTableXML\TestHashTable.vb:line 61
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
at TestHashTableXML.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
**************************End of Code and Detail*****************************
I have tried to mark the structure as serializable but that causes a compiler error.
I appreciate your help.