C#からC++のコードにアクセスするためには、カスタム属性を使用して関数や構造体の挙動を調整する必要があります。
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 |
※1 PreserveSigをfalseとしたときにシグネチャが一致しないと「'PInvoke 関数 '***' がスタックを不安定にしています。PInvoke シグネチャがアンマネージ ターゲット シグネチャに一致していないことが原因として考えられます。呼び出し規約、および PInvoke シグネチャのパラメーターがターゲットのアンマネージ シグネチャに一致していることを確認してください。'」として、MDAのPInvokeStackImbalanceが検出されます。
実行時に指定のDLLを読み込めないと、モジュールが見つからないとしてFileNotFoundExceptionやDllNotFoundExceptionが投げられます。
CallingConvention列挙型で、アンマネージド コードを呼び出すための呼び出し規約の指定をします。
列挙子 | 説明 |
---|---|
Cdecl | 呼び出し元が、スタックを消去。これはPrintfなどの可変引数のメソッドの呼び出しで使用する |
StdCall | 呼び出し先が、スタックを消去。アンマネージド関数を呼び出す既定値 |
ThisCall | 最初の引数がthisポインタ。アンマネージドDLLからエクスポートしたクラスのメソッドを呼び出すために使用する |
Winapi | プラットフォームに応じた、既定の呼び出し規約を使用する (WindowsではStdCall、Windows CE.NETではCdecl) |
FastCall | サポートされない |
[DllImport( "sample.dll" )] public static void MethodName( int x );
EntryPointで関数の名前を指定すれば、別の名前を与えられます。
[DllImport( "sample.dll", EntryPoint = "MethodName" )] public static void NewMethodName( int x );
クラスまたは構造体のデータメンバを、メモリ内でどのように配置するかを表せます。
[ StructLayout( layoutKind ) ]StructLayoutAttribute(LayoutKind) - StructLayoutAttribute コンストラクター (System.Runtime.InteropServices) | Microsoft Learn
列挙子 | 説明 |
---|---|
Sequential | 宣言される順番に従って並べる |
Explicit | FieldOffsetAttributeで独自のオフセットを指定して並べる |
Auto | 適切なレイアウトで並べる (マネージド コードの外からアクセスできない) |
パラメータ名 | 説明 | 既定値 |
---|---|---|
Pack |
パックサイズを指定するint値 指定可能な値は[ 1, 2, 4, 8, 16]のいずれか |
8 |
CharSet | 文字列のマーシャリング方法を示すCharSet列挙型 | CharSet.Auto |
Size | 構造体またはクラスのサイズを指定 |
[StructLayout( LayoutKind.Sequential )] public struct Position { public double x; public double y; public double z; }
CLSへの準拠を検証するかどうかをコンパイラに指示します。外部から参照できない型やメンバに、この属性を指定する必要はありません。指定すると「このアセンブリの外から認識できないため、CLS準拠の確認は '型' で実行されません」と警告が表示されます。
アセンブリ全体が準拠していることを示すならば、AssemblyInfo.csに
[assembly: CLSCompliant(true)]
を追記します。CA1014: アセンブリに CLSCompliantAttribute を設定します | MSDN
[CLSCompliant( false )] public int SetValue( UInt32 value );※この場合UInt32型はCLSに準拠しないため、
CLSCompliant(false)
と指定する必要があります。
マネージド コードからアンマネージド コードを、スタックウォーク (stack walk) なしで呼べるようにします。これにより実行時のセキュリティ チェックが省かれますが、効率は大幅に向上します。SuppressUnmanagedCodeSecurityAttribute クラス | MSDN
クラスに指定した場合は、そこに含まれるすべてのメソッドに適用されます。
マネージド コードとアンマネージド コードで、データをマーシャリングする方法を指定できます。
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属性 | 呼び出し先 (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のパラメータ修飾子やジェネリック修飾子とは異なります。