将数组作为 ref/out 传递时 P/invoke System.ExecutionEngineException
我在非托管 dll 函数 swe_calc_ut 上使用 P/invoke。
int swe_calc_ut(double tjd_et, int ipl, int iflag, double *xx, char *serr)
参数 xx 是一个“用于存储结果的 6 个双精度数组”,参数 serr 是一个“返回错误消息的字符串”,
我的 C# 代码如下。
[DllImport("swedll32.dll")]
private static extern int swe_calc_ut(double tjd_ut, int ipl, int iflag, out double[] xx, out char[] serr);
double jul_day_UT=22000;
int p=3;
int iflag=64 * 1024;
double[] arr;
char[] serr;
int x = swe_calc_ut(jul_day_UT, p, iflag , out arr, out serr);
现在,当我执行函数 swe_calc_ut 函数时,我收到错误“抛出了‘System.ExecutionEngineException’类型的异常。”。我是 P/invoke 新手,所以我可能犯了一个愚蠢的错误。我认为这一定是数组,因为早些时候当我意外地按值传递它们时,我没有收到错误。我非常感谢你的帮助。
Im using an P/invoke on an unmanaged dll function swe_calc_ut.
int swe_calc_ut(double tjd_et, int ipl, int iflag, double *xx, char *serr)
Parameter xx is meant to be an "array of 6 doubles for storing the result", and parameter serr a "character string to return error messages"
my c# code is as follows.
[DllImport("swedll32.dll")]
private static extern int swe_calc_ut(double tjd_ut, int ipl, int iflag, out double[] xx, out char[] serr);
double jul_day_UT=22000;
int p=3;
int iflag=64 * 1024;
double[] arr;
char[] serr;
int x = swe_calc_ut(jul_day_UT, p, iflag , out arr, out serr);
Now when i execute the function swe_calc_ut function i get the error "Exception of type 'System.ExecutionEngineException' was thrown.". I'm new to P/invoke so i'm probably making a stupid mistake. I thought it must be the arrays since earlier when i passed them by value accidentally i did not get an error. I'd really appreciate your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您不必在此处使用
out
或ref
。事实上,失去他们两个。并在 C# 中将两个数组预分配到所需的大小。You don't have to use
out
orref
here. In fact, lose both of them. And preallocate both arrays to the desired size in C#.这是 C 语言的约定,通过传递指向数组第一个元素的指针来传递数组。因此 double[] 已经被编组为
double*
。当您使用 out 或 ref 关键字时,您告诉编组器该函数返回一个指向 new 数组的指针,一个double **。
该函数不创建一个新数组,它要求客户端传递一个足够大的数组来接收结果。因此,out 和 ref 注释都不正确。顺便说一句,serr 参数应该声明为 StringBuilder。
该函数非常危险,因为客户端无法说出它创建的数组有多大。特别是 serr 参数的问题。详细的错误消息很容易超出数组的末尾,这将破坏垃圾收集堆。你无能为力,只能传递一个非常大的数组(即具有大容量的 StringBuilder)并祈祷。缓冲区溢出是恶意软件作者的首选攻击媒介。不太可能在托管程序中被滥用,它只会使应用程序崩溃并收取费用。
It is a convention of the C language, you pass an array by passing a pointer to the first element of the array. So a double[] is already marshaled as a
double*
. When you use the out or ref keyword, you tell the marshaller that the function returns a pointer to a new array, adouble**
.The function does not create a new array, it requires the client to pass an array that's large enough to receive the result. Therefore, neither the out nor the ref annotation is correct. The serr argument should be declared as StringBuilder btw.
The function is very dangerous since there is no way for the client to say how large an array it created. Particularly a problem with the serr argument. A detailed error message is prone to overrun the end of the array and that will destroy the garbage collected heap. Nothing you can do but pass a very large array (i.e. StringBuilder with a large Capacity) and keep your fingers crossed. Buffer overruns are the preferred attack vector for malware authors. Not likely to be abused in a managed program, it will just crash the app with FEEE.