您好我是C#和C ++编程的新手,并尝试在C#项目(.NET 3.5)中使用非托管C ++ dll。我坚持这个错误:
System.Runtime.InteropServices.SafeArrayTypeMismatchException:指定的数组不是预期的类型。
这是DLL的头文件
#ifdef FUNCTIONLIB_EXPORTS
#define FUNCTIONLIB_API __declspec(dllexport)
#else
#define FUNCTIONLIB_API __declspec(dllimport)
#endif
typedef struct _FunctionOpt
{
char UserName[32];
char Password[32];
char ServerIP[128];
int ServerPort;
int Index;
char TargetSubChannel;
long Timeout;
char Filepath[256];
bool isFirst;
DWORD SyncTime;
char *pOutBuf;
int OutBufSize;
unsigned short OutImgResW;
unsigned short OutImgResH;
}STFUNCTIONOPT, *PSTFUNCTIONOPT;
FUNCTIONLIB_API int FunctionLib_Snapshot( PSTFUNCTIONOPT pstFunctionOpt );
我无法访问C ++代码,因此我只能更改以下C#代码。我的相关代码如下:
public unsafe struct PSTFUNCTIONOPT
{
public char[] UserName;
public char[] Password;
public char[] ServerIP;
public int ServerPort;
public int Index;
public char TargetSubChannel;
public long Timeout;
public char[] Filepath;
public bool isFirst;
public uint SyncTime;
public char *pOutBuf; // example C++ usage: myStruct.pOutBuf = (char*)malloc(1920 * 1080 * 3);
public int OutBufSize;
public ushort OutImgResW;
public ushort OutImgResH;
}
// need to use dumpbin to get entrypoint name due to c++ mangling
[DllImport(@"C:\Location\To\Project\bin\FunctionLibLib.dll", EntryPoint = "?FunctionLib_Snapshot@@YAHPAU_FunctionOpt@@@Z")]
public static extern int FunctionLib_Snapshot(PSTFUNCTIONOPT pstFunctionOpt);
public unsafe int FunctionLib_Run()
{
PSTFUNCTIONOPT stFunctionOpt = new PSTFUNCTIONOPT();
stFunctionOpt.UserName = ("uname").ToCharArray();
stFunctionOpt.Password = ("pword").ToCharArray();
stFunctionOpt.ServerIP = ("192.168.1.1").ToCharArray();
stFunctionOpt.ServerPort = 80;
stFunctionOpt.Index = 255;
stFunctionOpt.Timeout = 15000;
stFunctionOpt.Filepath = ("c:\\temp\\test.jpg").ToCharArray();
stFunctionOpt.isFirst = true;
stFunctionOpt.SyncTime = 0;
//stFunctionOpt.pOutBuf = new char*[10000]; // not sure how to do this yet
stFunctionOpt.OutBufSize = 10000;
// get result from DLL
return FunctionLib_Snapshot(stFunctionOpt);
}
如何正确地将结构传递给此非托管DLL?这个错误似乎很简单,但我还没有能够缩小问题的范围。任何帮助表示赞赏!
答案 0 :(得分:2)
几个问题:
public char[] UserName;
需要将其编组为嵌入字符串:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string UserName;
对于声明为此的其他字段重复此操作。
public char *pOutBuf; // example C++ usage: myStruct.pOutBuf = (char*)malloc(1920 * 1080 * 3);
目前尚不清楚C ++函数是分配该缓冲区还是客户端代码应该这样做。如果它是前者那么你有一个大问题,你不能调用free()函数再次释放缓冲区。你唯一的希望是你的C#代码应该分配它,而不是不可能。在这种情况下它是:
public byte[] pOutBuf;
...
stFunctionOpt.pOutBuf = new byte[10000];
stFunctionOpt.OutBufSize = stFunctionOpt.pOutBuf.Length;
pinvoke声明错误:
[DllImport(@"C:\Location\To\Project\bin\FunctionLibLib.dll", EntryPoint = "?FunctionLib_Snapshot@@YAHPAU_FunctionOpt@@@Z")]
public static extern int FunctionLib_Snapshot(PSTFUNCTIONOPT pstFunctionOpt);
论证是ref PSTFUNCTIONOPT pstFunctionOpt
。从结构名称中删除P,它不是指针类型。避免硬编码DLL的路径,这不会对用户的机器起作用。只需确保在构建输出目录中有DLL的副本。
答案 1 :(得分:1)
我认为你遗漏了结构定义中的一些东西
[StructLayout(LayoutKind.Sequential)]
属性[MarshalAs(UnmanagedType.ByValTStr, SizeConst = your_array_lenght)]
来指定,而且如果你这样做,编组器将处理字符串和char数组之间的转换。您的结构定义应该类似于
[StructLayout(LayoutKind.Sequential)]
public struct PSTFUNCTIONOPT
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string UserName;
...
[MarshalAs(UnmanagedType.LPStr)]
public string pOutBuf;
}
有关详细信息,请查看http://msdn.microsoft.com/en-us/library/s9ts558h.aspx