マネージド コードでのプロトタイプの作成

このトピックは、アンマネージド 関数にアクセスする方法について説明し、マネージド コードでメソッドの定義の注釈を設定するいくつかの属性フィールドを紹介しています。 プラットフォーム呼び出しで使用する .NET ベースの宣言を作成する方法を示す例については、「プラットフォーム呼び出しによるデータのマーシャリング」を参照してください。

マネージド コードからアンマネージド DLL 関数にアクセスする前に、関数の名前とエクスポートする DLL の名前を知っている必要があります。 この情報を使用すると、マネージド DLL に実装されているアンマネージド 関数の定義の作成を開始できます。 さらに、プラットフォーム呼び出しが関数を作成し、関数間でデータをマーシャリングする方法を調整できます。

注意

文字列を割り当てる Windows API 関数を使用して、LocalFree などのメソッドを使用して文字列を解放できます。 プラットフォーム呼び出しは、このようなパラメーターを異なる方法で処理します。 プラットフォーム呼び出しでは、パラメーターを String 型の代わりに IntPtr 型にします。 System.Runtime.InteropServices.Marshal クラスにより提供されるメソッドを使用して、型を手動で文字列に変換し、手動で解放します。

宣言の基本

アンマネージド 関数に対するマネージド定義は、次の例で確認できるように、言語に依存します。 完全なコード例については、「プラットフォーム呼び出しの例」を参照してください。

Friend Class NativeMethods
    Friend Declare Auto Function MessageBox Lib "user32.dll" (
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
End Class

DllImportAttribute.BestFitMappingDllImportAttribute.CallingConventionDllImportAttribute.ExactSpellingDllImportAttribute.PreserveSigDllImportAttribute.SetLastError、または DllImportAttribute.ThrowOnUnmappableChar の各フィールドを Visual Basic の宣言に適用するには、Declare ステートメントではなく DllImportAttribute 属性を使用する必要があります。

Imports System.Runtime.InteropServices

Friend Class NativeMethods
    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Friend Shared Function MessageBox(
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
    End Function
End Class
using System;
using System.Runtime.InteropServices;

internal static class NativeMethods
{
    [DllImport("user32.dll")]
    internal static extern int MessageBox(
        IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
using namespace System;
using namespace System::Runtime::InteropServices;

[DllImport("user32.dll")]
extern "C" int MessageBox(
    IntPtr hWnd, String* lpText, String* lpCaption, unsigned int uType);

定義の調整

明示的に設定するかどうかに関係なく、属性フィールドは作業はマネージド コードの動作を動作中に定義します。 プラットフォーム呼び出しは、アセンブリ内のメタデータとして存在するさまざまなフィールドで設定された既定値どおりに動作します。 1 つまたは複数のフィールドの値を調整することによって、この既定の動作を変更することができます。 多くの場合、DllImportAttribute を使用して値を設定します。

次の表では、プラットフォーム呼び出しに関連する属性フィールドの完全なセットを一覧表示します。 各フィールドについては、表に既定値とこれらのフィールドを使用してアンマネージ DLL 関数を定義する方法に関する情報へのリンクが含まれます。

フィールド 説明
BestFitMapping 最適なマッピングを有効または無効にします。
CallingConvention メソッドの引数を渡すときに使用する呼び出し規則を指定します。 既定値は WinAPI で、32 ビットの Intel ベース プラットフォームの __stdcall に対応します。
CharSet 名前修飾および文字列の引数を関数にマーシャリングする方法を管理します。 既定値は、CharSet.Ansi です。
EntryPoint 呼び出される DLL エントリ ポイントを指定します。
ExactSpelling 文字セットに対応するエントリ ポイントを変更する必要があるかどうかを制御します。 既定値は、プログラミング言語によって異なります。
PreserveSig マネージド メソッドのシグネチャが、HRESULT を返すアンマネージド シグネチャに変換され、戻り値の追加の [out, retval] 引数を持つかどうかを制御します。

既定値は true です (シグネチャは変換されません)。
SetLastError 呼び出し元が Marshal.GetLastWin32Error API の関数を使用して、メソッドの実行中にエラーが発生したかどうかを判断できるようにします。 Visual Basic では既定値は true、C# および C++ では既定値は false です。
ThrowOnUnmappableChar ANSI の"?" 文字に変換されるマップできない Unicode 文字での例外のスローを制御します。

詳細なリファレンス情報については、「DllImportAttribute」を参照してください。

プラットフォーム呼び出しのセキュリティに関する考慮事項

SecurityAction 列挙型の AssertDeny、および PermitOnly のメンバーは、スタック ウォーク修飾子 と呼ばれます。 プラットフォーム呼び出しの宣言および COM インターフェイス定義言語 (IDL) ステートメントの宣言属性として使用される場合、これらのメンバーは無視されます。

プラットフォーム呼び出しの例

このセクションのプラットフォーム呼び出しのサンプルは、RegistryPermission スタック ウォーク修飾子を持つ属性の使用方法を示します。

次のコード例では、SecurityActionAssertDeny、および PermitOnly 修飾子は無視されます。

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionAssert();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

ただし、次の例の Demand 修飾子は受け入れられます。

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

プラットフォーム呼び出しを含む (ラップする) クラスに配置されている場合、SecurityAction 修飾子は正常に機能します。

      [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
public ref class PInvokeWrapper  
{  
public:  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
};  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
class PInvokeWrapper  
{  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
}  

SecurityAction 修飾子は、プラットフォーム呼び出しの呼び出し元に配置されたネストしたシナリオでも正しく動作します。

      {  
public ref class PInvokeWrapper  
public:  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
  
    [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
};  
class PInvokeScenario  
{  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionInternal();  
  
    [RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
}  

COM 相互運用機能の例

このセクションの次の COM 相互運用機能の例は、スタック ウォーク修飾子を持つ RegistryPermission 属性の使用方法を示します。

次の COM 相互運用機能のインターフェイスの宣言は、前のセクションのプラットフォーム呼び出しの例と同様に、AssertDeny、および PermitOnly の修飾子を無視します。

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDenyStubsItf  
{  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

さらに、次の例に示すように、Demand 修飾子は COM 相互運用機能のインターフェイスの宣言のシナリオでは許可されません。

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDemandStubsItf  
{  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

関連項目