2011-07-14 1 views
9

私は管理対象/非管理対象の相互運用をしようとしていました。この定義作品はC#P/Invoke:Varargsデリゲートコールバック


[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
public unsafe delegate void LogCallback(void* arg1,int level,byte* fmt); 

、しかし、私は、「サイズ=%dとスコアは=%dの形式%sの探査」のような文字列を取得します:拡張エラー情報を取得するには、私は、DLLによって提供されるログのコールバックを登録することを決めました。 __arglistキーワードを追加しようとしましたが、代理人には許可されていません。

まあ、それほど劇的ではありませんが、私はC#でvarargsパラメータを得ることができたのは不思議です。 私はinteropにC++を使用できることを知っています。 So:これを純粋にC#で、合理的なeffordで行う方法はありますか?

EDIT:私は可変引数機能をインポートするが、その後、私のネイティブコードと呼ばれるコールバック、としてそれを輸出しておりません。まだそれを取得していない人のために。一度に1つしか指定できません - > 1つのオーバーロードしかできず、__arglistは機能しません。

+1

[This(http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/301588-how-hooking-functions-wow- variable-arguments-c.html)が役に立つかもしれません。 – IllidanS4

答えて

4

なしにそれを行うには可能な方法はありません。その理由は、可変引数リストがC言語で動作する方法のためです。

Cでは、可変引数はスタック(この場合は管理されていないスタック)に追加パラメータとしてプッシュされます。 Cはスタック上のパラメータの数を記録しません。呼び出される関数は最後の仮パラメータ(varargsの前の最後の引数)を取得し、スタックから引数をポップすることを開始します。

スタックをポップアウトする変数の数は完全に規約に基づいています。他のパラメータは、可変引数の数がスタック上にあることを示します。 printfの場合は、書式文字列を解析し、書式コードが見つかるたびにスタックをポップすることによって行います。あなたのコールバックが似ているようです。

これを処理するCLRにとって、ピックアップに必要な引数の数を判断するための正しい規則を知る必要があります。アクセス権のないアンマネージスタックへのアクセスが必要になるため、独自のハンドラを記述することはできません。 C#からこれを行う方法はありません。

この詳細については、Cの呼び出し規約をお読みください。

0

次の記事では、わずかに異なるシナリオをカバーしていないし、役に立つことがあります。

How to P/Invoke VarArgs (variable arguments) in C#

+0

これには2つの問題があります: 1.)関数ポインタ/コールバックをDllImport経由でインポートするのではなく、すでにtryedしています。__arglist:デリゲートでは機能しません! )私は一度に1つのコールバックしか登録することができないので、すべての可能性のオーバーライドが機能しません。 – Zotta

+0

@Floste申し訳ありませんが、私はそれが思われる質問を読んでいます。 – Justin

+0

これはちょうど私の質問の誰かが答えることができる^^のように見える^^ – Zotta

0

これを可能にするには、P/invoke Marshallerのサポートが必要です。マーシャラーはそのようなサポートを提供しません。したがって、それはできません。

1

Marshal va_list in C# delegateを転記する前にこの質問に遭遇しました。私はそれが似ていると思うし、私のために働く実装を見つけました。 HTH。

1

は、実際にはCILで可能である:ここでは

.class public auto ansi sealed MSIL.TestDelegate 
     extends [mscorlib]System.MulticastDelegate 
{ 
    .method public hidebysig specialname rtspecialname 
      instance void .ctor(object 'object', 
           native int 'method') runtime managed 
    { 
    } 
    .method public hidebysig newslot virtual 
      instance vararg void Invoke() runtime managed 
    { 
    } 
} 
2

はそれに対処する方法です。コールバック引数がprintfファミリのファンクションファミリで使用されるかどうかによって、ケースに該当する場合とそうでない場合があります。

まず、msvcrtから輸入vsprintf_vscprintf

[DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] 
public static extern int vsprintf(
    StringBuilder buffer, 
    string format, 
    IntPtr args); 

[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int _vscprintf(
    string format, 
     IntPtr ptr); 

次に、IntPtr引数のポインタを使用してデリゲートを宣言します。デリゲートはネイティブコードを経由して呼び出されたときに、今

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
public unsafe delegate void LogCallback(
    void* arg1, 
    int level, 
    [In][MarshalAs(UnmanagedType.LPStr)] string fmt, 
    IntPtr args); 

、単にvsprintfを使用メッセージを正しくフォーマットする:

private void LogCallback(void* data, int level, string fmt, IntPtr args) 
{ 
    var sb = new StringBuilder(_vscprintf(fmt, args) + 1); 
    vsprintf(sb, fmt, args); 

    //here formattedMessage has the value your are looking for 
    var formattedMessage = sb.ToString(); 

    ... 
} 
+0

すごい!どのようにあなたがそれを理解したか分かりませんが、それは動作します! – Eternal21

+0

ありがとう、本当に私はトラックに乗るのを手伝った!しかし、私はそれをクロスプラットフォームにする方法が必要でした...だから私はそれを自分でやった!ここに私の仕事は、貢献すること自由に感じる:https://github.com/jeremyVignelles/va-list-interop-demo。 – cube45

関連する問題