我是Interop的新手,需要从C#调用托管C ++方法,该方法返回以下struct
的实例:
typedef struct DataBlock_ {
unsigned char data[10240];
unsigned int numberOfBytes;
unsigned long int startAddr;
} DataBlock;
返回实例的C ++方法声明如下:
__declspec(dllexport) DataBlock getDefaultPass( void )
{
DataBlock default_pass = {
{
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF,
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF,
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF,
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF,
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF,
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF,
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF,
(char)0xFF,(char)0xFF,(char)0xFF,(char)0xFF
},
32,
0xFFE0
};
return default_pass;
}
我已经在C#中声明了结构和方法,如下所示:
public static partial class My
{
[StructLayout(LayoutKind.Sequential)]
public struct DataBlock
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10240)]
public byte[] data;
//public fixed byte data[10240]; <-- this requires 'unsafe' but still doesn't work
public UInt32 numberOfBytes;
public UInt32 startAddr;
}
[DllImport("my.dll")]
static public extern DataBlock getDefaultPass( );
[DllImport("my.dll")]
static public extern byte sendPassword(DataBlock data);
}
我从C#调用方法如下:
var defaultPassword = My.getDefaultPass();
var response = My.sendPassword(defaultPassword);
但是对getDefaultPass()
的调用会抛出
未处理的类型异常 发生'System.Runtime.InteropServices.MarshalDirectiveException' ConsoleApplication1.exe中
附加信息:方法的类型签名不是PInvoke 兼容。
基于this question,我尝试将data
的声明更改为public fixed byte data[10240]
并将结构标记为unsafe
,但该方法返回一个{{1}的实例并且numberOfBytes
设置为0,随后对startAddr
的调用失败(请注意,在this answer中,后续调用使用指向结构的指针而不是实例本身,因为我的情况)。那么我应该如何调用C#中的方法?
该项目的目标是.NET 3.5和x86。
提前感谢您的帮助。
答案 0 :(得分:1)
struct
很好 - 它符合在P / Invoke中用作返回值的所有规则。
您需要使用正确的调用约定(在您的情况下,CallingConvention.Cdecl
)。
还有一些额外的优化,一些编译器使用,其中一个大的结构(如你的)通过引用传递,而不是返回。您可以在C#中复制它,如下所示:
static public extern void getDefaultPass(out DataBlock data);
答案 1 :(得分:0)
为了完整性和补充Luaan的答案,由于问题中的C ++方法没有参数,我想要涵盖一个方法确实有参数的情况,特别是因为它与{{1的位置有关方法接受2个或更多参数时的参数。
考虑C ++方法
out
__declspec(dllexport) DataBlock readText(char * dataArray , int bytesToRead)
参数在C#方法中应该是第一个还是最后一个,这一点并不明显。与框架将out
参数作为最后一个参数(例如out
)的惯例相反,此处必须是第一个参数,否则调用将失败:
TryParse