我应该如何从 C# 调用这个本机 dll 函数?
这是本机 (Delphi 7) 函数:
function Foo(const PAnsiChar input) : PAnsiChar; stdcall; export;
var
s : string;
begin
s := SomeInternalMethod(input);
Result := PAnsiChar(s);
end;
我需要从 C# 调用此函数,但 dll 的名称在编译时未知 - 因此我必须使用 LoadLibrary 来获取它。
这就是我的 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);
现在,这确实有效 - 至少,delphi 代码正确接收字符串,并且 C# 代码接收输出字符串。
然而,当从 C# 代码调用 delphi 代码时,我注意到在调试 delphi 代码时出现了一些奇怪的情况 - 调试器在不应该跳过的情况下跳过了行。
而且我担心我正在泄漏内存 - 是否有人清理了这些 PChar ?
谁能给我一些关于如何完成此操作的反馈/建议?
Here's the native (Delphi 7) function:
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.
This is what my C# code looks like so far:
[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.
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..
And I'm concerned that I'm leaking memory - is anyone cleaning up those PChars?
Can anyone give me some feedback / advice on how this should be done?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你能做的唯一合理的事情就是废弃这个函数并重写它。这是不可能的。
s
是Foo()
函数的本地字符串变量,因此当您离开Foo()
时,该字符串占用的内存将被释放。您返回的指针指向无效的内存位置,该位置碰巧仍然包含字符串数据。如果您使用内存管理器,当指向内存的指针被释放时,它会清除内存,那么它甚至不再包含数据。如果内存被重用,它将包含其他内容,如果包含该内存块的块被释放,您将获得 AV。StackOverflow 上还有更多关于如何从 DLL 返回字符序列数据的问题。使用与 Windows API 处理业务的方式兼容的字符串类型(COM 字符串),或者将预分配的缓冲区传递给函数并用数据填充该缓冲区。在后一种情况下,您可以使用与每个类似的 API 函数相同的方式来使用您的函数。
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 theFoo()
function, so the memory the string occupies will be freed when you leaveFoo()
. 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.There are more questions here on StackOverflow 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.
对于内存泄漏检测,您可以使用开源 FastMM4 Delphi 内存管理器。
它对于速度、泄漏检查和 dll 之间的内存共享非常有用。
FastMM4 选项界面,有助于配置 FastMM4。
For memory leak detection you can use the open source FastMM4 memory manager for Delphi.
It is great for speed, leak checking and memory sharing between dll's.
Also very useful is the FastMM4 Options Interface which helps to configure FastMM4.