编组字符 *

Posted

技术标签:

【中文标题】编组字符 *【英文标题】:Marshalling char * 【发布时间】:2011-02-21 21:07:41 【问题描述】:

我的 c++ dll 上有以下方法签名:

extern char *bpStringCalc(char *bpDirectory, char *issString);

我正在尝试使用以下方法从 c# 调用它:

[DllImport(@"C:\MuniAxis\Bp\BpDLL.dll", CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string bpStringCalc([MarshalAs(UnmanagedType.LPStr)] string bpDirectory,
                                         [MarshalAs(UnmanagedType.LPStr)] string issString);

但它不断收到此异常:

'ConsoleApplication1!ConsoleApplication1.Program::bpStringCalc' 使堆栈不平衡。这是 可能是因为托管的 PInvoke 签名与非托管的不匹配 目标签名。检查 调用约定和参数 PInvoke 签名匹配目标 非托管签名。

有什么想法吗?

谢谢

【问题讨论】:

据我所知,使用 StringBuilder 而不是字符串会更幸运。 确保在调用方法之前将字符串实例固定在内存中。 @BrokenGlass:考虑到参数不是问题,应该没有区别。 【参考方案1】:

尝试在导入时指定 Cdecl 调用约定或在导出时指定 __stdcall。见this almost similar question。

【讨论】:

+1 用于类似的问题链接和(正确)在__stdcall 之前放置两个下划线,我最初搞砸了:) 这就是答案。 C++ 默认为__cdecl,但出于某种疯狂的原因,P/Invoke 默认为__stdcall @DeadMG DllImport 默认为Winapi,根据平台选择StdCallCdecl @DeadMG:默认为__stdcall,因为P/Invoke最常用的就是调用Win32函数,Win32全部使用__stdcall @Billy:考虑到我在几分钟前回答了这个问题,很难不提供链接 :)【参考方案2】:

不平衡堆栈可能更多地与调用约定有关,而不是与实际参数有关。默认情况下,C++ 使用 __cdecl 调用约定。 C# 默认为 __stdcall,因为 __stdcall 是 Win32 使用的约定。您需要在 C# 中的 import 语句中设置 calling convention,或者您需要在 C++ 二进制文件中指定 __stdcall

编辑:对以上内容进行了编辑,以修正__cdecl__stdcall 各自只有一个前导下划线的事实;)

【讨论】:

以上是关于编组字符 *的主要内容,如果未能解决你的问题,请参考以下文章

编组包含 c 字符串的结构

C# 中的字符 * 编组

在 JaxB 编组期间将字符串截断到最大限制

C# 和 C++ dll - 编组字符串

从 C++ dll 编组导出的字符串向量

从 c# dll 调用/编组字符串到非托管代码