如何使用 C++/CLI Wrapper 将变量参数从托管传递到非托管?
Posted
技术标签:
【中文标题】如何使用 C++/CLI Wrapper 将变量参数从托管传递到非托管?【英文标题】:How do I pass variable arguments from managed to unmanaged with a C++/CLI Wrapper? 【发布时间】:2013-07-23 22:00:40 【问题描述】:要在托管域中实现参数(变量参数)功能,我们在 c++/cli 中执行以下操作,例如:
funcManaged(int n, ...array<int>^ 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? 重构遗留的非托管代码库并不是一个理想的解决方案。
【问题讨论】:
有没有可能只使用std::vector<int>
来存储变量参数?
我可以,但这需要对我想要避免的原始代码库进行更改。但看起来这是唯一的方法。我打算创建一个函数代理来接受使用变量 args 的遗留调用,将值转储到一个数组中并调用接受所述数组的新重构方法。
好计划。查看我的回复中有关处理变量参数的链接。
【参考方案1】:
如果你真的非常非常绝望,那么这并非不可能。可变参数函数只能由 C 代码调用,并且调用必须由 C 编译器生成。举个例子:
#include <stdarg.h>
#include <stdio.h>
#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);
之类的示例调用转换为:
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<System::String ^> ^args)
array<int>^ arr = gcnew array<int>(3) 1, 2, 3;
pin_ptr<int> arrp(&arr[0]);
variadicAdapter(arr->Length, arrp);
return 0;
运行良好,实际上并没有那么危险,在优化的发布版本中进行了测试。请注意,如果需要 64 位代码,您就没有希望完成这项工作。
【讨论】:
【参考方案2】:一般建议不推荐:See this article
我建议使用std::vector<int>
来存储参数。
【讨论】:
以上是关于如何使用 C++/CLI Wrapper 将变量参数从托管传递到非托管?的主要内容,如果未能解决你的问题,请参考以下文章
如何立即使用Vue CLI将多个Vue.js组件构建到本机Web组件?