将 C# 字符串作为参数发送到非托管 C++ DLL 函数

Posted

技术标签:

【中文标题】将 C# 字符串作为参数发送到非托管 C++ DLL 函数【英文标题】:Sending a C# string as an argument to a unmanaged C++ DLL function 【发布时间】:2011-06-07 19:26:51 【问题描述】:

我想将我的 C# 字符串发送到 C++ DLL 函数。我已经成功了,都使用了 StringBuilder:

[C#]
public static extern int installHook(StringBuilder directory);
StringBuilder myText = new StringBuilder(512);
myfunc(myText);

[C++]
int OPENGLHOOK_API myfunc(char* directory)

    ::MessageBoxA(NULL,directory,"test123",0);

还有一个简单的字符串 & wchar:

[C#]
public static extern int installHook(string directory);
myfunc("myText");

[C++]
int OPENGLHOOK_API installHook(wchar* directory)

    wstring s = directory;
    const wchar_t* wstr = s.c_str();
    size_t wlen = wcslen(wstr) + 1;
    char newchar[100];
    size_t convertedChars = 0;
    wcstombs_s(&convertedChars, newchar, wlen, wstr, _TRUNCATE);

    ::MessageBoxA(NULL,newchar,"test123",0);

正如 *** 上的其他线程中提到的那样。问题是每次我这样做,我都会得到一个错误,因为函数签名不一样:

托管调试助手“PInvokeStackImbalance”在“C:\Users\Dave\Documents\Visual Studio 2010\Projects\OpenGLInjector\Loader\bin\Release\Loader.vshost.exe”中检测到问题。 附加信息:对 PInvoke 函数 'Loader!Loader.Form1::myfunc' 的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

知道如何解决我的问题/从这里做什么?

【问题讨论】:

OPENGLHOOK_API 扩展为什么? 简单的 __declspec(dllexport) 定义 pinvokestackimbalance -- how can I fix this or turn it off?的可能重复 我希望它是.. 我可以关闭 MDA,但这并不能解决我的问题,不是吗? @David :这意味着你的函数被导出为__cdecl,但.NET P/Invoke 默认需要__stdcall。您需要协调这些。 【参考方案1】:

我认为问题在于两种语言之间的默认调用约定。我相信 C# 是 __stdcall 而 c++ 是 __cdecl。尝试在 C++ 方法签名上明确声明 __stdcall,看看是否不能解决错误。

C++:

int OPENGLHOOK_API __stdcall installHook(wchar* directory)

C#:

[DllImport( "yourdll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode )]
static extern int installHook(string directory);

【讨论】:

谢谢,我在哪里做这个?我要替换 __declspec(dllexport) 吗? - NVM 得到它,效果很好,谢谢 C++ 不应该是 int __stdcall installHook(wchar* directory),即没有 OPENGLHOOK_API 因为 OPENGLHOOK_API 扩展为 __declspec(dllexport) 吗?【参考方案2】:

您需要明确描述 32 位的非托管调用约定,此外,您还需要明确描述非托管字符串类型 - ASCII、UTF16 等。

【讨论】:

C# __stdcall 的默认调用约定不是独立于平台的吗? @Brandon Moretz:x64 没有不同的调用约定。 @Downvoter :按照这个答案的建议去做就可以完全解决 OP 的问题;为什么投反对票? 不好意思说的这么粗,但是你在哪里明确描述了非托管字符串类型呢?

以上是关于将 C# 字符串作为参数发送到非托管 C++ DLL 函数的主要内容,如果未能解决你的问题,请参考以下文章

将回调参数从 C# 传递到非托管 C++

C# 调用非托管 C++ 返回平方符号字符串

我想从 C++ 非托管代码调用 C# 委托。无参数委托工作正常,但有参数委托使我的程序崩溃

非托管 C++ 加密字符串转换为 C# byte[]

将回调作为参数发送到 QJSValue::callAsConstructor()

从 C# 调用非托管 DLL,将结构作为参数传递