C#とC++の相互運用のための属性の設定方法

C#からC++のコードにアクセスするためには、カスタム属性を使用して関数や構造体の挙動を調整する必要があります。

DllImport属性

DLLエントリポイントを定義する外部関数を示すことで、DLLの関数を呼び出せるようになります。

[ DllImport( "dllName" ) ]
DllImportAttribute(String) コンストラクター (System.Runtime.InteropServices) | Microsoft Learn
属性パラメータ
パラメータ名 説明 既定値
EntryPoint DLL内の関数の名前または序数 (ordinal)。序数は#に続けて記述  
CharSet 文字列のマーシャリング方法を示すCharSet列挙型 CharSet.Auto
SetLastError Win32エラー情報を維持するか? false
ExactSpelling EntryPointの関数名を厳密に一致させるか? false
PreserveSig 定義通りのメソッドのシグネチャを維持するか※1

trueならばHRESULTの値がそのまま返される。falseならばS_OKではないときに例外が投げられる

true
CallingConvention EntryPointで使用するモードを指定するCallingConvention列挙型 StdCall
フィールド - DllImportAttribute クラス (System.Runtime.InteropServices) | Microsoft Learn

※1 PreserveSigをfalseとしたときにシグネチャが一致しないと「'PInvoke 関数 '***' がスタックを不安定にしています。PInvoke シグネチャがアンマネージ ターゲット シグネチャに一致していないことが原因として考えられます。呼び出し規約、および PInvoke シグネチャのパラメーターがターゲットのアンマネージ シグネチャに一致していることを確認してください。'」として、MDAのPInvokeStackImbalanceが検出されます。

実行時に指定のDLLを読み込めないと、モジュールが見つからないとしてFileNotFoundExceptionやDllNotFoundExceptionが投げられます。

呼び出し規約 (calling convention)

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

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

サンプルコード

[DllImport( "sample.dll" )]
public static void MethodName( int x );

EntryPointで関数の名前を指定すれば、別の名前を与えられます。

[DllImport( "sample.dll", EntryPoint = "MethodName" )]
public static void NewMethodName( int x );

StructLayout属性

クラスまたは構造体のデータメンバを、メモリ内でどのように配置するかを表せます。

[ StructLayout( layoutKind ) ]
StructLayoutAttribute(LayoutKind) - StructLayoutAttribute コンストラクター (System.Runtime.InteropServices) | Microsoft Learn
LayoutKind列挙型
列挙子 説明
Sequential 宣言される順番に従って並べる
Explicit FieldOffsetAttributeで独自のオフセットを指定して並べる
Auto 適切なレイアウトで並べる
(マネージド コードの外からアクセスできない)
属性パラメータ
パラメータ名 説明 既定値
Pack

パックサイズを指定するint値

指定可能な値は[ 1, 2, 4, 8, 16]のいずれか

8
CharSet 文字列のマーシャリング方法を示すCharSet列挙型 CharSet.Auto
Size 構造体またはクラスのサイズを指定  
フィールド - StructLayoutAttribute クラス (System.Runtime.InteropServices) | Microsoft Learn

サンプルコード

[StructLayout( LayoutKind.Sequential )]
public struct Position
{
    public double x;
    public double y;
    public double z;
}

CLSCompliant属性

CLSへの準拠を検証するかどうかをコンパイラに指示します。外部から参照できない型やメンバに、この属性を指定する必要はありません。指定すると「このアセンブリの外から認識できないため、CLS準拠の確認は '型' で実行されません」と警告が表示されます。

アセンブリ全体が準拠していることを示すならば、AssemblyInfo.csに

[assembly: CLSCompliant(true)]

を追記します。CA1014: アセンブリに CLSCompliantAttribute を設定します | MSDN

サンプルコード

[CLSCompliant( false )]
public int SetValue( UInt32 value );
※この場合UInt32型はCLSに準拠しないため、CLSCompliant(false)と指定する必要があります。

SuppressUnmanagedCodeSecurity属性

マネージド コードからアンマネージド コードを、スタックウォーク (stack walk) なしで呼べるようにします。これにより実行時のセキュリティ チェックが省かれますが、効率は大幅に向上します。SuppressUnmanagedCodeSecurityAttribute クラス | MSDN

クラスに指定した場合は、そこに含まれるすべてのメソッドに適用されます。

MarshalAs属性

マネージド コードとアンマネージド コードで、データをマーシャリングする方法を指定できます。

public MarshalAsAttribute (
    System.Runtime.InteropServices.UnmanagedType unmanagedType
    );
MarshalAsAttribute(UnmanagedType) - MarshalAsAttribute コンストラクター (System.Runtime.InteropServices) | Microsoft Learn
// パラメータへの適用
public void M1(
    [MarshalAs(UnmanagedType.LPWStr)] string msg)
{
}

// クラスのフィールドへの適用
class MsgText
{
    [MarshalAs(UnmanagedType.LPWStr)]
    public string msg = "Hello World";
}

// 戻り値への適用
[return: MarshalAs(UnmanagedType.LPWStr)]
public string GetMessage()
{
    return "Hello World";
}

この属性は、その型が複数の型にマーシャリングできる場合にのみ必要です。たとえばstringは既定でBStrとしてマーシャリングされますが、これをLPStr、LPWStrやLPTStrとするときに指定します。Remarks - MarshalAsAttribute Class (System.Runtime.InteropServices) | Microsoft Learn

boolは4バイトのWin32 BOOLか、1バイトのC++ boolである可能性があるため、いずれであるかをMarshalAs(UnmanagedType.Bool)かMarshalAs(UnmanagedType.U1)で指定します。これを指定しないと、コード分析で「ブール型の P/Invoke 引数を MarshalAs に設定します」としてCA1414で警告されます。

In属性 / Out属性

データの渡し方を指示します。

属性 説明
In属性 呼び出し先 (callee) にデータをマーシャリングして渡すことを示す
InAttribute Class (System.Runtime.InteropServices) | Microsoft Learn
Out属性 呼び出し元 (caller) にデータをマーシャリングして戻すことを示す
OutAttribute Class (System.Runtime.InteropServices) | Microsoft Learn
void Method([In] int[] array);

InやOutのように記述されますが、実際はInAttributeとOutAttributeクラスであり、inやoutのパラメータ修飾子ジェネリック修飾子とは異なります。

C++のSAL注釈

Microsoft Learnから検索