Erstellungsdatum: 2013 Jun 15 - Links zuletzt geprüft: 2017 Mai 10 (alle okay)

Wichtige Windows Typen für C/C++-Programmierer

Diese Typen sind vor allem dann wichtig, wenn Sie direkt mit der Windows API programmieren (mit Message Loop und so). Sollten Sie Klassenbibliotheken wie MFC, WPF oder .NET verwenden, benötigen Sie das wahrscheinlich nicht.

CALLBACK, WPARAM, LPARAM, LRESULT, FAR, PASCAL, ...

Bei den ganzen Typen von Windows blickt man irgend wann nicht mehr durch. Insbesondere wenn man auch noch (z. B. wegen Portierung) 16-Bit-Windows Programme berücksichtigen muss. Man findet zwar alles über Google, aber es ist aufwendig. Daher habe ich mal die wichtigsten auf einer Seite zusammengefasst. Eine gute Übersicht über die Windows-Datentypen findet man auf:
msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx

Leider stimmt das nur, wenn nicht STRICT definiert ist (was anscheinend mittlerweile der Normalfall ist). Bei STRICT werden z. B. Handles (mit Ausnahme des Basistyps für Handles [HANDLE]) anders definiert, so dass der Compiler unterschiedliche Handles erkennen kann, siehe unten die Definition von HWND


CALLBACK

#define  CALLBACK  __stdcall
// WINAPI und APIENTRY sind Synonyme für CALLBACK:
#define  WINAPI  __stdcall
#define  APIENTRY  WINAPI
msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx


__stdcall

Die  __stdcall-Aufrufkovention wird benutzt um Win32 API Funktionen aufzurufen (vermutlich auch Win64). Die aufgerufene Funktion räumt den Stack auf (ist in C/C++ normalerweise genau anders herum).
msdn.microsoft.com/en-us/library/zxk0tw93(v=vs.71).aspx


WPARAM, LPARAM, LRESULT:
typedef  UINT_PTR  WPARAM;
typedef  LONG_PTR  LPARAM;
typedef  LONG_PTR  LRESULT;


UINT_PTR:

#if  defined(_WIN64)
    typedef  unsigned  __int64  UINT_PTR;
#else
    typedef  unsigned  int  UINT_PTR;
#endif


__int64 (__int8, __int16, __int32):

Unterstützung von Funktionen für C/C++ Microsoft sortierte ganzzahlige Typen. Sie können 8, 16 -, 32 - oder 64-Bit-Ganzzahl-Variablen deklarieren, indem Sie den Typspezifizierer __intn verwenden, wobei n 8, 16, 32 oder 64 ist. Für Portabilität, z. B. wäre ein int 16, 32 oder 64 Bit auf einem 16 Bit, 32 Bit oder 64 Bit-Windows mit __intN kann man sicher stellen, dass sie auf allen Systemen die angegebene Größe haben.
http://msdn.microsoft.com/de-de/library/vstudio/29dh1w7z.aspx dieser Link funktioniert leider nicht mehr. Versuchen Sie diesen:
https://msdn.microsoft.com/de-de/library/29dh1w7z.aspx


LONG_PTR:

typedef  __int3264  LONG_PTR;


__int3264

Spezifiziert einen Typ mit folgenden Eigenschaften (laut Microsoft):
It is 32-bit on 32-bit platforms
It is 64-bit on 64-bit platforms
It is 32-bit on the wire for backward compatibility. It gets truncated on the sending side and extended appropriately (signed or unsigned) on the receiving side.
Beispiel:
[ signed | unsigned ]  __int3264  [ int ]  declarator-list;
http://msdn.microsoft.com/en-us/library/windows/desktop/aa367390(v=vs.85).aspx


NEU HANDLE, HWND, ...

Laut msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx ist (z. B.) HWND folgendermaß definiert:

typedef void *PVOID;
typedef PVOID HANDLE;
typedef HANDLE HWND;

=> HWND entspricht void*

D. h. man kann ein HANDLE an ein HWND zuweisen und umgekehrt und der Compiler hat keine Chance, zu erkennen, dass man hier unterschiedliche Handles aneinander zuweist. Dies kann zu merkwürdigen Fehlern führen (wenn man z. B. ein File-Handle an ein Windows-Handle zuweist - der Compiler gibt keine Fehlermeldung/Warnung aus und übersetzt das.

Daher werden, wenn STRICT definiert ist (was anscheinend mittlerweile der Normalfall ist) Handles mittlerweile in „winnt.h” (bei mir im Verzeichnis „windows_kits\10\Include\10.0.14393.0\um” auf dem selben Laufwerk auf dem Visual Studio installiert ist) mittels Preprozessor-Makro definiert:

typedef void *PVOID;
...
#ifdef STRICT
typedef void *HANDLE; #if 0 && (_MSC_VER > 1000)
#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
#else
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
#endif
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name

HANDLE ist also nach wie vor als Pointer auf void (void*) definiert, andere Handles wie z. B. HWND werden jetzt aber folgendermaßen definiert (siehe in windef.h):

DECLARE_HANDLE(HWND)

D. h. HWND entspricht:

typedef struct HWND__ *HWND

Ein HWND ist jetzt also ein Pointer auf struct HWND__ ein anderes Handle ist z. B. HHOOK. Dies ist ebenfalls mit diesem Makro definiert und folglich ein Pointer auf struct HHOOK__. Dies hat den Vorteil, dass der Compiler jetzt zwischen HWND und HHOOK unterscheiden kann und bei Zuweisungen ohne Cast einen Fehler ausgeben kann.


16-Bit Windows

FAR PASCAL

#define  FAR  far
#define  PASCAL  pascal
"far" bedeutet dass der Code der aufgerufenen Funktion in einem anderen Code Segment als der des aufrufenden Programms liegt. Wird ab 32-Bit Windows nicht mehr benötigt.
"pascal" ist die Aufrufkovention wie __stdcall (parameter werden von links nach rechts auf den Stack übergeben, die aufgerufene Funktion räumt den Stack auf). Ab 32-Bit Windows verwendet man stattdessen __stdcall.

Hinweis: int war unter 16 Bit Windows 16 Bit, long 32 Bit


WORD

#define  WORD  unsigned  int


DWORD

#define  DWORD  unsigned  long


LONG

#define  LONG  long


LPSTR

#define  LPSTR  far  char*


[Alles für Windows 16 Bit aus "Programming Windows", Charles Petzold, Microsoft Press, ISBN 1-55615-264-7]