Here's the native (Delphi 7) function:
这是本机(Delphi 7)功能:
function Foo(const PAnsiChar input) : PAnsiChar; stdcall; export;
var
s : string;
begin
s := SomeInternalMethod(input);
Result := PAnsiChar(s);
end;
I need to call this from C#, but the name of the dll is not known at compile time - so I must use LoadLibrary to get to it.
我需要从C#调用它,但是在编译时不知道dll的名称 - 所以我必须使用LoadLibrary来实现它。
This is what my C# code looks like so far:
这是我的C#代码到目前为止的样子:
[DllImport("kernel32.dll")]
public extern static IntPtr LoadLibrary(String lpFileName);
[DllImport("kernel32.dll")]
public extern static IntPtr GetProcAddress(IntPtr handle, string funcName);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate string FooFunction(string input);
...
IntPtr dllHandle = LoadLibrary(dllName);
IntPtr fooProcAddr = GetProcAddress(dllHandle, "Foo");
FooFunction foo = (FooFunction)Marshal.GetDelegateForFunctionPointer(
fooProcAddr, typeof(FooFuncion)
);
string output = foo(myInputString);
Now, this actually works - at least, the delphi code receives the string correctly, and the C# code receives the output string.
现在,这确实有效 - 至少,delphi代码正确接收字符串,C#代码接收输出字符串。
However, I've noticed some weirdness when debugging the delphi code when it's called from the C# code - the debugger skips lines when it shouldn't..
但是,当从C#代码中调用delphi代码时,我注意到了一些奇怪的问题 - 调试器在不应该跳过行时跳过行。
And I'm concerned that I'm leaking memory - is anyone cleaning up those PChars?
我担心我会泄漏记忆 - 是否有人清理那些PChars?
Can anyone give me some feedback / advice on how this should be done?
谁能给我一些关于如何做到这一点的反馈/建议?
2 个解决方案
#1
3
The only reasonable thing that you can do is trash this function and rewrite it. There is no way this is ever going to work. s
is a local string variable of the Foo()
function, so the memory the string occupies will be freed when you leave Foo()
. The pointer you return points to an invalid memory location, which by chance still contains the string data. If you use a memory manager that clears the memory when pointers to it are freed it won't even contain the data any more. If memory is reused it will contain something else, if the block containing that chunk of memory is released you will get an AV.
你可以做的唯一合理的事情是废弃这个功能并重写它。这是不可能的。 s是Foo()函数的本地字符串变量,因此当您离开Foo()时,将释放字符串占用的内存。您返回的指针指向无效的内存位置,该位置偶然包含字符串数据。如果使用内存管理器在释放指针时清除内存,则它甚至不再包含数据。如果重用内存,它将包含其他内容,如果包含该内存块的块被释放,您将获得AV。
There are more questions here on * how to return character sequence data from a DLL. Either use a string type that is compatible with the way the Windows API does business, a COM string, or pass a preallocated buffer to your function and fill that with data. In the latter case you can use the same way of using your function like with every similar API function.
*上有更多关于如何从DLL返回字符序列数据的问题。使用与Windows API开展业务的方式兼容的字符串类型,COM字符串,或将预分配的缓冲区传递给您的函数,并用数据填充它。在后一种情况下,您可以像使用每个类似的API函数一样使用函数。
#2
2
For memory leak detection you can use the open source FastMM4 memory manager for Delphi.
对于内存泄漏检测,您可以使用Delphi的开源FastMM4内存管理器。
"FastMM is a lightning fast replacement memory manager for Embarcadero Delphi Win32 applications that scales well in multi-threaded applications, is not prone to memory fragmentation, and supports shared memory without the use of external .DLL files."
“FastMM是Embarcadero Delphi Win32应用程序的快速替换内存管理器,可在多线程应用程序中很好地扩展,不易出现内存碎片,并且在不使用外部.DLL文件的情况下支持共享内存。”
It is great for speed, leak checking and memory sharing between dll's.
它非常适合dll之间的速度,泄漏检查和内存共享。
Also very useful is the FastMM4 Options Interface which helps to configure FastMM4.
FastMM4选项界面也很有用,它有助于配置FastMM4。
#1
3
The only reasonable thing that you can do is trash this function and rewrite it. There is no way this is ever going to work. s
is a local string variable of the Foo()
function, so the memory the string occupies will be freed when you leave Foo()
. The pointer you return points to an invalid memory location, which by chance still contains the string data. If you use a memory manager that clears the memory when pointers to it are freed it won't even contain the data any more. If memory is reused it will contain something else, if the block containing that chunk of memory is released you will get an AV.
你可以做的唯一合理的事情是废弃这个功能并重写它。这是不可能的。 s是Foo()函数的本地字符串变量,因此当您离开Foo()时,将释放字符串占用的内存。您返回的指针指向无效的内存位置,该位置偶然包含字符串数据。如果使用内存管理器在释放指针时清除内存,则它甚至不再包含数据。如果重用内存,它将包含其他内容,如果包含该内存块的块被释放,您将获得AV。
There are more questions here on * how to return character sequence data from a DLL. Either use a string type that is compatible with the way the Windows API does business, a COM string, or pass a preallocated buffer to your function and fill that with data. In the latter case you can use the same way of using your function like with every similar API function.
*上有更多关于如何从DLL返回字符序列数据的问题。使用与Windows API开展业务的方式兼容的字符串类型,COM字符串,或将预分配的缓冲区传递给您的函数,并用数据填充它。在后一种情况下,您可以像使用每个类似的API函数一样使用函数。
#2
2
For memory leak detection you can use the open source FastMM4 memory manager for Delphi.
对于内存泄漏检测,您可以使用Delphi的开源FastMM4内存管理器。
"FastMM is a lightning fast replacement memory manager for Embarcadero Delphi Win32 applications that scales well in multi-threaded applications, is not prone to memory fragmentation, and supports shared memory without the use of external .DLL files."
“FastMM是Embarcadero Delphi Win32应用程序的快速替换内存管理器,可在多线程应用程序中很好地扩展,不易出现内存碎片,并且在不使用外部.DLL文件的情况下支持共享内存。”
It is great for speed, leak checking and memory sharing between dll's.
它非常适合dll之间的速度,泄漏检查和内存共享。
Also very useful is the FastMM4 Options Interface which helps to configure FastMM4.
FastMM4选项界面也很有用,它有助于配置FastMM4。