将数组作为ref/out传递时,调用System.ExecutionEngineException

smk*_*cmn 3 .net c# pinvoke dllimport

我在非托管DLL函数swe_calc_ut上使用P/invoke.

int swe_calc_ut(double tjd_et, int ipl, int iflag, double *xx, char *serr)
Run Code Online (Sandbox Code Playgroud)

参数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);
Run Code Online (Sandbox Code Playgroud)

现在当我执行函数swe_calc_ut函数时,我得到错误"抛出类型'System.ExecutionEngineException'的异常.".我是P/invoke的新手,所以我可能犯了一个愚蠢的错误.我认为它必须是数组,因为早些时候我偶然通过值传递它我没有得到错误.我非常感谢你的帮助.

lep*_*pie 6

你不必使用outref在这里.事实上,失去了他们两个.并在C#中将两个数组预分配到所需的大小.


Han*_*ant 5

它是C语言的约定,通过将指针传递给数组的第一个元素来传递数组.所以double []已被编组为double*.当你使用outref关键字时,你告诉marshaller该函数返回一个指向数组的指针,a double**.

该功能也不能创建一个新的阵列,它需要客户端传递数组这是大到足以接受的结果.因此,out和ref注释都不正确.应该将serr参数声明为StringBuilder btw.

该函数非常危险,因为客户端无法说出它创建的数组有多大.特别是serr论证的问题.详细的错误消息很容易超出数组的末尾,这将破坏垃圾收集堆.没有什么可以做但是传递一个非常大的数组(即具有大容量的StringBuilder)并保持手指交叉.缓冲区溢出是恶意软件作者的首选攻击媒介.它不太可能在托管程序中被滥用,它只会使应用程序与FEEE崩溃.