这是 native (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 代码时,我注意到一些奇怪的地方——调试器在不应该跳过的行时跳过了一些行。
我担心我正在泄漏内存 - 有人清理了那些 PChars 吗?
谁能给我一些关于如何完成的反馈/建议?
最佳答案
你能做的唯一合理的事情就是丢弃这个函数并重写它。这是永远行不通的。 s
是Foo()
函数的局部字符串变量,所以当您离开Foo()
时,该字符串占用的内存将被释放。您返回的指针指向无效的内存位置,该位置偶然仍包含字符串数据。如果您使用内存管理器在释放指向它的指针时清除内存,它甚至不会再包含数据。如果内存被重用,它将包含其他内容,如果包含该内存块的 block 被释放,您将获得一个 AV。
这里有更多关于 StackOverflow 如何从 DLL 返回字符序列数据的问题。要么使用与 Windows API 处理业务的方式兼容的字符串类型,COM 字符串,要么将预分配的缓冲区传递给您的函数并用数据填充它。在后一种情况下,您可以使用与每个类似 API 函数相同的方式来使用您的函数。
关于c# - 我应该如何从 C# 调用这个 native dll 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1704762/