Jump to content
Yaron

I need advice on converting a 500k lines 32bit Delphi 7 application to 64bit

Recommended Posts

I hope this is the right spot & apologize if it isn't.

 

I am the developer of Zoom Player, a windows media playback software developed in Delphi and initially released early 2000.

 

Since then, Zoom Player has grown to over 500,000 lines of code and code-base wise, Zoom Player is stuck at Delphi 7.

Over the years I got around most of Delphi 7's shortcoming using custom code, but now I've reached a point where converting Zoom Player to 64bit is becoming a greater necessity.

 

I own a license to Delphi 10.3 so that is the 64bit target code-base I'm aiming for.

 

Do you have any advice for me on ways to automate the jump from Delphi 7 32bit to Delphi 10.3 64bit without breaking the code in 1000's of places? Is there an AI agent or some other tool that could help me in this context?

 

Right now this feels like a pain-staking months long project, am I wrong?

Share this post


Link to post

It depends on the actual sources. I have had projects that just needed a compile with the new version and target, while others lasted several months.

  • Like 4

Share this post


Link to post

I have no knowledge of any tool for automatic conversion (even partial).


There are several contexts you should pay attention to when converting:

1) string: currently the definition is Unicode, in Delphi7 it was synonymous with AnsiString;
2) char: 1 character occupies two bytes. in Delphi7 it occupied 1 byte;
3) several definitions have changed in both core and third-party components;
4) several basic components distributed with Delphi7 are no longer distributed with Delphi 10.3, and obviously there must be third-party 64-bit components if you use them;
5) when converting between 32 and 64 bit you must pay attention to the various types of parameters, especially in third-party DLLs: PChar, PWChar, PAnsiChar....
6) Integer, cardinal, nativeint, etc....
7) Floating Extended type is 80 bit long in 32 bit application, but in 64 bit is an alias of double (64 bit long);
8 Pointers in 32 bit platforms are 4 bytes length, in 64 bit platforms they are 8 bytes length.
9) In 64 bit platforms you cannot mix assembler and pascal in the same method.

10) more other stuff

Look here for more info: https://docwiki.embarcadero.com/RADStudio/Rio/en/Converting_32-bit_Delphi_Applications_to_64-bit_Windows

 

Good luck and good work

Edited by DelphiUdIT
  • Like 2

Share this post


Link to post
4 hours ago, DelphiUdIT said:

1) string: currently the definition is Unicode, in Delphi7 it was synonymous with AnsiString;

2) char: 1 character occupies two bytes. in Delphi7 it occupied 1 byte;
...
5) when converting between 32 and 64 bit you must pay attention to the various types of parameters, especially in third-party DLLs: PChar, PWChar, PAnsiChar....

None of that has anything to do with migrating from 32-bit to 64-bit. Only with migrating from ANSI to Unicode. You can still use the ANSI types in 64-bit code if you need to, albeit more explicitly than before.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

I converted a lot of code, most without any issue.

I you have done like me, that is using each data type for what it really is, there will be no issue. But if you used, for example, a string as a general buffer instead of an array of byte, then you'll have to change your code. Another example is of you use Windows messages (PostMessage and other API function in the same category), if you used LPARM and WPARAM, then no issue. If you used other data types as integer of unsigned, then you have to change your code. There are other similar cases.

The biggest issue can come from 3rd party components which may not exists anymore and for which you don't have full source code. If you have full source code, you can recompile (with the same issues as you own code). If you don't have source code, even if the component still exists, you may be faced with their evolution over the years: properties, events, function may now differ.

 

I can't be more precise with seeing your code...

  • Like 1

Share this post


Link to post

I would (did not think this too much) something like this.
 

  1. Go code trough with D7, make it is modern at it can get. (Few refactoring rounds, get rid of code that is not in active use etc)
  2. Update all 3rd party components and libraries.  Get rid of those not available for modern delphi versions anymore and not supported
  3. Get rid of all visual components that are not absolutely needed. In legacy app there might be visual components form 5 different libraries or something like that. If can get byt, use stock Delphi components as much as you can. Mainly just reduse code base as small as you can, before start using new Delphi.
  4. Move to the new delphi and make 32bit app with that.
  5. Refactor and further modernice as much as you can.
  6. Do 64bit port as last step.

-Tee-

Edited by Tommi Prami
  • Like 2

Share this post


Link to post

Actually for good clean code it's just a matter of rebuild and fix slight API changes. But years back Delphiers used too much hacks/incorrect constructions that will break and most of them come from 2 presumptions that are now invalid:

