OpenFileDlg-Beispiel
Dieses Beispiel demonstriert, wie eine nicht verwaltete Funktion aufgerufen wird, die einen Zeiger auf eine Struktur erwartet, die eine Zeichenfolge enthält. Darüber hinaus wird demonstriert, wie eine verwaltete Klasse zum Darstellen einer nicht verwalteten Struktur verwendet wird, wie das InAttribute-Attribut und das OutAttribute-Attribut zum Zurückmarshallen der Klasse an den Aufrufer angewendet wird und wie verschiedene Felder der Klasse zum Erzeugen der richtigen nicht verwalteten Darstellung deklariert und initialisiert werden.
Das OpenFileDlg-Beispiel verwendet die folgende nicht verwaltete Funktion, die zusammen mit ihrer ursprünglichen Funktionsdeklaration aufgeführt wird:
GetOpenFileName aus Comdlg32.dll exportiert.
BOOL GetOpenFileName(LPOPENFILENAME lpofn);
Die LPOPENFILENAME-Struktur aus der Win32-API, die an die vorherige Funktion übergeben wird, enthält die folgenden Elemente:
typedef struct tagOFN {
DWORD lStructSize;
//…
LPCTSTR lpstrFilter;
//…
LPTSTR lpstrFile;
DWORD nMaxFile;
LPTSTR lpstrFileTitle;
DWORD nMaxFileTitle;
LPCTSTR lpstrInitialDir;
LPCTSTR lpstrTitle;
//…
LPCTSTR lpstrDefExt;
//…
} OPENFILENAME, *LPOPENFILENAME;
In diesem Beispiel enthält die OpenFileName-Klasse die Elemente der Originalstruktur als Klassenelemente. Die nicht verwaltete Struktur wird nicht als verwaltete Struktur, sondern als Klasse deklariert, um zu zeigen, wie eine Klasse verwendet werden kann, wenn die nicht verwaltete Funktion einen Zeiger auf eine Struktur erwartet. Da eine nicht verwaltete Klasse ein Referenztyp ist, wird ein Zeiger auf die Klasse an den nicht verwalteten Code übergeben, wenn diese durch einen Wert übergeben wird. Genau das erwartet die nicht verwaltete Funktion.
Das StructLayoutAttribute-Attribut wird auf die Klasse angewendet, um sicherzustellen, dass die Member im Speicher sequenziell in der Reihenfolge ihres Auftretens angeordnet werden. Das CharSet-Feld wird so eingerichtet, dass Plattformaufruf zur Laufzeit basierend auf der Zielplattform zwischen den Formaten ANSI und Unicode wählen kann.
Die LibWrap-Klasse enthält den verwalteten Prototyp der GetOpenFileName-Methode, der die OpenFileName-Klasse als In/Out-Parameter übergibt. Indem InAttribute und OutAttribute explizit angewendet werden, stellt das Beispiel sicher, dass OpenFileName als In/Out-Parameter gemarshallt wird und der Aufrufer die zurückgemarshallten Änderungen sehen kann. (Aus Leistungsgründen ist das direktionale Attribut für eine Klasse In, sodass der Aufrufer die zurückgemarshallten Änderungen nicht sehen kann.) Die App-Klasse erstellt eine neue Instanz der OpenFileName-Klasse und verwendet die Marshal.SizeOf-Methode, um die Größe der nicht verwalteten Struktur in Bytes anzugeben.
Deklarieren von Prototypen
' 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);
};
Aufrufen von Funktionen
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);
}
}
};
Siehe auch
Konzepte
Datentypen für den Plattformaufruf
Standardmäßiges Marshalling für Zeichenfolgen
Weitere Ressourcen
Creating Prototypes in Managed Code