c#dllimport参数移位

时间:2012-08-24 08:06:37

标签: c# c++ parameters marshalling dllimport

我目前正在使用C#开发Excel加载项,我正在使用C ++库的互操作。两者都是由我开发的。 C ++库不是COM组件,只是导出一些函数的DLL。

我有一个C#函数,我想将一个数字和两个字符串传递给C ++函数,C ++函数返回一个字符串。首先我尝试直接返回一个字符串,所以原型看起来像

//C#
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string Function([MarshalAs(UnmanagedType.I4)] int number,
                                      [MarshalAs(UnmanagedType.LPStr)]string str1,
                                      [MarshalAs(UnmanagedType.LPStr)] string str2);
//C++
extern "C" __declspec(dllexport) string Function(int, char*, char*);

(顺便说一下,我已经将C#中的调用约定设置为Cdecl)

然后当我调用C#版本并进入C ++(调试时)时,我发现参数被移位,所以整数是指向第一个字符串的指针的值,第一个字符串是第二个字符串string,第二个字符串指向其他地方。我还检查了内存,发现参数没有根据_cdecl约定传递,整数是最后一个被推入堆栈的(这没关系),但是两个字符串的位置都被切换了。编译器添加了许多其他信息,因此我不想进一步深入研究。

但是,后来我将返回字符串更改为参数,原型看起来像

//C#
private static extern void Function([MarshalAs(UnmanagedType.I4)]int number,
                                    [MarshalAs(UnmanagedType.LPStr)] string str1,
                                    [MarshalAs(UnmanagedType.LPStr)] string str2,
                                    [MarshalAs(UnmanagedType.LPStr), Out] StringBuilder returnStr);
//C++
extern "C" __declspec(dllexport) void Function(int, char*, char*, string&);

现在参数正确传递。

所以我的第一个问题是,这是怎么发生的?

我的第二个问题是,即使使用第二种方法,我也无法使程序正常运行,程序在从C ++函数返回时崩溃(实际上在C ++函数中,唯一要做的就是调用另一个成员函数一个类,所以函数就像成员函数的包装器一样,程序在成员函数返回时完全崩溃。由于warpper函数只调用成员函数,所以我不知道问题在哪里)。

有谁知道如何做到这一点?所以函数的要点是取一个数字和两个字符串并返回另一个字符串。

先谢谢。

1 个答案:

答案 0 :(得分:0)

look at this article about the usage of stringbuilder in unmanaged code

尝试这样的事情:

//C#
public string Function(int number, string str1, string str2)
{
    StringBuilder sbStr1 = new StringBuilder(str1);
    StringBuilder sbStr2 = new StringBuilder(str2);
    StringBuilder sbReturnStr = new StringBuilder(1024);
    Function(number, sbStr1 , sbStr2 , sbReturnStr , sbReturnStr.Capacity);
    return sbReturnStr.ToString();
}

//C# p/invoke
private static extern void Function(int number, StringBuilder str1, StringBuilder str2, StringBuilder returnStrBuffer, int size);

//C++
extern "C" __declspec (dllexport) void __stdcall Function(int number, const char* str1, const char* str2, char* returnStrBuffer, int size)
{
     //fill the returnStrBuffer
     strncpy(returnStrBuffer, "blablalb", size); //example!!
}