【问题标题】:How to use extern "C" dll function taking char** as an argument in C# application?如何在 C# 应用程序中使用以 char** 作为参数的 extern "C" dll 函数?
【发布时间】:2015-06-13 00:42:06
【问题描述】:

我有带函数的 dll:

extern "C"
int
doJob(char** buffer);

它在 C++ 中的用法如下所示:

char* buf;
int status = doJob(&buf);

在 C# 中我应该对这个函数有什么定义? 如何在 C# 中使用此函数?

【问题讨论】:

  • 谷歌很容易带来很多答案,比如this...
  • 它可以有多个签名,这取决于你想用它做什么。问题是谁会写buffer,调用函数还是doJob
  • 主要问题不是关于如何在 C# 中使用 C dll - 用简单的用例我知道如何做到这一点:
  • [DllImport("containsdojob.dll",CharSet=CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern Int32 doJob(out string buffer);
  • 但是应该用什么来代替“out string buffer”呢?对于这种情况,我有一个例外。

标签: c# c++ c dll unmanaged


【解决方案1】:

其中一种可能的模式是:

[DllImport("containsdojob.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 doJob(out IntPtr buffer);

[DllImport("containsdojob.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void freeMemory(IntPtr buffer);

IntPtr buffer = IntPtr.Zero;
string str = null;

try
{
    doJob(out buffer);

    if (buffer != IntPtr.Zero)
    {
        str = Marshal.PtrToStringAnsi(buffer);
    }
}
finally
{
    if (buffer != IntPtr.Zero)
    {
        freeMemory(buffer);
    }
}

请注意,您需要一个freeMemory 方法来释放doJob 分配的内存。

还有其他可能的模式,例如基于BSTRSysAllocString,更容易实现 C# 端(但更难实现 C 端)

使用 BSTR 的“模式”:

C端:

char *str = "Foo"; // your string
int len = strlen(str);
int wslen = MultiByteToWideChar(CP_ACP, 0, str, len, 0, 0);
BSTR bstr = SysAllocStringLen(NULL, wslen);
MultiByteToWideChar(CP_ACP, 0, str, len, bstr, wslen);
// bstr is the returned string

C#端:

[DllImport("containsdojob.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 doJob([MarshalAs(UnmanagedType.BStr)] out string buffer);

string str;
doJob(out str);

内存由 CLR 自动处理(释放)。

如果你使用 Visual C++,你甚至可以

char *str = "Foo"; // your string
_bstr_t bstrt(str);
BSTR bstr = bstrt.Detach(); 
// bstr is the returned string

或者 C 端,您可以使用可以在 C# 端释放的两个分配器之一:LocalAllocCoTaskMemAlloc

char *str = "Foo"; // your string
char *buf = (char*)LocalAlloc(LMEM_FIXED, strlen(str) + 1);
// or char *buf = (char*)CoTaskMemAlloc(strlen(str) + 1);
strcpy(buf, str);
// buf is the returned string

然后你使用第一个例子,而不是调用

freeMemory(buffer);

你打电话:

Marshal.FreeHGlobal(buffer); // for LocalAlloc

Marshal.FreeCoTaskMem(buffer); // for CoTaskMemAlloc

【讨论】:

  • 谢谢!我现在检查一下这个方法。
  • 非常感谢!您的回答对我有帮助 - 现在可以了!顺便说一句,“freeMemory”也存在于同一个dll中。
  • 我使用了第一种方法——使用 IntPtr。
猜你喜欢
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 2021-07-15
  • 2021-02-11
  • 2021-03-15
  • 1970-01-01
  • 2015-07-13
  • 2016-09-22
相关资源
最近更新 更多