我有一个导出为接口的C++函数,如下所示:
#define WIN322_API __declspec(dllexport)
WIN322_API char* Test(LPSTR str);
WIN322_API char* Test(LPSTR str)
{
return "hello";
}
该函数被.DEF文件正确地导出为API,因为我可以在依赖遍历工具中看到它。现在我有了一个C#测试程序:
[DllImport("c:\\win322.dll")]
public static extern string Test([MarshalAs(UnmanagedType.LPStr)] String str);
private void Form1_Load(object sender, EventArgs e)
{
string _str = "0221";
Test(_str); // runtime error here!
}
在调用Test()方法时,我得到错误:
“对PInvoke函数'MyClient!MyClient.Form1::Test‘的调用使堆栈不平衡。这可能是因为托管PInvoke签名与非托管目标签名不匹配。请检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。”
我尝试了许多其他数据类型和编组,但一无所获!请帮帮我!
发布于 2011-01-03 21:07:55
确保您有正确的调用约定。您的DLL可以使用Cdecl,而C#默认使用Cdecl。最好总是显式地定义调用约定。
特别是在使用存在于ANSI和宽字符版本(带有A或W前缀的版本)中的窗口函数时,请显式指定CharSet,以便使用正确的版本。
当函数返回值时,显式封送返回值。否则,编译器将选择默认值,这可能是错误的。我怀疑这也是问题所在。
因此,请更改为以下内容,例如:
[DllImport("c:\\win322.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string Test([MarshalAs(UnmanagedType.LPStr)] String str);
发布于 2011-01-03 21:51:04
这是由于调用约定不匹配造成的,DllImport的默认值是Stdcall,而C编译器的默认值是Cdecl。在声明中使用CallingConvention属性。
但这并不是唯一的问题,这段代码将在Vista和Win7上崩溃。从C函数返回一个字符串是相当麻烦的,有一个内存管理问题。目前还不清楚谁负责释放字符串缓冲区。你现在返回了一个文本,但这很快就不再有用了。下一步是使用malloc()作为返回字符串,目的是让调用者调用free()。这是行不通的,pinvoke编组程序不能调用它,因为它不知道C代码使用的是什么堆。
它将调用Marshal.FreeCoTaskMem()。这是错误的,字符串不是由CoTaskMemAlloc()分配的。这在XP和更早的版本上不会被注意到,除了它导致的非常难以诊断的内存泄漏。在Vista和Win7上失败了,他们有一个更严格的内存管理器。
你需要像这样重写C函数:
extern "C" __declspec(dllexport)
void __stdcall Test(const char* input, char* output, int outLen);
现在调用者提供了缓冲区,通过输出参数,不再猜测谁拥有内存。在C#声明中使用StringBuilder。
[DllImport("foo.dll")]
private static extern void Test(string input, StringBuilder output, int outLen);
...
var sb = new StringBuilder(666);
test("bar", sb, sb.Capacity);
string result = sb.ToString();
在C代码中使用outLen参数时要小心,这样可以确保不会使缓冲区溢出。这会破坏垃圾收集堆,并使用致命的执行引擎错误使应用程序崩溃。
发布于 2011-01-03 20:30:09
将宏定义更改为
#define WIN322_API __declspec(dllexport) __stdcall
或者,在导入时使用CallingConvention.Cdecl
。
例如,有关调用约定的更多信息,请阅读here。
https://stackoverflow.com/questions/4584111
复制相似问题