C# 委托中的元帅 va_list

Sui*_*den 5 c# c++ pinvoke marshalling

我正在尝试从 C# 开始这项工作:

C头:

typedef void (LogFunc) (const char *format, va_list args);

bool Init(uint32 version, LogFunc *log)
Run Code Online (Sandbox Code Playgroud)

C# 实现:

static class NativeMethods
{
    [DllImport("My.dll", SetLastError = true)]
    internal static extern bool Init(uint version, LogFunc log);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl, SetLastError = true)]
    internal delegate void LogFunc(string format, string[] args);
}

class Program
{
    public static void Main(string[] args)
    {
         NativeMethods.Init(5, LogMessage);
         Console.ReadLine();
    }

    private static void LogMessage(string format, string[] args)
    {
         Console.WriteLine("Format: {0}, args: {1}", format, DisplayArgs(args));
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生的是NativeMethods.Init调用回调LogMessage并将非托管代码中的数据作为参数传递。这适用于参数为字符串的大多数情况。但是,有一个调用的格式是:

已加载版本 %d 的插件 %s。

并且 args 仅包含一个字符串(插件名称)。它们不包含版本值,这是有道理的,因为我string[]在委托声明中使用过。问题是,我应该如何编写委托来获取字符串和整数?

我尝试使用object[] args并遇到此异常: 在从非托管 VARIANT 到托管对象的转换期间检测到无效的 VARIANT。将无效的 VARIANT 传递给 CLR 会导致意外异常、损坏或数据丢失。

编辑:我可以将委托签名更改为:

internal delegate void LogFunc(string format, IntPtr args);
Run Code Online (Sandbox Code Playgroud)

我可以解析格式并找出期望的参数数量和类型。例如,对于版本 %d 的已加载插件 %s。我希望有一个字符串和一个整数。有没有办法从 IntPtr 中获取这两个?

Sui*_*den 5

以防万一它对某人有帮助,这里有一个整理参数的解决方案。委托声明为:

[UnmanagedFunctionPointer(CallingConvention.Cdecl, SetLastError = true)] // Cdecl is a must
internal delegate void LogFunc(string format, IntPtr argsAddress);
Run Code Online (Sandbox Code Playgroud)

argsAddress是数组开始的非托管内存地址(我认为)。的format给出了该阵列的大小。知道了这一点,我可以创建托管数组并填充它。伪代码:

[UnmanagedFunctionPointer(CallingConvention.Cdecl, SetLastError = true)] // Cdecl is a must
internal delegate void LogFunc(string format, IntPtr argsAddress);
Run Code Online (Sandbox Code Playgroud)

说实话,我不确定这是如何工作的。它似乎只是获得了正确的数据。不过,我并没有声称它是正确的。


pau*_*sm4 1

据我所知,C# 中还有一个“__arglist”关键字:

  • 确实如此,但它不适用于代表。我尝试像这样使用它:`internal delegate void LogFunc(string format, __arglist);` (3认同)