5

私はこれをc#から機能させようとしています:

C ヘッダー:

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

bool Init(uint32 version, LogFunc *log)

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

ここで起こることは、 への呼び出しがNativeMethods.InitコールバックLogMessageし、アンマネージ コードからのデータをパラメーターとして渡すことです。これは、引数が文字列であるほとんどの場合に機能します。ただし、次の形式の呼び出しがあります。

バージョン %d のプラグイン %s をロードしました。

args には文字列 (プラグイン名) のみが含まれます。string[]デリゲート宣言で使用したため、バージョン値は含まれていません。質問は、文字列と int の両方を取得するデリゲートをどのように記述すればよいですか?

使用してみobject[] argsましたが、この例外が発生しました: アンマネージ VARIANT からマネージ オブジェクトへの変換中に、無効な VARIANT が検出されました。無効な VARIANT を CLR に渡すと、予期しない例外、破損、またはデータの損失が発生する可能性があります。

編集:デリゲート署名を次のように変更できます:

internal delegate void LogFunc(string format, IntPtr args);

形式を解析して、予想される引数の数と型を調べることができました。たとえば、バージョン %d のロード済みプラグイン %s の場合。文字列とintが必要です。その IntPtr からこれら 2 を取得する方法はありますか?

4

4 に答える 4

5

それが誰かを助ける場合に備えて、ここに議論をマーシャリングするための解決策があります。デリゲートは次のように宣言されます。

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

これargsAddressは、アレイが開始するアンマネージメモリアドレスです(私は思います)。はformat配列のサイズを示します。これを知っていると、マネージアレイを作成して埋めることができます。疑似コード:

size <- get size from format
if size = 0 then return

array <- new IntPtr[size]
Marshal.Copy(argsAddress, array, 0, size);
args <- new string[size]

for i = 0 to size-1 do
   placeholder <- get the i-th placeholder from format // e.g. "%s"
   switch (placeholder)
       case "%s": args[i] <- Marshal.PtrToStringAnsi(array[i])
       case "%d": args[i] <- array[i].ToString() // i can't explain why the array contains the value, but it does
       default: throw exception("todo: handle {placeholder}")

実を言うと、これがどのように機能するのかわかりません。正しいデータを取得しているようです。しかし、私はそれが正しいとは主張していません。

于 2012-04-30T07:37:02.733 に答える
1

C# で利用可能な "__arglist" キーワードもあると理解しています。

于 2012-04-28T07:14:15.403 に答える
1

.NET は (ある程度) と の間va_listでマーシャリングできますArgIterator。これを試すことができます:

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

引数がどのように渡されるのかわかりません (文字列はおそらくポインターとして)。運がいいかもしれませんArgIterator.GetNextArgType。最終的には、フォーマット文字列のプレースホルダーを解析して引数の型を取得する必要があります。

于 2015-04-16T12:59:44.737 に答える