我使用PInvoke从C++代码访问C++库。但是,我在使用以下函数时遇到了问题:
UINT32 myfunc(IN char * var1, IN UINT32 var2, INOUT UINT16 * var3, OUT UINT8 * var4)文件上说:
返回参数是错误代码。 var1是一个字符串 var2是一个整数 var3是一个指向整数的指针(该值将为var4的大小,该值将由该函数更改) var4是指向将由函数填充的缓冲区的指针。
当我用
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int myfunc(string var1, int var2, out int var3,
out byte[] var4);该函数提供了以下异常:
托管调试助手“FatalExecutionEngineError”检测到了FatalExecutionEngineError中的一个问题 附加信息:运行时遇到致命错误。在线程0x2edc上,错误地址为0x74292e44。错误代码为0xc0000005。此错误可能是CLR中的错误,也可能是用户代码中不安全或不可验证部分中的错误。此错误的常见来源包括COM-interop或PInvoke的用户封送错误,这可能会损坏堆栈。 如果存在此异常的处理程序,则可以安全地继续该程序。
我尝试使用参数来查看是否可以得到任何内容,并将字符集更改如下:
[DllImport("mydll.dll, CallingConvention = CallingConvention.Cdecl", CharSet = CharSet.Unicode)]
public static extern int myfunc(string var1, int var2, out int var3, out byte[] var4);在这种情况下,它不会给出FatalExecutionEngineError,相反,函数返回时不会出错。但返回值表示函数中发生了内部错误hass。(我不知道为什么字符集更改会阻止FatalExecutionEngineError。)
我不知道我做错了什么,请帮帮我。
发布于 2013-01-16 11:47:54
p/invoke声明应该如下所示:
[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int myfunc(
string var1,
uint var2,
ref ushort var3,
byte[] var4
);然后你就这样叫它:
string var1 = "...";
uint var2 = ...;
ushort var3 = 1024;//use whatever length buffer you want to pass
byte[] var4 = new byte[var3];
int retval = myfunc(var1, var2, ref var3, var4);
Array.Resize(ref var4, var3);本机代码的工作方式是期望调用代码分配缓冲区var4。调用代码说明缓冲区在var3中的时间。
然后,当本机代码返回时,var3包含缓冲区的实际长度。也可能是复制的字节数。前者更有用。假设是前者,那么您也许可以这样写它:
string var1 = "...";
uint var2 = ...;
ushort var3 = 0;
int retval = myfunc(var1, var2, ref var3, null);
byte[] var4 = new byte[var3];
int retval = myfunc(var1, var2, ref var3, var4);您应该检查返回值等。
我不能100%确定如何调用函数,因为您的问题中没有足够的信息。至少p/invoke签名现在与您的C++代码匹配。
发布于 2013-01-16 12:07:18
这是一个潜在的非常危险的功能,它可以通过第四个参数任意地向内存中喷射垃圾。如果它设计得很好(手指交叉),那么它应该允许您首先测量所需的缓冲区大小。任意猜测:
[DllImport("mydll.dll, CallingConvention = CallingConvention.Cdecl", CharSet = CharSet.Ansi)]
public static extern int myfunc(string name, ref int var2, ref int buflen, IntPtr buf);
string name = "foo";
int var2 = 42; //???
int len = 0;
int error = myfunc(name, ref var2, ref len, IntPtr.Zero);
if (error == BUFFER_TOO_SMALL) {
IntPtr buf = Marshal.AllocCoTaskMem(len);
try {
error = myfunc(name, ref var2, ref len, buf);
if (error == OK) {
var bytes = new bytes[len];
Marshal.Copy(buf, bytes, 0, len);
//...
}
}
finally {
Marshal.FreeCoTaskMem(buf);
}
}
if (error != OK) handleError(error);这是个很大的猜测。如果函数实际上不允许您首先请求所需的缓冲区大小,那么您应该更改C代码,因此它的工作方式如下。唯一安全的方法。
https://stackoverflow.com/questions/14356362
复制相似问题