可変引数をパラメータに持つC++の関数を、C#から利用する方法

printfなどの可変引数を持つ関数はそのまま呼び出すことができないため、想定される引数を持つ関数をそれぞれ明示的に定義する必要があります。
CallingConvention Enumeration (System.Runtime.InteropServices) - MSDN

サンプルコード

例えば、呼び出す対象の関数が次のように定義されているとすると、

int printf( const char *format [, argument]... )

C#のコードは次のようにします。

[DllImport( "msvcrt.dll", CallingConvention=CallingConvention.Cdecl )]
public static extern int printf( String format, int i, double d );
[DllImport( "msvcrt.dll", CallingConvention=CallingConvention.Cdecl )]
public static extern int printf( String format, int i, String s );

呼び出し規約

CallingConvention列挙体で、アンマネージド コードを呼び出すための呼び出し規約の指定をします。

CallingConvention 列挙体
メンバ 説明
Cdecl 呼び出し元がスタックを消去。可変引数のメソッドで使用する
StdCall 呼び出し先がスタックを消去。
ThisCall 最初の引数がthisポインタ。アンマネージドDLLからエクスポートしたクラスのメソッドを呼び出すために使用する。
Winapi プラットフォームに応じた、既定の呼び出し規約を使用する。
(WindowsではStdCall、Windows CE.NETではCdecl)
FastCall これはサポートされない。

__arglistキーワード

__arglistキーワードを使用して可変引数を実現する方法もあります。
可変個の引数にパラメータを使用します - MSDN

サンプルコード

[DllImport( "msvcrt", CallingConvention = CallingConvention.Cdecl )]
static extern int printf( string format, __arglist );

static void Main()
{
    printf( "%d",     __arglist( 123 ) );
    printf( "%d, %f", __arglist( 123, 456.78 ) );
    printf( "%d, %s", __arglist( 123, "abc" ) );
}
How do I call a C/C++ vararg function from .NET? - N/Direct - FAQ

va_list型

va_list型の引数が書式制御のパラメータならば、vsprintf関数を使用してstring型に変換できます。

[DllImport( "msvcrt" )]
static extern int vsprintf( byte[] str, string format, IntPtr args );

/// <param name="format">const char*型の書式制御文字列</param>
/// <param name="args">va_list型の可変引数リストへのポインタ</param>
static void Foo( string format, IntPtr args )
{
    byte[] str = new byte[ 0xFF ];
    int count = vsprintf( str, format, args );

    Console.Write( System.Text.Encoding.ASCII.GetString( str, 0, count ) );
}