Zuerst sollten wir herausfinden, welche Version der "shell32.dll" vorhanden ist. Dazu nutzen wir eine Funktion, die die Bibliothek selbst exportiert:
HRESULT CALLBACK DllGetVersion( DLLVERSIONINFO* pdvi // Zeiger auf "DLLVERSIONINFO"-Record );
Das benötigte Record,
DllVersion.pas", die vom Beispielprogramm benutzt wird.
In unserem Fall werden die Haupt- und Nebenversionsnummer zu einem numerischen Wert zusammengefasst. So steht 500 beispielsweise für die Version 5.0; 600 würde demzufolge Version 6.0 bedeuten usw.
dll := LoadLibrary('shell32.dll'); if(dll <> 0) then begin DllGetVersion := GetProcAddress(dll,'DllGetVersion'); if(@DllGetVersion <> nil) then begin ZeroMemory(@ver,sizeof(TDllVersionInfo)); ver.cbSize := sizeof(TDllVersionInfo); if(DllGetVersion(@ver) = NOERROR) then shell32_ver := (ver.dwMajorVersion * 100) + ver.dwMinorVersion; end;
FreeLibrary(dll); end;
Bei der Initialisierung setzen wir die Versionsnummer auf 400, für den Fall, dass wir mit einer DLL-Version arbeiten, die die o.g. Funktion noch nicht exportiert, bzw. keinen Wert zurückliefert o.ä. Wir müssen ja leider auch immer mit solchen Dingen rechnen.
Dann setzen wir, abhängig von der vorhandenen DLL-Version die Größe des Records:
if(shell32_ver = 600) then NID.cbSize := sizeof(TNotifyIconData) else if(shell32_ver >= 500) then NID.cbSize := NOTIFYICONDATA_V2_SIZE else NID.cbSize := NOTIFYICONDATA_V1_SIZE;
Hier sehen Sie die Anwendung der Konstanten, die wir hier deklariert haben. So können wir z.B. unter Windows XP (DLL-Version 6.0) das komplette Record benutzen. Unter Windows ME und 2000 (DLL-Version 5.0) steht uns immerhin alles außer der TGuid-Membervariablen zur Verfügung, weshalb wir die Konstante NOTIFYICONDATA_V2_SIZE nutzen müssen. Und unter Windows 95, 98 und NT müssen wir das Originalrecord und seine Größe benutzen, da uns hier die erweiterten Funktionen natürlich nicht zur Verfügung stehen. Und das entspricht der Konstanten NOTIFYICONDATA_V1_SIZE.
Was passiert dabei?
Im Fall von NOTIFYICONDATA_V2_SIZE wird die Größe des erweiterten Records lediglich um die Größe der TGuid-Variablen verringert. Ein Aufruf unter Windows 2000 beispielsweise würde demzufolge dann auch nur die noch vorhandenen Membervariablen füllen.
NOTIFYICONDATA_V1_SIZE hat dagegen zwei feste Werte (jeweils für die Ansi- und Unicode-Version), die sich aus dem Originalrecord errechnen. Im Fall der Ansi-Version wären das z.B. 88 Bytes. Auf diesen Wert würde die Größe des Records eingestellt werden. Ein Aufruf würde dann also auch nur die ersten 88 Bytes berücksichtigen. Und das bedeutet auch, dass 64 Bytes von der szTip-Variablen abgezogen werden. Probleme gibt es daher unter keinem Betriebssystem, selbst wenn Sie unter Windows 98 mit dem neuen Record arbeiten. Sie sollten nur nicht auf Membervariablen zugreifen, die erst durch neuere DLL-Versionen eingeführt werden. Im Idealfall passiert nichts, ebenso wäre aber auch eine Fehlermeldung oder ein Absturz denkbar.
Eine Sicherheitsabfrage oder -prüfung sollte daher Pflicht sein. Nehmen wir als Beispiel den Balloon-Stil, der sich ja erst ab DLL-Version 5.0 oder höher nutzen lässt, und der im Beispielprogramm auch nur dann verwendet wird:
if(shell32_ver >= 500) then begin if(BalloonsEnabled) then begin NID.uFlags := NID.uFlags or NIF_INFO; NID.szInfo := 'Ein Beispiel für einen neuen Balloon-Tipp,' + #13#10 + 'der auch mehrzeilig sein kann.'; NID.szInfoTitle := szClassname; NID.dwInfoFlags := NIIF_INFO; end else MessageBox(wnd,'Balloon-Tipps sind bei Ihnen deaktiviert!', nil,MB_ICONERROR) end;
Wenn wir das Programm nun starten und die DLL aktuell genug ist, sehen wir den neuen Balloon-Tipp. Andernfalls passiert aber auch nichts, und wir haben zumindest den gewohnten TNA-Funktionsumfang.
Das System kümmert sich um die Zeitdauer der Anzeige. Im PSDK heißt es dazu sinngemäß, dass ein Balloon-Tipp mit einem Timeout von 30 Sekunden für ca. 7 Sekunden sichtbar ist, sobald eine zweite Anwendung einen Tipp anzeigen möchte. Der Timeout-Wert, den Sie angeben, dient also mehr als Richtwert und weniger als tatsächliche Anzeigedauer.