billroper: (Default)
I made a change to one of my MFC template classes this afternoon and am now embedded in serialization hell as I try to figure out exactly how to get the framework to write the correct RuntimeClass information into itself so that everything will serialize correctly.

I am fairly sure that a solution exists, but *finding* it is a challenge.
billroper: (Default)
I have been head down in bugs for the last two days since I came back from Confusion, dealing with nasty interactions between MFC in C++ and interoperable code in Java. I think that I've managed to sort out the nastiness, although it was disconcerting to find a big fat bug in a built-in Windows method.

*sigh*
billroper: (Default)
I've been trying to beat the bugs out of a Java demo that I'm supposed to do on Monday. This was complicated by socket connections between client and server gleefully timing out whenever I stopped to debug, but one of my compatriots sent me the proper registry settings to fix that problem and debugging became much more tractable.

Unfortunately, the MFC serialization code that I wrote in Java was writing an ID that was causing a problem on the C++ side of the world. Specifically, an ID that was supposed to be unique had shown up on the client side as shared. And when the second attempt was made to delete the same object, well, nothing good at all happened.

I spent a lot of time making sure that all of the IDs and objects were being correctly cloned on the Java side, but no luck.

Ok. Maybe there was a problem in serialization. I traced into the writing code and discovered that I was using a HashMap to store objects so that I could (like the C++ MFC serialization) detect when I was serializing the same object twice and write a reference to it the second time.

But the HashMap calls the hashCode() function for the object on the Java side. And I had overridden the hashCode() function for a couple of the ID objects, because I wanted to make sure that two IDs that contained the same strings would locate the same hash bucket. And this meant that the HashMap in serialization thought they were the same object. So when I encountered the second unique object and wrote it out to the MFC archive, my serialization code wrote a reference to the first object.

Thud. Thud. Thud.

I have now spent the last several hours beating up all of my HashMap code that stored these various IDs so that they now store the keys as Strings. The overriding hashCode() methods have been exterminated.

And maybe this will work now.

*sigh*
billroper: (Default)
One of the nice things about MFC's serialization routines is that if you write your code correctly, you should be able to take a file that was written out by a 32-bit application and successfully read it into a 64-bit version of the same application. The trick is not doing things that will cause the serialization code to break as you move between the 32-bit and 64-bit compilers.

Enter CMap. CMap is a lovely little template class that allows you to take a key of arbitrary type and locate a value of some other arbitrary type. You can even serialize your CMap objects out to your archive and read them back in.

The problem occurs when you're trying to read and write a complex type, like an MFC class, as either your key or your value. CMap uses the SerializeElements function in order to persist the keys and values and -- by default! -- writes an exact copy of the bits that existed in your object to the archive.

This is almost certainly not what you wanted to happen if your key or value is an MFC class, especially if it contains any virtual functions -- which it will, if you derived it from CObject, or any pointers. See, one of the things that's hidden inside your class is a pointer to the virtual function table for the class. I cannot imagine any good outcomes from reading in a previously stored value of that pointer.

But perhaps you're fortunate and don't actually call any of the virtual functions that you might try to find via that pointer. You're still going to get clobbered when you try to move between a 32-bit and a 64-bit version of your application, because the pointer that had been four bytes long is now eight bytes long and when the default implementation of SerializeElements takes the sizeof( YourClass), you get a different value on the two systems. Hilarity -- and a CArchiveException -- ensues.

The happy news is that you can easily write a templated version of SerializeElements that will call CArchive::SerializeClass() to write out the class header for your key and/or value followed by a call to serialize the underlying object. Or if your CMap stores a pointer to your key or value class, you can use the insertion/extraction operators, which is even simpler. And then your CMap classes will serialize correctly whether you're on a 32-bit or a 64-bit system.

Isn't that easy?
billroper: (Default)
One of the nice things about MFC's serialization routines is that if you write your code correctly, you should be able to take a file that was written out by a 32-bit application and successfully read it into a 64-bit version of the same application. The trick is not doing things that will cause the serialization code to break as you move between the 32-bit and 64-bit compilers.

Enter CMap. CMap is a lovely little template class that allows you to take a key of arbitrary type and locate a value of some other arbitrary type. You can even serialize your CMap objects out to your archive and read them back in.

The problem occurs when you're trying to read and write a complex type, like an MFC class, as either your key or your value. CMap uses the SerializeElements function in order to persist the keys and values and -- by default! -- writes an exact copy of the bits that existed in your object to the archive.

This is almost certainly not what you wanted to happen if your key or value is an MFC class, especially if it contains any virtual functions -- which it will, if you derived it from CObject, or any pointers. See, one of the things that's hidden inside your class is a pointer to the virtual function table for the class. I cannot imagine any good outcomes from reading in a previously stored value of that pointer.

But perhaps you're fortunate and don't actually call any of the virtual functions that you might try to find via that pointer. You're still going to get clobbered when you try to move between a 32-bit and a 64-bit version of your application, because the pointer that had been four bytes long is now eight bytes long and when the default implementation of SerializeElements takes the sizeof( YourClass), you get a different value on the two systems. Hilarity -- and a CArchiveException -- ensues.

The happy news is that you can easily write a templated version of SerializeElements that will call CArchive::SerializeClass() to write out the class header for your key and/or value followed by a call to serialize the underlying object. Or if your CMap stores a pointer to your key or value class, you can use the insertion/extraction operators, which is even simpler. And then your CMap classes will serialize correctly whether you're on a 32-bit or a 64-bit system.

Isn't that easy?
billroper: (Default)
MFC does not have wonderful support for changing languages on the fly in a running application by reloading the underlying resource DLL. It turns out that this is something you can do -- you just have to get your incantations straight.
Technogeekery inside... )
billroper: (Default)
MFC does not have wonderful support for changing languages on the fly in a running application by reloading the underlying resource DLL. It turns out that this is something you can do -- you just have to get your incantations straight.
Technogeekery inside... )

Profile

billroper: (Default)
billroper

January 2026

S M T W T F S
     1 2 3
4 5 6 7 8910
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28293031

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 29th, 2026 08:53 pm
Powered by Dreamwidth Studios