Eine Frage zum Verständnis von Handles ...
-
Bin über die Deklaration der verschiedenen API-Handles gestolpert (nach dem der Präprozessor darübergelaufen ist):
struct HINSTANCE__{int unused;}; struct HWND__ {int unused;}; struct HICON__ {int unused;}; struct HBRUSH__ {int unused;}; typedef struct HINSTANCE__ *HINSTANCE; typedef struct HWND__ *HWND; typedef struct HICON__ *HICON; typedef struct HBRUSH__ *HBRUSH;Und ich bin auch über Funktionen gestolpert, die wie <CreateWindow> oder <LoadIcon> solche Handles zurückgeben.
Aber wie definieren sich Handles? Ich meine, der einzige Wert in diesen Strukturen (unused) lässt ja ahnen, dass er nicht verwendet wird, aber wo werden dann die Werte gesichert? Was unterscheidet ICON_1 von ICON_2 beim betrachten der jeweiligen Handles? Wenn ich mit <CreateWindow> ein Fensterhandle erstelle und den Rückgabewert in einer Handlevariable sichere, muss sich dieses Handle z.B. von einem zweiten Fensterhandle unterscheiden lassen können, oder?
-
Die Handles sind einfach Pointer (Interessant ist nur der Pointerwert selbst, nicht die Daten auf die der Pointer zeigt)
Der Struct-Kram ist quasi ein "Hack", damit der Compiler weiß, dass HWND und HBRUSH was anderes sind und z.B. IsWindow() mit nem HBRUSH nichts anfangen kann.
-
Dann ist unused 'ne Adresse?
-
HWND = Pointer auf "HWND__"-Struktur
Die Inhalte der Struktur ("int unused") sind allerdings völlig irrelevant
-
Jaja, das habe ich schon verstanden. Aber wenn der Wert völlig irrelevant ist, wie kann Windows dann zwischen den Rückgabewerten von
LoadCursor(NULL,IDC_ARROW)und
LoadCursor(NULL,IDC_IBEAM)unterscheiden, wenn der Wert von HCURSOR völligst irrelevant ist?
-
HCURSOR cursor1=LoadCursor(NULL,IDC_ARROW); HCURSOR cursor2=LoadCursor(NULL,IDC_IBEAM);ist in Wirklichkeit, wenn man die Typedefs auflöst, sowas:
HICON__* cursor1=LoadCursor(NULL,IDC_ARROW); HICON__* cursor2=LoadCursor(NULL,IDC_IBEAM);D.h. cursor1 könnte z.B. den Wert 12 haben und cursor2 den Wert 15 - die sind also unterschiedlich. Dabei hast du "unused" aber noch nicht angeschaut.
Theoretisch könnte man im Speicher an Stelle 12 jetzt auf "unused" zugreifen, oder über cursor1->unused.Windows benutzt aber nur den Wert "12" als Unterscheidungsmerkmal, nicht die Daten ("unused") auf die, der cursor1-Pointer (also die 12) zeigt.
Ich vermute mal das Problem besteht hier gerade beim Pointer-Verständnis

