【问题标题】:How should I call this native dll function from C#?我应该如何从 C# 调用这个本机 dll 函数?
【发布时间】:2009-11-09 23:56:35
【问题描述】:

这是本机 (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 代码时,我在调试它时发现了一些奇怪的地方 - 调试器在不应该的时候跳过了行。

而且我担心我会泄漏内存 - 有人清理这些 PChar 吗?

谁能给我一些反馈/建议,告诉我应该怎么做?

【问题讨论】:

  • 我唯一一次看到调试器不应该跳过行是编译的代码与源代码不匹配。您确定要绑定到正确版本的程序集吗?

标签: c# .net delphi pinvoke delphi-7


【解决方案1】:

你能做的唯一合理的事情就是丢弃这个函数并重写它。这是不可能的。 sFoo()函数的局部字符串变量,所以当你离开Foo()时,字符串占用的内存会被释放。您返回的指针指向一个无效的内存位置,该位置偶然仍包含字符串数据。如果您使用内存管理器在释放指向它的指针时清除内存,它甚至不再包含数据。如果内存被重用,它将包含其他内容,如果包含该内存块的块被释放,您将获得一个 AV。

这里有更多关于 StackOverflow 如何从 DLL 返回字符序列数据的问题。要么使用与 Windows API 执行业务的方式兼容的字符串类型,即 COM 字符串,要么将预分配的缓冲区传递给您的函数并用数据填充该缓冲区。在后一种情况下,您可以使用与每个类似 API 函数相同的方式来使用您的函数。

【讨论】:

  • 谢谢,我很困惑,因为它确实有效 - 我想也许 PChar 演员正在做一些聪明的事情,比如分配内存。
  • 您能否指出有关“Windows API 开展业务的方式”的资源?我不想预先分配缓冲区,因为返回的字符串的长度会千差万别。
  • 好的,我正在尝试这种方法:stackoverflow.com/questions/1699736/…
  • 我无法比 Rob Kennedy 在回答链接问题时更好地解释它:stackoverflow.com/questions/1699736/…。但是,如果您在 [delphi] 标签中搜索“c#”和“dll”,还有更多内容。问题是不同的,但它总是归结为相同的事情:除非您使用相同的内存管理器(Delphi 和 C# 不可能),否则不要在不同的模块中分配和释放内存。仅使用基本类型。并且不要返回指向不再有效的指针。
  • 如果你 a) 声明返回的字符串的最大大小(如MAX_PATH),或者 b) 你使用两步算法,第一步返回,那么预分配缓冲区是没有问题的只有必要的缓冲区大小,第二个缓冲区至少具有该大小。 Rob 解释得很好。
【解决方案2】:

对于内存泄漏检测,您可以使用开源FastMM4 memory manager for Delphi

“FastMM 快如闪电 替换内存管理器 Embarcadero Delphi Win32 应用程序 在多线程中很好地扩展 应用程序,不易记忆 分片,支持共享 无需使用外部存储器 .DLL 文件。”

它对于速度、泄漏检查和 dll 之间的内存共享非常有用。

FastMM4 Options Interface 也非常有用,它有助于配置 FastMM4。

【讨论】:

  • 干杯,我去看看
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
  • 1970-01-01
  • 2013-05-08
相关资源
最近更新 更多