Trouble Cloning Objects between Projects

MyForumID

Active member
Joined
Sep 25, 2005
Messages
26
Programming Experience
Beginner
Hi,

I have a project that saves a certain class via a binary stream. I am trying to make a DLL with limited functionality that uses the same classes for a separate application.

The class is big enough that I prefer not to have to code out the entire thing in text to transfer it to the dll.

The problem is that when I try to load the object - it's not being recognized by the new program because it was made by the other program - even though the classes are identical. Apparently the stream is storing the name of the program in the object.

Can anyone please help - or am I stuck with having to transfer everything in text and remake the object files?

I've included the code for the object saving/loading and the command that's failing.

Thanks in advance.

VB.NET:
[SIZE=2][COLOR=#0000ff]Public[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Shared[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Function[/COLOR][/SIZE][SIZE=2] CloneObject([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] originalObject [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE][SIZE=2]) [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] BinFormatter [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] BinaryFormatter[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] memStream [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] MemoryStream[/SIZE]
[SIZE=2]BinFormatter.Serialize(memStream, originalObject)[/SIZE]
[SIZE=2]memStream.Position = 0[/SIZE]
[SIZE=2]CloneObject = BinFormatter.Deserialize(memStream)[/SIZE]
[SIZE=2]memStream.Close()[/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Function[/COLOR][/SIZE]
 
[SIZE=2][COLOR=#0000ff]Public[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Shared[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE][SIZE=2] SaveObjectFile([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] fileName [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String[/COLOR][/SIZE][SIZE=2], [/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] saveObject [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE][SIZE=2])[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] fileStream [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] FileStream(fileName, FileMode.Create)[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] fileFormatter [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] BinaryFormatter[/SIZE]
[SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
[SIZE=2]fileFormatter.Serialize(fileStream, saveObject)[/SIZE]
[SIZE=2][COLOR=#0000ff]Finally[/COLOR][/SIZE]
[SIZE=2]fileStream.Close()[/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE]
 
[SIZE=2][COLOR=#0000ff]Public[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Shared[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Function[/COLOR][/SIZE][SIZE=2] LoadObjectFile([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] fileName [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String[/COLOR][/SIZE][SIZE=2]) [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] fileStream [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] FileStream(fileName, FileMode.Open)[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] fileFormatter [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] BinaryFormatter[/SIZE]
[SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
[SIZE=2]LoadObjectFile = [/SIZE][SIZE=2][COLOR=#0000ff]CType[/COLOR][/SIZE][SIZE=2](fileFormatter.Deserialize(fileStream), [/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE][SIZE=2])[/SIZE]
[SIZE=2][COLOR=#0000ff]Finally[/COLOR][/SIZE]
[SIZE=2]fileStream.Close()[/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Function[/COLOR][/SIZE]

Here's the load part that's failing:
VB.NET:
[SIZE=2]myNewObject = [/SIZE][SIZE=2][COLOR=#0000ff]CType[/COLOR][/SIZE][SIZE=2](LoadObjectFile(ObjectFileName), MyObjectClass)[/SIZE]
 
Instead of declaring the class locally in both assemblies, define the class object to be serialized in a Class Library and reference this from all other assemblies.
 
Thanks. So I tried making a library dll now. I could access the classes via the old dll as I had hoped in visual studio and it was built just fine, but unfortunately when I try to access the original dll, the error message just changes. Now instead of saying it can't locate the assembly for the original program, it says it can't locate the assembly for the new libraryclass dll.

I don't know if this makes a difference or not, but here's the whole situation. I have a program that sets up a very large object and then saves it through serialization. I have a program that uses COM dll's that needs to access that object and get information back. I made a COM dll that can be accessed and do things like return a filename or simple arrays. When I try to load the object that was saved though - that's when I get the error.

EDIT: Actually, I just tried commenting out the line that loads the file - the error is actually coming just because it's trying to import the librarydll. I thought about making the libraryclass a COM class, but unfortunately I don't think COM classes can be access by my original program. I'm really stuck here :(

I had to regasm the COM dll and after making the new libraryclass, I tried regasm'ng that too, but I'm still getting the error.

Unfortunately, I'm lost without being able to access that object :( I need to do one of the following:

1) Find a way to desrialize that object via the COM dll

2) Access the needed functions by using my original exe file as if it were a COM dll (no idea if that's even possible)

3) Find a way to save that object without having to indiviudally texting out 100's of arrays of arrays of arrays (the object has many arrays of subobjects which also have subobject arrays) and without having it stamped with the file name.

I thought 1 would be the easiest but I'm wondering if there's another way to save the objects...

Thanks for any help.
 
Not sure what you're saying there. To serialize the class must be marked with the Serializable attribute. Serialization is assembly specific, so to serialize between different assemblies the class must be defined in a commonly referenced class library assembly. I don't think COM support .Net serialization, but you may gather the information you need from COMs into a .Net class object and serialize this if that was what you meant.
 
I figured it out :)

My classes did have the Serializable attribute and they worked fine within the project. Once it was saved though if you tried to load it through another project it didn't work. The problem is that I was using the Binary formatter. After hours of messing around with things that are way over my head (e.g. setting keys and assemblies and whatever else I didn't understand), I found out how to do it. It's an ugly solution but it works so I don't really care...

Basically, instead of using the binary serialization if you use XML serialization then it works fine. I tried saving the object as file both with xml and with my original method. Then using a different project that is basically an exact copy of the original project - I was unable to load the object saved with the binary method. The file saved through the XML serialize method however loaded the object just fine :)

It's ugly for two reasons. First because it exposes the object to everyone since it's basically just a text file. The second is because while the binary method is completely generalized for any class, with this method you need to write a separate set of methods for each different class (I think - I couldn't get the place where it says "YourClass" in the code to figure out what type it was automatically). For those who run into the same problem I had - here's the code for the XML methods:

VB.NET:
[SIZE=2][COLOR=#0000ff]Imports[/COLOR][/SIZE][SIZE=2] System.Xml.Serialization[/SIZE]
 
[SIZE=2][COLOR=#0000ff]Public[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE][SIZE=2] XMLSaveObjectFile([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] fileName [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String[/COLOR][/SIZE][SIZE=2], [/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] saveObject [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE][SIZE=2])[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] sw [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] StreamWriter = File.CreateText(fileName)[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] xml_serializer [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] XmlSerializer[/SIZE]
[SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
[SIZE=2][COLOR=#008000]' Create the XmlSerializer. GetType(object) tells the[/COLOR][/SIZE]
[SIZE=2][COLOR=#008000]' serializer about the object class.[/COLOR][/SIZE]
[SIZE=2]xml_serializer = [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] XmlSerializer([/SIZE][SIZE=2][COLOR=#0000ff]GetType[/COLOR][/SIZE][SIZE=2](YourClass))[/SIZE]
[SIZE=2][COLOR=#008000]' Make the serialization, writing it into the StringWriter.[/COLOR][/SIZE]
[SIZE=2]xml_serializer.Serialize(sw, saveObject)[/SIZE]
[SIZE=2][COLOR=#0000ff]Finally[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE]
 
[SIZE=2][COLOR=#0000ff]Public[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE][SIZE=2] XMLLoadObjectFile([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] fileName [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String[/COLOR][/SIZE][SIZE=2], [/SIZE][SIZE=2][COLOR=#0000ff]ByRef[/COLOR][/SIZE][SIZE=2] loadObject [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Object[/COLOR][/SIZE][SIZE=2])[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] fStream [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] FileStream = [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] FileStream(fileName, FileMode.Open)[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] xml_serializer [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] XmlSerializer([/SIZE][SIZE=2][COLOR=#0000ff]GetType[/COLOR][/SIZE][SIZE=2](YourClass))[/SIZE]
[SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] string_reader [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] StringReader[/SIZE]
[SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
[SIZE=2][COLOR=#008000]' Create the new object from the serialization.[/COLOR][/SIZE]
[SIZE=2]loadObject = [/SIZE][SIZE=2][COLOR=#0000ff]CType[/COLOR][/SIZE][SIZE=2](xml_serializer.Deserialize(fStream), YourClass)[/SIZE]
[SIZE=2][COLOR=#0000ff]Finally[/COLOR][/SIZE]
[SIZE=2]fStream.Close()[/SIZE]
[SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Try[/COLOR][/SIZE]
 
It really isn't more difficult than to do what I have said two times already, define the class to serialize in a separate class library, not locally.

Attached is a example solution containing two windows application project and one class library project. An instance of the class is binary serialized between the two windows application assemblies. (solution starts up both windows apps when you press 'play')

Regarding the "YourClass" comment, you can overcome this by using the .GetType method on an instance of any type object, it works even if the true object type is boxed to for example Object type. Example:
VB.NET:
Dim xser As New Xml.Serialization.XmlSerializer(loadObject.GetType)
 

Attachments

  • vbnet20-serializing.zip
    34.3 KB · Views: 18
  • vbnet11-serializing.zip
    14.8 KB · Views: 16
Thank you for the example. That's neat how you can open 2 forms at once. It's also doing exactly what I couldn't do. Does it work because it all has the same GUID? I was trying all day to learn about that stuff but it's a completely foreign language to me.

The problem with the example is that I need the deserializing part to be in a .dll in a COM Class and it has to be accessible by the CreateOLEObject in a third-party application.

I tried generalizing your example to the situation by making a second deserializing com class and it didn't work in the application. The other method seems to be working ok though so I'll just stick to that for now and if I have time later I'll try again.

I had also tried the .gettype thing and tried it again after you mentioned it and it still gives the error "Type 'loadobject.gettype' is not defined."

Thank you very much for taking the time to show me the examples and I'll play with it more when I have a chance. Your help is much appreciated.
 
Select startups in Solution properties.

It works not because of GUID, but because of assembly. The example Class1 is part of assembly ClassLibrary1, and this is the assembly qualified class instance that is serialized. Since the assembly that serialize and the assembly that deserialize both use this external assembly they both operate on the same assembly qualified class. If you defined the identical class Class1 in all these three assemblies you would still have three different qualified classes; WindowsApplication1.Class1, WindowsApplication2.Class1 and ClassLibrary1.Class1.

Here is an example of boxed type and using the GetType function for Xml (de)serialization: (of course it works directly on strong type variable t.GetType also)
VB.NET:
Dim fs As New IO.FileStream("c:\test", IO.FileMode.Open, IO.FileAccess.Read)
Dim t As New Class1
Dim o As Object = t
Dim xser As New Xml.Serialization.XmlSerializer(o.GetType)
t = xser.Deserialize(fs)
fs.Close()
Label1.Text = t.myfield
 
Hi JohnH,

Sorry for the delay, I've been travelling and haven't had access. I tried implementing the XML deserializer and it didn't recognize the class this time, but it's ok - for now I only really need it for one type.

Assemblies were one of the things I was spending all those hours reading about and being a novice I just never understood it. Believe it or not I couldn't even find a single easy to follow example of how to create more than one project within a single assembly in VB.Net Standard edition. It's probably because I'm still not exactly sure what an assembly is or how it works, but most of the time if there are step-by-step instructions I can figure it out.

Anyways, what I have is working very well so unless I need it to be more complicated, I'll have to put the whole assembly thing aside for now.

Thank you again very much for your time and examples.
 
Last edited:
Back
Top