AnsiString returns values ​​from a Delphi 2007 DLL in a Delphi 2009 application

I have a DLL compiled with D2007 that has functions that return AnsiStrings.

My application is compiled in D2009. When it calls AnsiString functions, it returns garbage.

I created a small test application / dll for the experiment and found that if both applications and dll are compiled with the same version of Delphi (2007 or 2009), there is no problem. But when one compiles in 2009 and the other 2007, I get garbage.

I tried to include the latest version of FastMM in both projects, but even then the 2009 application cannot read AnsiStrings from dll 2007.

Any ideas on what's going wrong here? Is there any way around this?

+4
source share
6 answers

The internal structure of AnsiStrings has changed between Delphi 2007 and Delphi 2009. (Do not be discouraged, this feature is present from day one). The Delphi 2009 line supports a number indicating which codepage its data is on.

I recommend that you do what every other DLL on Earth does and pass character buffers that the function can fill. The caller must pass a buffer pointer and a number indicating the size of the buffer. (Make sure you understand if you are measuring the size in bytes or characters.) The DLL function fills the buffer, writing no more than the specified size, counting the terminating null character.

If the caller does not know how many bytes should be in the buffer, you have two options:

  • Make a DLL, especially if the input buffer pointer is null. In this case, return the required size so that the caller can allocate so much space and call the function a second time.

  • Let the DLL allocate space for itself, with a predefined method available to the caller to free the buffer later. A DLL can either export a function to free allocated buffers, or you can specify some mutually accessible API function for the caller, such as GlobalFree . Your DLL should use the appropriate distribution API, such as GlobalAlloc . (Do not use Delphi's built-in memory allocation functions such as GetMem or New ; there is no guarantee that the caller's memory manager will know how to call Free or Dispose , even if it is written in the same language, even if it is written with the same version of Delphi .)

It is also selfish to write a DLL that can only be used in one language. Write your DLLs in the same style as the Windows API, and you won’t be mistaken.

+11
source

OK, so I haven’t tried it, so there was a big disclaimer.

In the help viewer, browse the topic (Unicode in RAD Stufio). ms-help: //embarcadero.rs2009/devcommon/unicodeinide_xml.html

When returning a Delphi 2007 string to Delphi 2009, you should get two problems.

Firstly, the code page mentioned by Rob. You can set this by declaring another AnsiString and calling StringCodePage in the new AnsiString. Then assign it to the old AnsiString by calling SetCodePage. That should work, but if that doesn't happen, there is hope.

The second problem is the size of the element, which will be something completely insane. It should be 1, so do it 1. The problem here is that there is no SetElementSize function to rely on.

Try the following:

 var ElemSizeAddr: PWord; // Need a two-byte type BrokenAnsiString: AnsiString; // The patient we are trying to cure ... ElemSizeAddr := Pointer(PAnsiChar(BrokenAnsiString) - 10); ElemSizeAddr^ := 1; // The size of the element 

That should do it!

Now, if the StringCodePage / SetCodePage object does not work, you can do the same as above by changing the line where we get the address to subtract 12 instead of 10.

He has hacked inscriptions, so I love him.

In the end, you will have to port these DLLs, but this makes the port more manageable.

One final word - depending on how you return AnsiString (function result, output parameter, etc.), you may need to first assign a string to another AnsiString variable to make sure there is no need to overwrite memory.

+2
source

You probably just need to convert the DLL in 2009. According to Embarcadero, the transition to 2009 is "simple" and does not take time at all.

0
source

Your DLL should not return AnsiString values ​​to begin with. The only way that will work correctly in the first place is that both the DLL and the EXE were compiled using the ShareMem module, and even then only if they were compiled with the same version of Delphi. The D2007 memory manager is not compatible with the D2009 memory manager (or any other use of memory managers using the cross-version), AFAIK.

0
source

I agree with Rob and Remy here: regular Dlls should return PAnsiChar instead of from AnsiStrings.

If the DLL works fine, compiled with D2009, why doesn't it just stop compiling it with D2007 and start compiling with D2009 once and for all?

0
source

As a quick solution here: if your actual data that you transfer back from the dll in a line does not exceed 255 characters, you can change both decentralization in the dll and the interface for using ShortString, which will work regardless of the 2007/2009 version. Since you use AnsiString as early as 2007 without a code page identifier, unicode will not give you any problems.

if you go this way, all you have to do is change the declarations like:

 function MyStringReturningFunction : ShortString ; external 'MyLibrary.dll'; 

(and in dll: function MyStringReturningFunction : ShortString; respectively)

The same goes for input / output parameters, of course:

 procedure MyStringTakingAndReturningFunction(s1:ShortString; var s2:ShortString); external 'MyLibrary.dll'; 

It should be easier than changing a lot of code. But be careful, as I said, your data should not exceed 255 characters, as this is the maximum size that a ShortString can contain.

0
source

Source: https://habr.com/ru/post/1286723/


All Articles