如何使用C ++ / CLI Wrapper将可变参数从托管传递到非托管? [英] How do I pass variable arguments from managed to unmanaged with a C++/CLI Wrapper?

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

问题描述

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

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
重构旧的非托管代码库不是一个理想的解决方案。

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代码调用,调用必须由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));
    }
}

编译器会调用 variadic(3,1,2,3); into:

The compiler will turn a sample call like variadic(3, 1, 2, 3); into:

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

很简单,只是一些shenanigans得到堆栈指针恢复。现在您有一个适配器功能,您可以从托管代码调用。您需要一个pin_ptr<>将数组转换为本地指针:

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位代码,您没有希望进行此工作。

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 Wrapper将可变参数从托管传递到非托管?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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