OpenFileDlg のサンプル

このサンプルでは、文字列を含む構造体へのポインタを要求する、アンマネージ関数を呼び出す方法について説明します。さらに、マネージ クラスを使用してアンマネージ構造体を表す方法、InAttribute 属性と OutAttribute 属性を適用してクラスを呼び出し元へとマーシャリングする方法、クラスの各種フィールドを宣言および初期化して正確なアンマネージ表現を生成する方法について説明します。

OpenFileDlg のサンプルで使用するアンマネージ関数とその関数宣言を次に示します。

  • Comdlg32.dll からエクスポートされる GetOpenFileName

    BOOL GetOpenFileName(LPOPENFILENAME lpofn);
    

前記の関数に渡される Win32 API の LPOPENFILENAME 構造体には、次の要素があります。

typedef struct tagOFN { 
  DWORD         lStructSize; 
  //…
  LPCTSTR       lpstrFilter; 
  //…
  LPTSTR        lpstrFile; 
  DWORD         nMaxFile; 
  LPTSTR        lpstrFileTitle; 
  DWORD         nMaxFileTitle; 
  LPCTSTR       lpstrInitialDir; 
  LPCTSTR       lpstrTitle; 
  //… 
  LPCTSTR       lpstrDefExt; 
  //…
} OPENFILENAME, *LPOPENFILENAME; 

このサンプルでは、OpenFileName クラスの中には、クラス メンバとして、元の構造体の要素が含まれます。アンマネージ構造体は、アンマネージ関数が構造体へのポインタを要求する場合にどのようにクラスを使用できるかを示すために、マネージ構造体ではなくクラスとして宣言されます。マネージ クラスは参照型なので、マネージ クラスを値渡しする場合には、そのクラスへのポインタがアンマネージ コードに渡されます。アンマネージ関数が要求しているのは、このポインタです。

各メンバが出現する順番でメモリ内に順次配置されることを保証するために、クラスに StructLayoutAttribute 属性を適用します。対象プラットフォームに従って、プラットフォーム呼び出しが実行時に ANSI 形式と Unicode 形式のどちらかを選択できるように、CharSet フィールドを設定します。

LibWrap クラスには GetOpenFileName メソッドのマネージ プロトタイプが含まれます。このメソッドは OpenFileName クラスを In/Out パラメータとして渡します。InAttributeOutAttribute を明示的に適用すると、このサンプルでは、OpenFileName が In/Out パラメータとしてマーシャリングされ、マーシャリングされた変更内容を呼び出し元が確実に参照できるようになります。パフォーマンスのためにクラスに関する既定の方向属性は In となります。このため、呼び出し元はマーシャリングされた変更内容を参照できません。App クラスは OpenFileName クラスの新しいインスタンスを作成し、Marshal.SizeOf メソッドを使用してアンマネージ構造体のサイズをバイト単位で決定します。

次のコード例のソース コードは、.NET Framework「プラットフォーム呼び出しの技術サンプル」で提供されています。

プロトタイプの宣言

' Declare a class member for each structure element.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Auto )> _
Public Class OpenFileName

   Public structSize As Integer = 0
   '…
   Public filter As String = Nothing
   '…
   Public file As String = Nothing
   Public maxFile As Integer = 0
   Public fileTitle As String = Nothing
   Public maxFileTitle As Integer = 0
   Public initialDir As String = Nothing
   Public title As String = Nothing
   '…
   Public defExt As String = Nothing
   '…
End Class 'OpenFileName

Public Class LibWrap
   ' Declare managed prototype for the unmanaged function.
   Declare Auto Function GetOpenFileName Lib "Comdlg32.dll" ( _
      <[In], Out> ByVal ofn As OpenFileName ) As Boolean
End Class 'LibWrap
// Declare a class member for each structure element.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Auto )]  
public class OpenFileName 
{
    public int       structSize = 0;
    //…
    public String    filter = null;
    //…
    public String    file = null;
    public int       maxFile = 0;
    public String    fileTitle = null;
    public int       maxFileTitle = 0;
    public String    initialDir = null;
    public String    title = null;   
    //…
    public String    defExt = null; 
    //…
}

public class LibWrap
{
   // Declare a managed prototype for the unmanaged function.
   [ DllImport( "Comdlg32.dll", CharSet=CharSet.Auto )]
   public static extern bool GetOpenFileName([ In, Out ] 
OpenFileName ofn );  
}

関数の呼び出し

Public Class App
   Public Shared Sub Main()
   
      Dim ofn As New OpenFileName()
      ofn.structSize = Marshal.SizeOf( ofn )
      ofn.filter = "Log files" & ChrW(0) & "*.log" & ChrW(0) & _
         "Batch files" & ChrW(0) & "*.bat" & ChrW(0)
      ofn.file = New String( New Char( 256 ) {})
      ofn.maxFile = ofn.file.Length
      ofn.fileTitle = New String( New Char( 64 ) {})
      ofn.maxFileTitle = ofn.fileTitle.Length
      ofn.initialDir = "C:\"
      ofn.title = "Open file called using platform invoke..."
      ofn.defExt = "txt"
      
      If LibWrap.GetOpenFileName( ofn ) Then
         Console.WriteLine( "Selected file with full path: {0}", _
         ofn.file )
      End If
   End Sub 'Main
End Class 'OpenFileDlgSample
public class App
{
   public static void Main()
   {
      OpenFileName ofn = new OpenFileName();
      ofn.structSize = Marshal.SizeOf( ofn );
      ofn.filter = "Log files\0*.log\0Batch files\0*.bat\0";
      ofn.file = new String( new char[ 256 ]);
      ofn.maxFile = ofn.file.Length;
      ofn.fileTitle = new String( new char[ 64 ]);
      ofn.maxFileTitle = ofn.fileTitle.Length;
      ofn.initialDir = "C:\\";
      ofn.title = "Open file called using platform invoke...";
      ofn.defExt = "txt";
      
      if( LibWrap.GetOpenFileName( ofn ))
      {
         Console.WriteLine( "Selected file with full path: {0}", 
            ofn.file );
      }
   }
}

参照

処理手順

プラットフォーム呼び出しの技術サンプル

概念

文字列のマーシャリング
プラットフォーム呼び出しのデータ型
文字列に対する既定のマーシャリング
マネージ コードでのプロトタイプの作成