简体   繁体   English

C#dllimport参数移位

[英]c# dllimport parameters shift

I am currently developing an Excel add-in in C#, and I am using interop with a C++ library. 我目前正在开发一个Excel加载在C#中,我使用互操作与C ++库。 Both are developed by me. 两者都是我开发的。 The C++ library is not a COM component, but just a DLL exporting some functions. C ++库不是COM组件,而只是导出某些功能的DLL。

I have one C# function, that I want to pass a number and two strings to the C++ function, and the C++ function returns a string. 我有一个C#函数,我想将一个数字和两个字符串传递给C ++函数,然后C ++函数返回一个字符串。 First I tried to return a string directly, so the prototypes look something like 首先,我尝试直接返回一个字符串,所以原型看起来像

//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*);

(Btw, I set already the calling convention in C# for this function as Cdecl) (顺便说一句,我已经在C#中将此函数的调用约定设置为Cdecl)

Then when I call the C# version, and stepped into the C++ (when debugging), I found that the parameters are shifted, so the integer is the value of the pointer to the first string, and the first string is the second string, and the second string points to somewhere else. 然后,当我调用C#版本并进入C ++(调试时)时,我发现参数已移位,因此整数是指向第一个字符串的指针的值,第一个字符串是第二个字符串,并且第二个字符串指向其他地方。 I also checked the memory, and found that the parameters were not passed according to the _cdecl convention, the integer was the last one pushed into the stack (which is ok), but the positions of the two strings were switched. 我还检查了内存,发现未根据_cdecl约定传递参数,该整数是最后一个压入堆栈的堆栈(可以),但是两个字符串的位置已切换。 There are many other information that the compiler added, so I don't want to go further deep into this. 编译器还添加了许多其他信息,因此我不想进一步深入探讨。

However, later I changed the return string as a parameter, and the prototypes look like 但是,后来我将返回字符串更改为参数,原型看起来像

//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&);

And now the parameters are passed correctly. 现在,参数已正确传递。

So my first question is, how does this happen? 所以我的第一个问题是,这是怎么发生的?

My second question is, even using the second method, I could not get the program run correctly, the program crashed when returning from the C++ function (actually in the C++ function, the only thing being done is calling another member function of a class, so the function is just like a wrapper of the member function, and the program crashed exactly when returning in the member function. Since the warpper function just calls the member function, so I cannot tell where the problem is). 我的第二个问题是,即使使用第二种方法,我也无法使程序正常运行,从C ++函数返回时,程序崩溃了(实际上是在C ++函数中,唯一要做的就是调用类的另一个成员函数,因此该函数就像成员函数的包装器一样,并且返回成员函数时程序完全崩溃。由于warpper函数只是调用成员函数,因此我无法确定问题出在哪里。

Does anyone have an idea how to do this? 有谁知道如何做到这一点? So the main point of the function is to take a number and two strings and return another string. 因此,函数的要点是取一个数字和两个字符串并返回另一个字符串。

Thanks in advanced. 提前致谢。

look at this article about the usage of stringbuilder in unmanaged code 查看有关非托管代码中stringbuilder用法的本文

try something like this: 尝试这样的事情:

//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!!
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM