Was ist der "InitCommonControlsEx"-Bug?
Wenn Sie beim Test der beiliegenden Programme bemerken, dass einige der "Common Controls" nicht angezeigt werden, dann liegt dies nicht am Programm. Als Beispiel möchte ich das Eingabefeld für IP-Adressen anführen.
Dazu muss man wissen, dass der Befehl "InitCommonControls" im Platform SDK von Microsoft als veraltet (obsolete) bezeichnet wird. Die meisten Beispiele dieses Tutorials nutzen ihn dennoch. In einigen Fällen, etwa beim schon erwähnten IP-Control, reicht dieser Befehl aber nicht mehr aus. Hier muss zwingend der Befehl "InitCommonControlsEx" verwendet werden. Auf Grund des Bugs werden die Controls jedoch nicht korrekt initialisiert, und das IP-Eingabefeld ist nicht zu sehen.
Welche Versionen sind betroffen?
| Delphi-Version | Status |
|---|---|
| Delphi 2 | - |
| Delphi 3 | - |
| Delphi 4 | - |
| Delphi 5 | der Fehler tritt ohne und mit SP1 auf |
| Delphi 6 | der Fehler tritt ohne und mit Updates/Service-Packs auf |
| Delphi 7 | der Fehler tritt ohne und mit SP1 auf |
| Delphi 2005 (Delphi 9) | in der Preview tritt der Fehler auf |
| Delphi 2006 | - |
| TurboDelphi für Win32 | der Fehler tritt auf (lt. Quellcode der "CommCtrl.pas") |
(keine Angabe bedeutet: mir lagen zu diesem Zeitpunkt keine Informationen vor, ob der Fehler auftritt oder nicht)
Wenn Sie eine Standard- oder Personal-Version von Delphi besitzen, haben Sie keinen Zugriff auf die Quellcodes der Unit. Mein Rat lautet in dem Fall: benutzen Sie eine möglichst aktuelle Standardversion (in der Hoffnung, dass der Fehler dort behoben wurde).
Ist das nicht der Fall, dann rufen Sie in Ihrem Programm zusätzlich den Befehl
InitCommonControls;
auf. Es spielt zwar keine Rolle, an welcher Stelle Sie das tun, aber wg. der besseren Übersichtlichkeit empfehle ich, dass Sie den Befehl vor "InitCommonControlsEx" in den Quellcode eintragen. Sollte der Fehler einmal behoben worden sein, müssen Sie nicht lange suchen und können die dann überflüssige Anweisung schnell entfernen.
Hierfür benötigen Sie Borlands Quellcode der "CommCtrl"-Unit. Wenn wir uns die Deklaration am Beispiel von Delphi 5 einmal anschauen, dann finden wir in der Unit eine eigene Funktion mit dem Namen "InitCommonControlsEx". Dies ist kein Fehler, sondern hat damit zu tun, dass die Funktion unter Windows 95 und NT4 den Internet Explorer 3 als Minimum erfordert. Arbeitet noch jemand mit einer Originalversion dieser Systeme (ohne installiertem IE), existiert die Funktion bei ihm noch gar nicht. Der Versuch, sie dennoch (statisch) zu laden, würde eine unschöne Fehlermeldung verursachen.
Daher wird in der Unit von Borland nun versucht, die Funktion dynamisch zu laden. Zu dem Zweck wird eine zweite, interne Funktion aufgerufen, die (im Fall von D5 und beispielsweise TurboDelphi) wie folgt aussieht:
procedure InitComCtl; begin if ComCtl32DLL = 0 then begin ComCtl32DLL := GetModuleHandle(cctrl); if ComCtl32DLL <> 0 then @_InitCommonControlsEx := GetProcAddress(ComCtl32DLL, 'InitCommonControlsEx'); end; end;
Und hier liegt meines Erachtens nach der Fehler. In der Zeile
ComCtl32DLL := GetModuleHandle(cctrl);
wird das Handle der geladenen DLL "comctl32.dll" gesucht und an die Variable übergeben. Wenn die DLL aber nicht geladen ist, erhält die Variable den Wert Null und führt in dem Fall die nachfolgenden Anweisungen auch nicht mehr aus. Fügen Sie daher nach der eben gezeigten Zeile folgendes ein:
if ComCtl32DLL = 0 then ComCtl32DLL := LoadLibrary(cctrl);
Sollte also "GetModuleHandle" tatsächlich den Wert Null als Ergebnis liefern, wird die Bedingung aktiv und die DLL geladen.