如何使用C ++ / CLI Wrapper将变量参数从托管传递到非托管?

要在托管域中实现params(可变参数)function,我们在c ++ / cli中执行以下操作,例如:

funcManaged(int n, ...array^ variableParams) 

我对如何将其传递给接受可变参数的非托管域感到茫然。

 funcUnmanaged(int n, ...) 

我试图传入数组,但结果很糟糕(访问冲突,垃圾数据等)。

 //where unmanagedVariableParamsArray is an int array funcUnmanaged(int n, unmanagedVariableParamsArray); 

资源建议创建一个va_list并传递它,

 vFuncUnmanaged(int n, va_list vl) 

但是如何在c ++ / cli域中创建va_list以接受variableParams ? 重构遗留的非托管代码库并不是一个理想的解决方案。

如果你真的非常绝望,那么这不是不可能的。 可变函数只能由C代码调用,并且调用必须由C编译器生成。 我们来举个例子:

 #include  #include  #pragma unmanaged void variadic(int n, ...) { va_list marker; va_start(marker, n); while (n--) { printf("%d\n", va_arg(marker, int)); } } 

编译器会像variadic(3, 1, 2, 3);那样调用一个样本调用variadic(3, 1, 2, 3); 成:

 00D31045 push 3 00D31047 push 2 00D31049 push 1 00D3104B push 3 00D3104D call variadic (0D31000h) 00D31052 add esp,10h 

注意参数是如何从堆栈传递到堆栈的,从左到右。 通话结束后,堆栈会被清理干净。 您可以使用内联汇编来模拟完全相同的调用模式。 看起来像这样:

 void variadicAdapter(int n, int* args) { // store stack pointer so we can restore it int espsave; _asm mov espsave,esp; // push arguments for (int ix = n-1; ix >= 0; --ix) { int value = args[ix]; _asm push value; } // make the call variadic(n); // fix stack pointer _asm mov esp,espsave; } 

非常直接,只是一些恶作剧,以恢复堆栈指针。 现在您有了一个可以从托管代码调用的适配器函数。 你需要一个pin_ptr <>来将数组转换为本机指针:

 #pragma managed using namespace System; int main(array ^args) { array^ arr = gcnew array(3) { 1, 2, 3}; pin_ptr arrp(&arr[0]); variadicAdapter(arr->Length, arrp); return 0; } 

在优化的版本构建中经过测试,效果很好,实际上并不危险。 请注意,如果需要64位代码,则无法使其工作。

一般建议是不建议: 参见本文

我建议使用std::vector来存储参数。