Win32-DLLs und Win32-API Funktionen in Windows Forms-Anwendungen

Veröffentlicht: Dezember 2009
Von Richard Kaiser und Alexander Kaiser

In einer C++ Windows Forms-Anwendung können auch Win32-DLLs verwendet werden. Das wird im Folgenden am Beispiel von Win32-API Funktionen gezeigt.

Dieser Artikel ist ein kurzer Auszug aus dem Buch „C++ mit Microsoft Visual C++ 2008“ (ISBN 978-3540238690), das C++ mitsamt den Visual C++-Erweiterungen (C++/CLI) umfassend darstellt. Der Verfasser dieses Buches ist ein erfahrener C++- und C#-Trainer, der auch für Firmenschulungen zur Verfügung steht.

Die Funktionen der Win32-API sind unter .NET normalerweise nicht notwendig, da für sie in der .NET Klassenbibliothek meist Klassen und Funktionen mit derselben Funk­tio­nalität zur Verfügung stehen, die einfacher sind und besser zu .NET passen. Wenn man Win32-Pro­gramme auf .NET portieren will, kann diese Gegenüberstellung von Win32 und .NET Funktionen hilfreich sein.

Da die Win32-Funktionen auch unter CLR-Anwendungen ver­fügbar sind, kann man Quelltexte mit solchen Funktionen auch in CLR-Projekten verwenden und so den Aufwand sparen, sie in die .NET-Klassenbibliothek zu portieren. Als Beispiel soll die Win32-API Funktion

int MessageBox(HWND hWnd,  LPCTSTR lpText,  LPCTSTR lpCaption,  UINT uType);

dienen, die wie Message­Box::Show ein Fenster mit einer Meldung anzeigt.

Für den Aufruf einer solchen Funktion in einer CLR-Anwendung gibt es im We­sentlichen zwei Möglichkeiten, die im Folgenden unter 1. und 2. beschrieben sind. Diese Möglichkeiten bestehen aber nicht nur für Funktionen der Win32-API, sondern für Funktionen aus beliebigen Win32-DLLs. Sie setzen voraus, dass man zuvor die InteropServices mit

using namespace System::Runtime::InteropServices;

verwendet (das ist für DLLImport notwendig).

1.   Falls die Parameter und Rückgabetypen der DLL-Funktion spezielle Namen verwenden, definiert man zuerst diese Namen (siehe dazu die Tabelle unten):

typedef void* HWND;

typedef wchar_t*  LPCTSTR;

typedef unsigned int  UINT;

Danach gibt man ein DLLImport-Attribut mit dem Namen der DLL (hier „user32“), dem Zeichensatz (oft CharSet::Auto) und dem Prototyp der Funktion an:

[DllImport("user32.dll", CharSet=CharSet::Auto)]

extern "C" int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,  UINT uType);

Stören Sie sich nicht an der vielleicht ungewohnten Syntax mit den eckigen Klammern. Das war’s nämlich schon: Die DLL-Funktion kann dann folgendermaßen aufgerufen werden:

void call_Win32Messagebox() 

{

const LPCTSTR pText = L"Hello World! ";

const LPCTSTR pCaption = L"Win32 MessageBox";

MessageBox(0, pText, pCaption, 0);

}

2.   Mit den Datentypen und Funktio­nen aus System::Runtime::InteropServices geht es sogar noch etwas einfacher. Damit kann man Funktionen aus Win32-DLLs auch mit Argumenten eines C++/CLI-Typs aufrufen und so die Definition der Datentypen unter 1. sparen. Dazu gibt man nach

using namespace System; // für String, IntPtr usw.

wieder das DLLImport-Attribut (wie unter 1.) an. Beim Prototyp der Funktion gibt man aber nicht die Win32-Datentypen an, sondern C++/CLI-Parametertypen, die den Datentypen aus der Win32-Deklara­tion entsprechen (siehe auch dazu die Tabelle unten):

[DllImport("user32", CharSet=CharSet::Auto)]

int MessageBox(IntPtr hWnd, String^ pText, 

  String ^ pCaption, unsigned int uType);

Dann kann man die Funktion der Win32-DLL mit Argumenten eines C++/CLI-Typs (z.B. String) aufrufen:

void call_Win32Messagebox() 

{

String^ pText = "Hello World! ";

String^ pCaption = "Win32 MessageBox";

MessageBox(IntPtr(0), pText, pCaption, 0);

}

Die unter 1. und 2. verwendeten Daten¬typen ergeben sich aus dieser Tabelle:

nicht verwaltete

Typen aus wtypes.h

Win32-Datentypen aus C C++/CLI-Datentyp
HANDLE, HWND void* System::IntPtr
BYTE unsigned char System::Byte
SHORT short System::Int16
WORD unsigned short System::UInt16
INT int System::Int32
UINT unsigned int System::UInt32
LONG, BOOL long System::Int32
DWORD, ULONG unsigned long System::UInt32
CHAR char  System::Char
LPSTR char* 

System::String oder

System::Text::StringBuilder

LPCSTR const char*

System::String oder

System::Text::StringBuilder

LPWSTR wchar_t*

System::String oder

System::Text::StringBuilder

LPCWSTR const wchar_t*

System::String oder

System::Text::StringBuilder

FLOAT float System::Single
DOUBLE double System::Double

 

Die Namen der ersten beiden Spalten sind auch nach #include <windows.h> verfügbar, aber das kann nicht aufgelöste externe Symbole beim Linken zur Folge haben.

Zurück: .NET-Klassen in C++ Windows Forms-Anwendungen