【问题标题】:How to P/Invoke "__arglist" function?如何 P/Invoke "__arglist" 函数?
【发布时间】:2015-11-17 11:51:40
【问题描述】:

背景:
我用 C++ 编写了以下函数:

extern "C" __declspec(dllexport) int test(const char*, ...);

我正在使用 P/Invoke 从 C# 中调用它:

[DllImport("foo/bar.dll", EntryPoint = "test")]
public static unsafe extern int __unmanaged__test(byte* buffer, __arglist);


问题:
我需要动态初始化__arglist,这意味着我有一个Array<object>,我必须在调用C++ 函数之前将其转换为__arglist

我尝试了以下方法,但它返回编译器错误:

unsafe {
    byte[] buffer = ....
    object[] args = ....

    // ....

    fixed (byte* ptr = buffer)
        return __unmanaged__test(ptr, __arglist(args)); // <--ERROR
}

有人知道解决这个问题的方法吗?


对于那些不知道什么的人 __arlist http://bartdesmet.net/blogs/bart/archive/2006/09/28/4473.aspx

【问题讨论】:

    标签: c# c++ pinvoke argument-passing


    【解决方案1】:

    您需要使用 C 风格的调用约定 - 其他(包括默认的 Stdecl)不支持可变参数:

    [DllImport("foo/bar.dll", EntryPoint = "test", 
               CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern int __unmanaged__test(byte* buffer, __arglist);
    

    另一个棘手的部分是__arglist(...) 是一个编译时特性——它只是为其每个“参数”生成一个(虚拟)堆栈推送。这意味着您不能将它与在编译时未知的参数一起使用 - 在您的示例代码中,您只是尝试创建一个参数,键入 object[]

    构建辅助反射方法并不难 - 请参阅 Calling varargs method via DynamicMethod 以获取示例。我无法对此进行测试,但我猜Expression 可用于轻松构建此代码 - 如果您不必通过byte*,那就是(您真的必须? 传递byte[] 也可以)。

    【讨论】:

    • 谢谢,但错误仍然存​​在。我认为它是数组和 __arglist 之间的转换
    • @Unknown6656 好吧,是的,你不能那样做。如果您需要动态构建__arglist(也就是说,您事先不知道参数的类型和数量),您可能必须使用反射。例如,请参阅stackoverflow.com/questions/29458616/…
    【解决方案2】:

    Luuan 写的评论 (see here) 有我需要的解决方案:

    引用

    如果您需要动态构建 __arglist(也就是说,您事先不知道参数的类型和数量),您可能必须使用反射。
    stackoverflow.com/questions/29458616/… 为例

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-17
      相关资源
      最近更新 更多