【问题标题】:PInvoke and char**PInvoke 和字符**
【发布时间】:2011-08-23 22:34:06
【问题描述】:

我从某人那里得到了这个程序集,我想在我的 c# 应用程序中使用它。

标题如下所示:

int __declspec(dllimport) s2o(WCHAR* filename, char** out, int* len);

我设法让它部分工作,使用:

[DllImport("s2o.dll", EntryPoint = "?skn2obj@@YAHPA_WPAPADPAH@Z", CallingConvention = CallingConvention.Cdecl)]
public static extern int s2o(
    [MarshalAs(UnmanagedType.LPWStr)]
    string filename,
    ref char[] @out,
    ref int len
);

然后这样称呼它:

char[] result = null;
int length = 0;
s2o("filepath", ref result, ref length);

它似乎部分起作用,因为“长度”实际上得到了一个值。 不幸的是,“结果”保持为空。

我应该怎么做才能让它工作?

编辑:

好的,我设法将 char[] 替换为 IntPtr,然后像 Nick 建议的那样调用“Marshal.PtrToStringAnsi”:

string result = Marshal.PtrToStringAnsi(ptr);

但是,由于同一答案中的 cmets,我有点担心内存使用情况。程序集中没有提供其他方法,所以我该如何清理?

【问题讨论】:

  • 您可以尝试将 char[] 替换为 IntPtr 并为指针调用 PtrToStringAutoMarshal .PtrToStringAuto(@out)
  • 请在您的 DLL 中使用 extern "C" 声明您的函数以禁用名称修改。现在回答你的问题。在您告诉我们out 参数的工作原理之前,我们无法告诉您如何调用此函数。谁分配什么?你有s2o 的任何文档吗?
  • @David:我认为他是在说这是第 3 方 DLL,所以他可能无法添加 extern "C"。
  • 确实是第三方dll。
  • 您可以尝试使用 Marshal.FreeCoTaskMem 或 FreeHGlobal。但是如果不知道 DLL 中的内存是如何分配的,就很难知道会发生什么!

标签: c# .net pinvoke char marshalling


【解决方案1】:

关于你的最后一个问题:

  • char 是单个字符。
  • char* 是一个指向字符的指针。如果将其解释为字符串,则内存中此内存地址之后的所有数据都将被视为属于该字符串,直到遇到具有 0x0 的值。将char* 传递给方法意味着该方法可以更改字符串的内容,但不能更改其长度。
  • char** 是一个指向 char 的指针。将此传递给方法意味着该方法能够创建一个新字符串并将新地址返回给调用者。

【讨论】:

  • 另一种可能性是char** 是一个 C 字符串数组,例如argv.
【解决方案2】:

看看Marshal.PtrToStringAnsi 方法。

或者正如 Centro 在对您问题的评论中所说,PtrToStringAuto 可能更合适。

复制所有字符直到第一个 来自非托管 ANSI 的空字符 字符串到托管字符串,并加宽 每个 ANSI 字符转换为 Unicode。

另请注意,您可能负责释放从该函数返回的内存。

【讨论】:

  • 托管代码如何释放本地代码中分配的内存?只有当本机代码提供释放它的方法、导出分配器或使用 COM 分配器时,这才有效。
  • @David:是的,你是对的。 O.P. 需要查看 DLL 的文档并确定如何释放内存。
  • 当 PtrToStringAuto 工作时,我没有得到预期的结果(相反我得到了很多汉字),所以我认为出了点问题。另外,我很确定 'out' 是一个 char 数组,所以我不需要先进行某种转换吗?
  • 你试过Ansi版本吗?
猜你喜欢
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 2011-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
相关资源
最近更新 更多