- Char is 1-byte (wrong since D2009 - now it's 2 bytes)

- Pointer is the same size as Integer (wrong for x64)

 

Also using generic Delphi types for WinAPI calls instead of those specified in docs (like Cardinal instead of DWORD) was very widespread and also will cause troubles on x64.

That said, I'd recommend to read advises regarding porting and do like guys said above: check availability of 3rd party components, then ensure clean code in each unit, then port to x32 app in modern Delphi, then build as x64. You'll likely have to create many test projects that use only a few of units just to test things are OK.

Edited by Fr0sT.Brutal
  • Like 1

Share this post


Link to post

My take on this is that you want to start making changes in your Delphi 7 code base that don't change the meaning of the program there, but mean that it will compile and work as expected in both ANSI and Unicode Delphi. In an ideal world you'd be able to do all that work preparing for the switch and reach a point where you can compile with both ANSI and Unicode Delphi, and the program works the same.

 

Then you can cut the chord to Delphi 7 and commit to Unicode Delphi. Then you do the second piece of work which is to get the code working on 64 bit.

  • Like 3

Share this post


Link to post

Over the last two years, I've converting Delphi 2007 applications to modern compilers.  Not finished yet.

 

Apart from all the other comments made, a couple of my own.

 

Avoid the simple solution of using AnsiString, you will end up with thousands of compiler cast warning and have trouble with functions that use UnicodeString.  Use TBytes for non-string data, there are lots of ways of converting TB to other formats

 

Look at file handling carefully, loading a text file into a TStringList will result in Chinese as it assumes it's reading unicode, unless it finds a BOM or is told otherwise, ditto saving files.

 

Angus

 

  • Like 1

Share this post


Link to post
10 hours ago, Remy Lebeau said:

None of that has anything to do with migrating from 32-bit to 64-bit. Only with migrating from ANSI to Unicode. You can still use the ANSI types in 64-bit code if you need to, albeit more explicitly than before.

He's talking about DELPHI 7 !!! and my explanation is about DELPHI 7 to Delphi 10.3 differences (surely only some of them)...

16 hours ago, Yaron said:

Do you have any advice for me on ways to automate the jump from Delphi 7 32bit to Delphi 10.3 64bit without breaking the code in 1000's of places? Is there an AI agent or some other tool that could help me in this context?Gì

 

Edited by DelphiUdIT

Share this post


Link to post

Just open the project in the newer version and see if it compiles, and try to fix the obvious bugs? (This doesn't mean you have to test all the functions to see if anything is broken)

Share this post


Link to post
1 hour ago, toms said:

Just open the project in the newer version and see if it compiles, and try to fix the obvious bugs? (This doesn't mean you have to test all the functions to see if anything is broken)

This was the exact approach I took to convert our legacy application to 64-bit. Our custom component package took about 2 days (plus 2 to fix issues which weren’t obvious), the program itself (1,5M loc) was only one day (plus 7 for fixing the same).

 

I’m not saying it’s the most sophisticated method but it’s one of the easiest and definitely viable.

  • Like 1

Share this post


Link to post
1 hour ago, toms said:

Just open the project in the newer version and see if it compiles, and try to fix the obvious bugs? (This doesn't mean you have to test all the functions to see if anything is broken)

Yes, this option as well. Compiler will give lots of hints and warnings from which you can start

Share this post


Link to post
51 minutes ago, Fr0sT.Brutal said:

Compiler will give lots of hints and warnings from which you can start

And so will the users if he just ships it 🙂

 

But seriously; There's already lots of good advice here. If I should add anything it would be to make sure that you do all this under version control (re: Git). That relieves some of the pressure of changing something that works into something that might potentially be full of bugs. It also makes it easy to see what you've changed so far.

Share this post


Link to post

I made the assumption that my D1-7 custom controls were only 32 bit x86 so made all new controls for 64 bit x64 on D10.2 several years ago. (Naive and fear, uncertainty and dread caused by the marketing and not staying current. 

lately, I found some of the custom TGraphiccontrols actually work better on a touch screen and readily cast to TV with Bluetooth. (Albeit a new win11 machine)

 

In 32 x86

  • The question is under D7 is there any warnings or hints as each library or package is compiled?   
  • The question is under D10 is there any warnings or hints as each library or package is compiled?

In 32/64 x64

  • have dcu64 directories to prevent error 2048 found x86 wanting x64 before trying to compile 64*.  
  • use NativeInt vs integer for offsets if using pointers. 
  • after a build all check the dcu filedatetimes to verify all the code actually compiled.

 

 

 

  *In case the 64 compile ever needs to be recompiled.   

 

   

 

  

 

Share this post


Link to post

Thank you everyone for your kind advance.

 

Zoom Player is already fully unicode, I bypassed this Delphi 7 limitations by using the TNT Unicode Controls, so at least part of the process wouldn't be as painful.

 

Since whatever string that needed to support unicode is already defined as "WideString", I thought of doing a blind search and replace from "String" to "AnsiString".

Share this post


Link to post
19 minutes ago, Yaron said:

Since whatever string that needed to support unicode is already defined as "WideString", I thought of doing a blind search and replace from "String" to "AnsiString".

Don't do that; I don't know your code but I would think that very few strings actually need to be AnsiString.

And even if your code already supports Unicode there can still be places that assume that SizeOf(Char)=SizeOf(Byte) and SizeOf(PChar^)=SizeOf(PByte^).

 

Also, WideString is not the same as UnicodeString. WideString should generally only be used with COM.

https://docwiki.embarcadero.com/RADStudio/Sydney/en/String_Types_(Delphi)

Quote

UnicodeString variables are reference counted, and two or more of them can reference the same value without consuming additional memory.

Quote

WideString is appropriate for use in COM applications. However, WideString is not reference counted, and so UnicodeString is more flexible and efficient in other types of applications.

 

  • Like 2

Share this post


Link to post
Quote

Since whatever string that needed to support unicode is already defined as "WideString", I thought of doing a blind search and replace from "String" to "AnsiString"

Widestring and Unicodestring are not the same thing, despite both being 16-bit.  You really need to change Widestring to Strimg sooner or later.  And beware of ansistring as I said before.

 

Angus

Share this post


Link to post
29 minutes ago, Yaron said:

I thought of doing a blind search and replace from "String" to "AnsiString".

Don't do that. This is the wrong approach. Just follow the hints from compiler. It will tell you where you need to do something about string conversion. For most of the code you will not need to change anything regarding strings. And if you do blind search and replace you will create more issues in your code than you will solve potential problems.

 

 

Share this post


Link to post

Everyone replying about strings, my code deals with a lot of UTF8 encoded strings, wouldn't leaving "string" as is has the potential of breaking UTF8 encoding in places?

 

Share this post


Link to post
9 minutes ago, Yaron said:

my code deals with a lot of UTF8 encoded strings, wouldn't leaving "string" as is has the potential of breaking UTF8 encoding in places?

Possibly.  Depends on the context in which it's being used.

 

In any case, if you need UTF-8 strings, you should use the native UTF8String type instead of AnsiString (even in Delphi 7, you should have been doing that).  If you must use UTF8 encoded AnsiString in D2009+, at least use SetCodePage() to make sure the CP_UTF8 (65001) codepage is assigned to its data.  UTF8String and UnicodeString are assignment-compatible in D2009+, the RTL will automatically convert between them without any data loss (in Delphi 7, you would have had to use the UTF8Encode()/UTF8Decode() functions for that).  At least with SetCodePage(), you can make sure not to lose any data if a UTF8 encoded AnsiString is assigned to a UnicodeString (the reverse is not true, though).

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

Is there a way for me to continue developing/fixing the current Delphi 7 version while slowly fixing the code (maintaining Delphi 7 compatibility) based on compiler errors in the Delphi 10.3 environment without breaking everything?

 

Or is my only option to maintain two separate code-bases until I successfully complete the transition?

Share this post


Link to post

My advise would be to branch your master and do the conversion there. That way you can cherry pick bugfix commits between them but they would be separated enough.

 

When conversion is done simply merge/cherry pick everything back to master.

 

If you have no version control (which you definitely should) you can start to use IFDEFs to separate code. This will make it less readable and does not allow .dfm changes though.

  • Like 2

Share this post


Link to post
14 hours ago, Yaron said:

Is there a way for me to continue developing/fixing the current Delphi 7 version while slowly fixing the code (maintaining Delphi 7 compatibility)

Like @Remy Lebeau said, start by using UTF8String for strings that hold UTF-8 data. It exists in Delphi 7, too. And doing that will make your transition to Unicode Delphi smoother. You will also be able to more easily verify that you haven't broken anything while doing changes in Delphi 7. This should be your starting point.

 

Another thing you can do is make a short demo application where you will use the most common string handling patterns from your code and then you can transform and move that code to Unicode Delphi. If something goes wrong in that small demo you will be able to more easily understand what you need to do and how.

Share this post


Link to post
1 hour ago, Dalija Prasnikar said:

Like @Remy Lebeau said, start by using UTF8String for strings that hold UTF-8 data. It exists in Delphi 7, too. And doing that will make your transition to Unicode Delphi smoother. You will also be able to more easily verify that you haven't broken anything while doing changes in Delphi 7. This should be your starting point.

 

Another thing you can do is make a short demo application where you will use the most common string handling patterns from your code and then you can transform and move that code to Unicode Delphi. If something goes wrong in that small demo you will be able to more easily understand what you need to do and how.

From what you're writing, it seems that I'm in more of a mess than I initially considered.

 

Most of the strings I use are WideString in order to support Unicode text in Delphi 7, not only that, all of my base visual components are based on the TNT Unicode library (e.g. TTNTForm, TTNTListBox, TTNTStringList, etc), so I can't even load the project without getting lots of error messages and I'm not even sure if the TNT Unicode library is compatible with Delphi 10.3, which means I have to revert 1000's of work-arounds for unicode text that I've implemented over the years.

 

My code also uses quite a bit of ASM optimized code for Audio DSP, graphic processing, etc.

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×