我如何通过可变参数从托管到非托管与C ++ / CLI包装? [英] How do I pass variable arguments from managed to unmanaged with a C++/CLI Wrapper?

查看:146
本文介绍了我如何通过可变参数从托管到非托管与C ++ / CLI包装?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要实现一个PARAMS(可变参数)功能,在管理领域,我们做++ / CLI,如按照C:

To implement a params(variable arguments) functionality in the managed domain, we do the following in c++/cli such as:

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

我傻眼了如何把它传递给非托管域,它接受变量参数。

I'm dumbfounded on how to pass this to the unmanaged domain that takes in variable arguments.

funcUnmanaged(int n, ...)

我试图通过数组,但它结束了糟糕(访问冲突,垃圾数据,等等)。

I tried to pass the array in, but it ended up badly (access violations, junk data, etc).

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

资源提示创建一个va_list的,并通过周围,

Resources suggest to create a va_list and pass that around,

vFuncUnmanaged(int n, va_list vl)

但我怎么建立在C ++ / CLI域所使用的va_list采取在 variableParams ? 重构传统的非托管codeBase的是不是一个理想的解决方案。

But how do I create the va_list in the c++/cli domain to take in the variableParams? Refactoring the legacy unmanaged codebase is not a desirable solution.

推荐答案

如果你是真的,真的绝望了,那么这是不可能的。一个可变参数函数只能被C code被调用,调用必须由C编译器产生。让我们看一个例子:

If you are really, really desperate then this is not impossible. A variadic function can only be called by C code and the call has to be generated by the C compiler. Let's take an example:

#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));
    }
}

编译器将变成像示例调用可变参数(3,1,2,3);

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

请注意如何参数传递在栈中,由左到右。堆栈被调用后清理。您可以通过使用内联汇编效仿了完全相同的调用模式。这看起来是这样的:

Note how the arguments are passed on the stack, from left to right. The stack gets cleaned up after the call. You can emulate that exact same call pattern by using inline assembly. That looks like this:

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;
}

pretty的直线前进,只是一些有心计得到恢复堆栈指针。现在你有一个适配器的功能,你可以从管理code调用。你需要一个pin_ptr&LT;>把数组复制到一个本地指针:

Pretty straight forward, just some shenanigans to get the stack pointer restored. Now you have an adapter function that you can call from managed code. You'll need a pin_ptr<> to turn the array into a native pointer:

#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位code这项工作。

Works well and not actually that dangerous, tested in the optimized Release build. Beware that you have no hope of making this work if 64-bit code is required.

这篇关于我如何通过可变参数从托管到非托管与C ++ / CLI包装?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