Partager via


OpenFileDlg, exemple

Cet exemple montre comment appeler une fonction non managée qui nécessite un pointeur vers une structure contenant une chaîne. De plus, il montre comment utiliser une classe managée pour représenter une structure non managée, comment appliquer les attributs InAttribute et OutAttribute pour remarshaler la classe vers l'appelant, et comment déclarer et initialiser différents champs de la classe pour produire la représentation non managée correcte.

L'exemple OpenFileDlg utilise la fonction non managée suivante, illustrée avec sa déclaration de fonction d'origine :

  • GetOpenFileName exportée à partir de Comdlg32.dll.

    BOOL GetOpenFileName(LPOPENFILENAME lpofn);
    

La structure LPOPENFILENAME de l'API Win32 qui est passée à la fonction précédente contient les éléments suivants :

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

Dans cet exemple, la classe OpenFileName contient les éléments de la structure d'origine en tant que membres de classe. La structure non managée est déclarée en tant que classe au lieu de l'être en tant que structure managée, afin de montrer comment une classe peut être utilisée lorsque la fonction non managée nécessite un pointeur vers une structure. Dans la mesure où une classe managée est un type référence, lorsque celle-ci est passée par valeur, un pointeur vers la classe est passé vers du code non managé. C'est précisément à quoi la fonction non managée s'attend.

L'attribut StructLayoutAttribute est appliqué à la classe afin de garantir que les membres sont disposés en mémoire de manière séquentielle, dans l'ordre de leur apparition. Le champ CharSet est défini de telle sorte que l'appel de code non managé peut choisir entre les formats Unicode et ANSI au moment de l'exécution, en fonction de la plateforme cible.

La classe LibWrap contient le prototype managé de la méthode GetOpenFileName qui passe la classe OpenFileName comme paramètre en entrée/sortie. En appliquant InAttribute et OutAttribute explicitement, l'exemple s'assure que OpenFileName est marshalé comme paramètre en entrée/sortie et que l'appelant peut voir les changements remarshalés. (Pour de meilleures performances, l'attribut directionnel par défaut pour une classe est In, ce qui empêche l'appelant de voir les changements remarshalés.) La classe App crée une nouvelle instance de la classe OpenFileName et utilise la méthode Marshal.SizeOf pour déterminer la taille, en octets, de la structure non managée.

Déclaration de prototypes

' Declare a class member for each structure element.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class OpenFileName
    Public structSize As Integer = 0
    Public hwnd As IntPtr = IntPtr.Zero
    Public hinst As IntPtr = IntPtr.Zero
    Public filter As String = Nothing
    Public custFilter As String = Nothing
    Public custFilterMax As Integer = 0
    Public filterIndex As Integer = 0
    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 flags As Integer = 0
    Public fileOffset As Short = 0
    Public fileExtMax As Short = 0
    Public defExt as String = Nothing
    Public custData As Integer = 0
    Public pHook As IntPtr = IntPtr.Zero
    Public template As String = Nothing
End Class

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
// Declare a class member for each structure element.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class OpenFileName
{
    public int       structSize = 0;
    public IntPtr    hwnd = IntPtr.Zero;
    public IntPtr    hinst = IntPtr.Zero;
    public string    filter = null;
    public string    custFilter = null;
    public int       custFilterMax = 0;
    public int       filterIndex = 0;
    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 int       flags = 0;
    public short     fileOffset = 0;
    public short     fileExtMax = 0;
    public string    defExt = null;
    public int       custData = 0;
    public IntPtr    pHook = IntPtr.Zero;
    public string    template = 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);
}
// Declare a class member for each structure element.
[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Auto)]
public ref class OpenFileName
{
public:
    int       structSize;
    IntPtr    hwnd;
    IntPtr    hinst;
    String^   filter;
    String^   custFilter;
    int       custFilterMax;
    int       filterIndex;
    String^   file;
    int       maxFile;
    String^   fileTitle;
    int       maxFileTitle;
    String^   initialDir;
    String^   title;
    int       flags;
    short     fileOffset;
    short     fileExtMax;
    String^   defExt;
    int       custData;
    IntPtr    pHook;
    String^   tmplate;

    OpenFileName()
    {
        // Initialize the fields.
        for each (FieldInfo^ fi in this->GetType()->GetFields())
        {
            fi->SetValue(this, nullptr);
        }
    }
};

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

Fonctions d'appel

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
End Class
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);
        }
    }
}
public ref class App
{
public:
    static void Main()
    {
        OpenFileName^ ofn = gcnew OpenFileName();

        ofn->structSize = Marshal::SizeOf(ofn);
        ofn->filter = "Log files\0*.log\0Batch files\0*.bat\0";
        ofn->file = gcnew String(gcnew array<Char>(256));
        ofn->maxFile = ofn->file->Length;
        ofn->fileTitle = gcnew String(gcnew array<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);
        }
    }
};

Voir aussi

Concepts

Marshaling de chaînes

Types de données d'appel de code non managé

Marshaling par défaut pour les chaînes

Autres ressources

Creating Prototypes in Managed Code