通过 Interop 调用一个方法,其中 returns 一个结构的实例
Call a method through Interop which returns an instance of a struct
我是 Interop 的新手,需要从 C# 调用托管 C++ 方法,其中 returns 以下 struct
的实例:
typedef struct DataBlock_ {
unsigned char data[10240];
unsigned int numberOfBytes;
unsigned long int startAddr;
} DataBlock;
returns实例声明的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()
的调用抛出
An unhandled exception of type
'System.Runtime.InteropServices.MarshalDirectiveException' occurred in
ConsoleApplication1.exe
Additional information: Method's type signature is not PInvoke
compatible.
基于this question, I tried changing the declaration of data
to public fixed byte data[10240]
and marked the struct as unsafe
, but then the method returns an instance with numberOfBytes
and startAddr
set to 0, and the subsequent call to sendPassword()
fails (note that in this answer,后续调用使用指向结构的指针而不是实例本身,就像我的情况一样)。那么我应该如何从 C# 调用方法?
该项目面向 .NET 3.5 和 x86。
在此先感谢您的帮助。
struct
很好 - 它满足在 P/Invoke.
中用作 return 值的所有规则
您需要使用正确的调用约定(在您的情况下,CallingConvention.Cdecl
)。
还有一些编译器使用的额外优化,其中大结构(例如您的结构)通过引用传递,而不是 returned。您可以像这样在 C# 中复制它:
static public extern void getDefaultPass(out DataBlock data);
为了完整性和补充 Luaan 的回答,由于问题中的 C++ 方法没有参数,我想涵盖方法确实有参数的情况,特别是因为它与 out
参数,当方法接受 2 个或更多参数时。
考虑 C++ 方法
__declspec(dllexport) DataBlock readText(char * dataArray , int bytesToRead)
在 C# 方法中 out
参数应该是第一个还是最后一个并不是很明显。与框架约定将out
参数放在最后一个参数(如TryParse
)相反,这里必须是第一个参数,否则会调用失败:
[DllImport("my.dll", CallingConvention = CallingConvention.Cdecl)]
static public extern void readText(out DataBlock dataBlock, string dataArray, int bytesToRead);
我是 Interop 的新手,需要从 C# 调用托管 C++ 方法,其中 returns 以下 struct
的实例:
typedef struct DataBlock_ {
unsigned char data[10240];
unsigned int numberOfBytes;
unsigned long int startAddr;
} DataBlock;
returns实例声明的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()
的调用抛出
An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in ConsoleApplication1.exe
Additional information: Method's type signature is not PInvoke compatible.
基于this question, I tried changing the declaration of data
to public fixed byte data[10240]
and marked the struct as unsafe
, but then the method returns an instance with numberOfBytes
and startAddr
set to 0, and the subsequent call to sendPassword()
fails (note that in this answer,后续调用使用指向结构的指针而不是实例本身,就像我的情况一样)。那么我应该如何从 C# 调用方法?
该项目面向 .NET 3.5 和 x86。
在此先感谢您的帮助。
struct
很好 - 它满足在 P/Invoke.
您需要使用正确的调用约定(在您的情况下,CallingConvention.Cdecl
)。
还有一些编译器使用的额外优化,其中大结构(例如您的结构)通过引用传递,而不是 returned。您可以像这样在 C# 中复制它:
static public extern void getDefaultPass(out DataBlock data);
为了完整性和补充 Luaan 的回答,由于问题中的 C++ 方法没有参数,我想涵盖方法确实有参数的情况,特别是因为它与 out
参数,当方法接受 2 个或更多参数时。
考虑 C++ 方法
__declspec(dllexport) DataBlock readText(char * dataArray , int bytesToRead)
在 C# 方法中 out
参数应该是第一个还是最后一个并不是很明显。与框架约定将out
参数放在最后一个参数(如TryParse
)相反,这里必须是第一个参数,否则会调用失败:
[DllImport("my.dll", CallingConvention = CallingConvention.Cdecl)]
static public extern void readText(out DataBlock dataBlock, string dataArray, int bytesToRead);