Grob gesagt sind Pointer eine spezielle Art von Variablen, die nicht direkt Daten speichern sondern nur die Adresse im Speicher, an dem sich die tatsächlichen Daten befinden.
-
Moment. Du sagst, cursor1 hat den Wert 12. 12 wird als Adresse interpretiert (HICON__*), also ist an 0x0C das HICON-Objekt gesichert. Aber an 0x0C ist doch nur ein int-Wert ... und der es irrelevant. Ein Handle kann ja auch nur auf Daten zugreifen, die in der Struktur deklariert wurden ...
Also egal, welche Resourcen geladen werden, die Adresse von Handles wird automatisch als Datum angesehen?
-
Cler schrieb:
12 wird als Adresse interpretiert (HICON__*)
Genau das ist der Harken an der Sache bei Handles: Die 12 wird hier gerade nicht als Adresse interpretiert, sondern einfach als Zahl 12 - quasi als ne ID.
Mit der 12 können die Windows-Funktionen dann selbst irgendwo intern nachschlagen was der Cursor für ne Größe hat, wo Windows sich die Pixeldaten gespeichert hat, etc.Ein Handle ist im Prinzip nur eine Zahl, mit der irgendeine Resource eindeutig identizifert werden kann.
Die Microsoft-Leute hätten im Prinzip auch einfach sowas machen können:
int cursor1=LoadCursor(NULL,IDC_ARROW);Den seltsam aussehenden Umweg über Pointer sind die gegangen um sowas zu vermeiden:
int cursor1=LoadCursor(NULL,IDC_ARROW); int dc=CreateCompatibleDC(cursor1);CreateCompatibleDC() kann mit nem Cursor eigentlich nichts anfangen und wird beim Ausführen dann auch fehlschlagen.
Wenn man das über Pointer macht:
HICON cursor1=LoadCursor(NULL,IDC_ARROW); HDC dc=CreateCompatibleDC(cursor1);kann der Compiler meckern, dass man CreateCompatibleDC() mit einem HICON füttert obwohl die Funktion eigentlich einen HDC braucht.
-
Ob die 12 als Adresse oder als ID oder als was auch immer interpretiert wird, ist schlicht und ergreifend nicht definiert.
Es kann an der Stelle auf die das Handle "zeigt" (als Zeiger interpretiert) sehrwohl eine bedeutsame Datenstruktur zu finden sein.
-
Ah, danke. Also, es KANN eine Adresse sein oder einfach nur eine Zahl. Wie wenn ich im normalen C das hier schreiben würde:
char*pValue=0x0C; //Achtung! Zeiger wurde nicht mit reserviertem Speicher initialisiert, //sondern mit der Adresse 0x0C. Aber falls man den Zeiger deferenziert, //gibt's Haue vom Laufzeitsystem.Man sollte also Handles nicht deferenzieren und den Rest den API-Funktionen überlassen. Sie sorgen dafür, dass die Handles korrekt ausgelesen werden.
-
Der Unterschied zwischen handles und pointers ist u.a.
dass man handles zur laufzeit auf gültigkeit prüfen kann.Man verliert aber häufig compilezeit type sicherheit.
z.B.
HANDLE handle = ... CloseHandle (handle); // hier kann die api zur laufzeit feststellen, dass das handle ungültig ist apiSoSomeThingWithHandle(handle);Weiterhin wird der Speicher auf den die Handles referenzieren oft
linear hintereinander abgelegt, z.B. in einem Array.
Das kann unter Last günstig werden, fragmentierten Speicher vermeiden
macht es sogar möglich Speicher direkt wiederzuverwenden.
Das kommt dann vielen kleinen, Heapmanagern für jeden Type gleich ...Insgesamt bin ich von der Handle Technik überzeugt,
ich verwende eingene Handle Implementierugen recht oft.
Mir fehlt z.Z. leider etwas um Type Fehler zur Kompilezeit aufzuzeigen.Gruß Frank
-
Cler schrieb:
Jaja, das habe ich schon verstanden. Aber wenn der Wert völlig irrelevant ist, wie kann Windows dann zwischen den Rückgabewerten von
LoadCursor(NULL,IDC_ARROW)und
LoadCursor(NULL,IDC_IBEAM)unterscheiden, wenn der Wert von HCURSOR völligst irrelevant ist?
Hallo,
Windows benutzt intern einfach eine andere Definition. Die Application bekommt nur die Adresse der Struktur und das wird im WinSDK als Handle verkauft. Der Quelltext von Windows benutzt einfach eine eigene Definition der Struktur, die dann mehr als nur ein unused enthält. Es kann aber auch sein, daß es einfach nur ein Arrayindex ist. Wie auch immer, dem Nutzer der WinAPI geht das nichts an.
Der Hack in der windows.h und anderen Header dient einfach nur, daß Du nicht versehentlich der CloseWindow-Funktion ein Handle auf ein Icon geben kannst.
mfg Martin