【问题标题】:Native DLL - C#本机 DLL - C#
【发布时间】:2016-11-05 16:50:28
【问题描述】:

我有用 Delphi 编写的本地 DLL 库。我想从 C# 中引用这个库并得到返回的字符串。

功能

function GetCode (aUser,aPassword: PAnsiChar): PAnsiChar; stdcall;

C#代码

[DllImport("C:\\library.dll", CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Ansi)]
private static extern String GetCode([MarshalAs(UnmanagedType.LPStr)]string aUser, [MarshalAs(UnmanagedType.LPStr)]string aPassword);

public String getCode(String login, String password) {
        return GetCode(login, password);
}

尝试调用函数应用程序退出,代码为 -1073740940 (0xc0000374)。

你有过期的吗?谢谢你的帮助

【问题讨论】:

  • 1.在调试器下调用它时是否收到正确的异常消息? 2.函数是否导出? 3. 函数名有错吗? 4.你应该如何释放返回值?
  • 1.不,应用程序以 NTSTATUS 错误代码结束。 2. 是的,否则会引发托管异常。 3. 见 2. 4. 非常好的问题!
  • @DavidHeffernan 你是对的,我应该先用谷歌搜索 0xc0000374。 (我想通过不在调试器下运行来确保 OP 不会错过托管异常)
  • @LucasTrzesniewski 4.) 如果您可以控制 DLL,您可以实现一个附加函数来释放该值。例如,FreeCode 函数(以指向字符串的指针作为参数)可以在 C# 代码完成对字符串的处理后调用(例如,将其复制到另一个变量)。
  • @quasoft 是的,这是一种方式。另一种方法是将缓冲区和大小传递给函数,以便它可以填充它。不过,您需要事先知道最大字符串长度。 P/Invoke 允许您为此提供 StringBuilder,您只需使用所需的容量对其进行初始化。

标签: c# delphi dll


【解决方案1】:

返回值为string,编组器负责释放返回的字符串。它通过调用CoTaskMemFree 来实现。毫无疑问,您的字符串没有在 COM 堆上分配。因此出现错误,即STATUS_HEAP_CORRUPTIONNTSTATUS 错误代码。

您的 p/invoke 应该返回 IntPtr 来避免这种情况:

[DllImport("C:\\library.dll", CallingConvention = CallingConvention.StdCall,
    CharSet = CharSet.Ansi)]
private static extern IntPtr GetCode(string aUser, string aPassword);

要获取字符串,请将返回值传递给Marshal.PtrToStringAnsi

public string getCode(string login, string password) 
{
    IntPtr retval = GetCode(login, password);
    string result = Marshal.PtrToStringAnsi(retval);
    // how do we deallocate retval
    return result;
}

还要注意我删除了多余的MarshalAs 属性。 CharSet.Ansi 负责输入参数的编组。

您仍然需要弄清楚如何释放返回的内存。我们不知道它是如何分配的。您需要联系 Delphi 代码的开发人员,或阅读源代码。如果使用了本机 Delphi 堆,请不要感到惊讶,这会让您陷入困境。通过调用CoTaskMemAlloc 来使用COM 堆实际上是一个不错的选择,然后你原来的p/invoke 返回值string 就可以了。

其他选项包括导出释放器或要求调用者分配缓冲区。网上有很多关于如何实现各种选项的示例。

【讨论】:

  • 分配和释放可以在 Delphi 中使用 WideString 和在 C# 中使用 UnmanagedType.BStr 来处理。但是不要将其用作返回值,而是用作参数(请参阅stackoverflow.com/questions/9349530/…
  • 非常感谢 :-) 这很好用,但是我在释放返回的内存时遇到了问题。我用过 Marshal.FreeHGlobal(retval);但它仍然使应用程序崩溃(关闭后)并且进程永远不会死。你有什么想法吗?
猜你喜欢
  • 2019-08-12
  • 2019-10-04
  • 1970-01-01
  • 1970-01-01
  • 2013-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多