Thursday, 21 January 2010

Upgrading to Delphi 2010

While the next major release of the application I work on will no doubt be written in C# (unless we get a 64-bit Delphi, then I have something to argue my case with), for the short-term, we will continue using Delphi. To that end, I like to keep up with the latest version (not always sure that’s a good idea, but anyway) so we recently got a copy of Delphi 2010 to see how easy the upgrade would be.

Not so long ago, I moved from Delphi 2006 to Delphi 2009, so I thought this upgrade would be a walk in the park. There should be no breaking changes. I would need to change a few defines, but that’s about it. And initially that was the case. In no time at all, I had upgraded our third-party components, made the necessary changes to include the new compiler version (more about that in a later post perhaps), and I had the whole thing building in no time. I ran it and disaster. Well it seemed like a disaster. All the fonts of all the menus, both the main menu and all popups were both the wrong font, very large (some the size of the monitor) and skewed. I checked the components in question, and yes the font property was basically garbage. I checked the DFM file, and everything was correct.

Now I have to add that we use some old DevExpress components for our menus. We never upgraded them as they did a complete rewrite of their grid component at the same time, and we had too much invested in the old one. Anyway, we have faithfully updated the source as and when needed. The unicode changes were perhaps the biggest challenge, but not too difficult. Now this! What was wrong?

Something was changing the font. I delved into the source for the components, and zeroed in on the following few lines.

NonClientMetrics: TNonClientMetrics;
NonClientMetrics.cbSize :
= SizeOf(TNonClientMetrics);
0, @NonClientMetrics, 0);
Font.Handle :
= CreateFontIndirect(NonClientMetrics.lfMenuFont);

Now this code hasn’t changed since we compiled it with Delphi 2009, so I delved into windows.pas, and found the record that TNonClientMetrics ultimately points to tagNONCLIENTMETRICSW and down at the end, the following line.

iPaddedBorderWidth: Integer; //Requires Windows Vista or Later

Aha, I’m working on Windows XP. I checked the same record in Delphi 2009, and that line was missing. So sizeof was returning 4 bytes extra in Delphi 2010 than it did in Delphi 2009. I confirmed this by trying the following

NonClientMetrics.cbSize := SizeOf(TNonClientMetrics) - SizeOf(NonClientMetrics.iPaddedBorderWidth);

Yes, everything back to normal. Obviously, the code should check for windows version and return the size accordingly, but some kind soul has done that work for me, and added a static method, sizeof, to the record. So the code becomes

NonClientMetrics.cbSize := TNonClientMetrics.SizeOf;

The sizeof static method checks windows version and adds or removes the extra 4 bytes accordingly. I hate breaking changes like these, but whose fault was it. Delphi 2010 or Microsoft?


Roddy said...

Microsoft's fault :-)

You'd have exactly the same problem with any C/C++ application recompiled to use the latest MS SDK header files.

There are any number of ways they could have prevented the problem, but no...

check the 'remarks' section at the bottom here.

Warren said...

I got hit with this too.

I didn't enjoy it much either.

But hey, you learn something, and you move with the times.

I'm kind of laughing at the idea that you would throw all your delphi code away and move to a dot-net bytecode platform, and rewrite everything, just to be "64 bits". But hey, whatever.

Maybe your Delphi code isn't worth keeping. Mine is. I'm staying put. 32 or 64, or 57 bits. Whatever.



Anonymous said...

And I always thought the whole point of the cbSize params was so Windows could return the information for your Windows version, rather than failing miserably.

I think some needs to tell Raymond Chen!

Helen said...

Nice and clear review. But I think beginners still need the basics to fully grasp what's going on here.

Helen Neely

Anonymous said...

Thanks, above discussion really helped me for fixing my issue. Hopeless Microsoft .......