Windows XP Professional x64 – RC1
Was lange währt, wird hoffentlich endlich mal gut. Heute wurde im MSDN der RC1 von Windows XP Professional x64 freigegeben.
Ist eBay überall?
In den letzten Tagen hat sich mein Interesse auf Porzellan von Ritzenhoff & Breker gerichtet. Es gibt eine Vielzahl von verschiedenen Sets, die mehr oder weniger gut aussehen und sich daher auch preislich mehr oder weniger voneinander unterscheiden. Als einer sich etwas im Internet auskennender Zeitgenosse ist man natürlich versucht, möglichst viele Informationen zu den verschiedenen Produkten zu bekommen, insbesondere Preisvergleiche oder günstige Anbieter zu finden. Flugs Onkel Google zu „Ritzenhoff Breker“ gefragt und nach kurzem Überlegen präsentiert er mir ungefähre 3870 deutsche Seiten zu diesem Thema.
Hier mal eine Auswahl der Ergebnisse der ersten 3 Seiten:
- http://www.gaysheaven.de/breker.html
- http://www.sf-database.de/ek_24226_6_Markenglas_Ritzenhoff.html
- http://www.sdwc-niedersachsen.de/ek_24226_12_Markenglas_Ritzenhoff.html
- http://www.regional-vernetzt.de/ek_24226_1_Markenglas_Ritzenhoff.html
- http://medizin-und-technik.de/ek_24226_8_Markenglas_Ritzenhoff.html
- http://www.lehrstuhlnehlsen.de/3-set-teiliges.html
- http://www.jam-jelly.de/espresso-ritzenhoff.html
- http://www.edelmetallgewinnung.de/ek_74385_11_Geschirr-Einzelteile_Espressotassen.html
- http://www.disrespect.de/untertassen.html
- http://www.britneyforen.de/ek_87330_4_Weihnachten_Krippen.html
- http://www.top-versicherungen-online.de/ek_24226_9_Markenglas_Ritzenhoff.html
- http://hoerbuchversand.de/ek_2762_1_Markenkeramik_Sonstige.html
Eine Menge unterschiedlicher Domains, aber letztlich immer nur ein Ziel. Alle Links bringen einen nach kurzer Umleitung zu einer Unterseite von http://www.auktion-9.de/, dort werden alle angebotenen eBay-Aktionen zu Ritzenhoff & Breker aufgelistet.
Muss das denn unbedingt sein? Diese eBay-Schwemme in Google nervt ungemein, zumindestens mich. Hat noch jemand ähnliche (schlechte) Erfahrungen gemacht?
Imageliste mit System
Eine Imageliste ist eine Ansammlung von Bildobjekten gleicher Größe und Farbauflösung, die anhand ihres Index innerhalb der Liste referenziert werden. Die einzelnen Bildobjekte können auf einfache und vielfältige Weise gezeichnet werden. Listenansicht und Baumansicht nutzen die Imageliste zur Darstellung von Symbolen, jeder Eintrag in den beiden Ansichten kann als Eigenschaft einen Index des darzustellenden Symbols innerhalb einer Imageliste enthalten. Die zu verwendende Imageliste wird den beiden Ansichten mit einer Funktion zugewiesen.
Die Systemimageliste ist eine von der Shell erzeugte und gepflegte Imageliste, genaugenommen sind es sogar mehrere. Bis einschließlich Windows 2000 verwendet die Shell zwei Imagelisten (16×16 und 32×32), mit Windows XP kam eine dritte (48×48) hinzu. Unter Windows 9x/ME wird für alle Prozesse eine gemeinsame Systemimageliste verwendet, jede Manipulation hat auch Auswirkungen auf alle anderen Prozesse. Unter Windows NT/2000/XP erhält jeder Prozess eine eigene Systemimageliste, Änderungen an dieser betreffen dann nur noch die eigene und nicht die der anderen Prozesse.
Der Zugriff auf die Systemimageliste erfolgt über die Funktion SHGetFileInfo. Der Rückgabewert von SHGetFileInfo ist ein Handle auf eine Imageliste, entweder auf die kleine (16×16) oder auf die große (32×32). Die extragroße Imageliste (48×48) unter Windows XP kann durch SHGetFileInfo nicht ermittelt werden, hierfür muss die Funktion SHGetImageList verwendet werden. Zur einfachen Handhabung habe ich mir eine Funktion Lwl_ShlGetSystemImageList geschrieben, die alle nötigen Aufrufe kapselt und abwärtskompatibel bis Windows 95 ist. Die Parameter sind SHIL_LARGE (32×32), SHIL_SMALL (16×16) und SHIL_EXTRALARGE (48×48), alle 3 Konstanten sind in der Headerdatei ShellAPI.h definiert.
HIMAGELIST Lwl_ShlGetSystemImageList(int iImageList) { // 16x16 und 32x32 auf konventionelle Art if (SHIL_SMALL == iImageList || SHIL_LARGE == iImageList) { // Flags zusammenstellen SHFILEINFO sfi; DWORD dwFlags = SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES; dwFlags |= (SHIL_SMALL == iImageList ? SHGFI_SMALLICON : SHGFI_LARGEICON); // Imageliste abrufen return (HIMAGELIST) SHGetFileInfo(_T("123.txt"), 0, &sfi, sizeof(SHFILEINFO), dwFlags); } // 48x48-Imageliste abrufen HIMAGELIST hImageList = NULL; if (S_OK != _SHGetImageList(iImageList, IID_IImageList, (void**) &hImageList)) return NULL; // Ans kloar return hImageList; }
Die Funktion _SHGetImageList importiert SHGetImageList dynamisch und ruft diese bei Verfügbarkeit auf. Somit ist die Lauffähigkeit auch unter älteren Windows-Versionen sichergestellt.
typedef HRESULT (STDMETHODCALLTYPE *SHGETIMAGELIST)(int, REFIID, void**); STDAPI _SHGetImageList(int iImageList, REFIID riid, void** ppv) { // Alles wird gut HRESULT hResult = S_OK; // Dll laden HINSTANCE hInstShell32 = LoadLibrary(_T("Shell32.dll")); if (NULL == hInstShell32) return HRESULT_FROM_WIN32(GetLastError()); // Funktion anhand des Namens importieren SHGETIMAGELIST pfn = (SHGETIMAGELIST) GetProcAddress(hInstShell32, "SHGetImageList"); // Funktion aufrufen if (NULL != pfn) { hResult = (pfn)(iImageList, riid, ppv); } // Funktion ist nicht vorhanden else { hResult = HRESULT_FROM_WIN32(GetLastError()); } // Dll freigeben FreeLibrary(hInstShell32); // Ans kloar return hResult; }
Lwl_ShlGetSystemImageList gibt das Handle auf die gewünschte Imageliste zurück. Wenn diese noch nicht existiert, dann werden unter Windows NT/2000/XP alle zwei (bzw. ab XP drei) Imagelisten erstellt und mit folgenden Symbolen gefüllt:
- Freigabesymbol (Overlay)
- Verknüpfungssymbol (Overlay)
- Offlinesymbol (Overlay)
- Unbekannter Dateityp
- Textdatei
Unter Windows 9x/ME ist mit sehr großer Wahrscheinlichkeit der Explorer die erste Anwendung, welche die Systemimageliste initialisiert. Alle anderen nachfolgenden Prozesse bekommen dann einen Verweis auf die bereits gut gefüllte Imageliste zurück.
Jeder nachfolgende Aufruf von SHGetFileInfo zur Ermittlung von Dateisymbolen fügt das entsprechende Symbol dann der Systemimageliste hinzu, sofern es noch nicht in dieser enthalten ist. Alle zwei (oder drei) Imagelisten werden synchron gefüllt, so dass ein Index für ein Symbol in der 16×16-Liste gleich dem Index in der 32×32-Liste ist.
Wetter, Wetter, Wetter
wetter.de bietet einen netten Service, über den sich das aktuelle lokale Wetter in die eigene Website integrieren lässt. Nach Angabe von Ort, Name, Website und eMail-Adresse bekommt man ein Stück HTML-Code zugesandt. Die Einbindung ist sehr einfach, zudem sieht es auch recht schick aus. Die Größe der Flash-Animation ist anpassbar.
Leider verwendet der HTML-Code das embed-Tag und ist damit nicht XHTML-kompatibel. Lässt man das embed-Tag weg, dann zeigt zwar der IE das Flash an, Mozilla mag aber nicht mehr. Unter Flash standardkonform und barrierearm in XHTML einbinden zeigt Angie Radtke, wie man Flash auch ohne embed-Tag mit beiden Browsern zum Laufen bringt.
Langsame Laufwerke
Bei der Optimierung der Dateianzeige für VPN-Laufwerke bin ich über die Funktion PathIsSlow gestolpert. Die Dokumentation im Platform SDK ist nicht gerade aussagekräftig, eine Eigenschaft, die leider für viele Funktionen zutrifft, welche erst 2002 im Zuge des Antitrust-Prozesses gegen Microsoft dokumentiert wurden. In der Funktionsbeschreibung zu PathIsSlow steht
Determines whether a file path is a high-latency network connection.
Doch nach welchen Kriterien legt Windows fest, ob es sich für den angegebenen Dateinamen um eine langsame oder um eine schnelle Verbindung handelt?
Um dies herauszufinden, habe ich mir die Funktion im Debugger mal etwas näher angeschaut. Mit Hilfe der von Microsoft angebotenen Symboldateien lässt sich mit ein wenig Assembler-Kenntnis einiges herausfinden. PathIsSlow ist eine recht kurze Funktion und sieht wie folgt aus:
PathIsSlowW@8: 773DA350 push esi 773DA351 mov esi,dword ptr [esp+8] 773DA355 push esi 773DA356 call dword ptr [__imp__PathIsUNCW@4 (773a20a8)] 773DA35C test eax,eax 773DA35E push esi 773DA35F jne _PathIsSlowW@8+11h (774478bc) 773DA365 call dword ptr [__imp__PathGetDriveNumberW@4 (773a20e4)] 773DA36B push eax 773DA36C call _CMtPt_IsSlow@4 (773da388) 773DA371 test eax,eax 773DA373 jne _PathIsSlowW@8+21h (773da383) 773DA375 push dword ptr [esp+0Ch] 773DA379 push esi 773DA37A call _PathIsHighLatency@8 (773da3b8) 773DA37F pop esi 773DA380 ret 8 773DA383 xor eax,eax 773DA385 inc eax 773DA386 jmp _PathIsSlowW@8+40h (773da37f)
Zuerst wird mit Hilfe der Funktion PathIsUNC geprüft, ob der Dateiname in der UNC-Konvention (\\Server\Freigabe) vorliegt. Wenn ja, verzweigt PathIsSlow zur Adresse 0x774478bc. Befindet sich der Dateiname dagegen auf einem gemappten Laufwerk, dann wird über PathGetDriveNumber der Laufwerksbuchstabe ermittelt und mit diesem die Funktion CMtPt_IsSlow aufgerufen:
_CMtPt_IsSlow@4: 773DA388 push esi 773DA389 push edi 773DA38A push 1 773DA38C xor edi,edi 773DA38E push edi 773DA38F push dword ptr [esp+14h] 773DA393 call CMountPoint::GetMountPoint (773cb43b) 773DA398 mov esi,eax 773DA39A cmp esi,edi 773DA39C je _CMtPt_IsSlow@4+29h (773da3b1) 773DA39E mov eax,dword ptr [esi] 773DA3A0 mov ecx,esi 773DA3A2 call dword ptr [eax+0CCh] 773DA3A8 mov ecx,esi 773DA3AA mov edi,eax 773DA3AC call CMountPoint::Release (773cb385) 773DA3B1 mov eax,edi 773DA3B3 pop edi 773DA3B4 pop esi 773DA3B5 ret 4
In dieser Funktion wird geprüft, ob es für den gewünschten Laufwerksbuchstaben ein CMountPoint-Objekt gibt. Im Erfolgsfall wird CMtPtRemote::IsSlow (0x773DA3A2) aufgerufen:
_IsSlow@CMtPtRemote@@EAEHXZ: 77521018 push esi 77521019 xor esi,esi 7752101B call CMtPtRemote::_GetPathSpeed (77517e98) 77521020 test eax,eax 77521022 je CMtPtRemote::_IsSlow+14h (7752102c) 77521024 cmp eax,190h 77521029 ja CMtPtRemote::_IsSlow+14h (7752102c) 7752102B inc esi 7752102C mov eax,esi 7752102E pop esi 7752102F ret
Windows verzweigt weiter zur Funktion CMtPtRemote::GetPathSpeed:
_GetPathSpeed@CMtPtRemote@@AAEKXZ: 77517E98 push esi 77517E99 lea esi,[ecx+25Ch] 77517E9F cmp dword ptr [esi],0 77517EA2 jne CMtPtRemote::_GetPathSpeed+11h (77517ea9) 77517EA4 call CMtPtRemote::_CalcPathSpeed (77517cbb) 77517EA9 mov eax,dword ptr [esi] 77517EAB pop esi 77517EAC ret
und prüft, ob die Geschwindigkeit für das MountPoint-Objekt bereits berechnet und gespeichert wurde. Wenn ja, dann wird dieser Wert zurückgegeben. Ansonsten verzweigt Windows zur Funktion CMtPtRemote::CalcPathSpeed und berechnet mit Hilfe von MultinetGetConnectionPerformance die Geschwindigkeit. Diese wird in einer NETCONNECTINFOSTRUCT-Struktur zurückgeben und besitzt folgende Bedeutung:
Speed of the media to the network resource, in 100 bits-per-second (bps).
For example, a 1200 baud point-to-point link returns 12. A value of zero indicates that no information is available. A value of one indicates that the actual value is greater than the maximum that can be represented by the member.
In der Funktion CMtPtRemote::IsSlow sieht man an der Adresse 0x77521024, dass die ermittelte Geschwindigkeit mit 0x190 (400) verglichen wird. Ist sie größer als 400, dann gilt das Laufwerk als schnell; ist sie kleiner oder gleich 400, dann ist das Laufwerk langsam. 40000 bps ist also die Grenze für ein langsames Laufwerk. Nach meinem Verständnis ist dies eine normale Modemverbindung, anhand der gemessenen Werten ist für mich die Bedeutung dieses Wertes allerdings nicht ganz klar:
Verbindung | Geschwindigkeit |
1 MBit (VPN DSL) | 104 |
10 MBit | 948 |
54 MBit (WLAN) | 2044 |
100 MBit | 2115 |
1 GBit | 7972 |
Die VPN-Verbindung fällt noch eindeutig in den langsamen Bereich, während die 10 MBit-Netzwerkanbindung schon deutlich zu schnell ist, um noch als langsam zu gelten.
Doch nun wieder zurück zu PathIsSlow. Die Ermittlung der Geschwindigkeit für UNC-Namen in der Funktion GetPathSpeed erfolgt ebenfalls über MultinetGetConnectionPerformance, den Abdruck der Funktion habe ich mir jetzt erspart. Sollte die Geschwindigkeitsprüfung für den Dateinamen ergeben, dass er sich nicht auf einem langsamen Laufwerk befindet, ruft Windows noch die Funktion PathIsHighLatency auf. Diese ist leider nicht dokumentiert und sieht wie folgt aus:
_PathIsHighLatency@8: 773DA3B8 mov eax,dword ptr [esp+8] 773DA3BC push esi 773DA3BD xor esi,esi 773DA3BF cmp eax,0FFFFFFFFh 773DA3C2 jne _PathIsHighLatency@8+26h (773da3d9) 773DA3C4 cmp dword ptr [esp+8],esi 773DA3C8 je _PathIsHighLatency@8+1Eh (773da3e8) 773DA3CA push dword ptr [esp+8] 773DA3CE call dword ptr [__imp__GetFileAttributesW@4 (773a1a38)] 773DA3D4 cmp eax,0FFFFFFFFh 773DA3D7 je _PathIsHighLatency@8+2Eh (773da3e2) 773DA3D9 test ah,10h 773DA3DC jne _PathIsHighLatency@8+2Bh (774478b4) 773DA3E2 mov eax,esi 773DA3E4 pop esi 773DA3E5 ret 8 773DA3E8 or eax,0FFFFFFFFh 773DA3EB jmp _PathIsHighLatency@8+21h (773da3d4)
Anhand der Dateiattribute, die der Funktion PathIsSlow übergeben worden sind, wird geprüft, ob das Attribut FILE_ATTRIBUTE_OFFLINE gesetzt ist. Dieses Flag wird von Remote Storage Systemen verwendet und gibt an, dass die Daten im Moment ausgelagert sind. Werden an PathIsSlow keine Dateiattribute übergeben, so ermittelt PathIsHighLatency die Attribute über GetFileAttributes selbst.
Das Rätsel um langsame Laufwerke ist nun (fast) gelüftet. PathIsSlow nutzt die Funktion MultinetGetConnectionPerformance, um die Geschwindigkeit zu bestimmen. Zusätzlich wird noch geprüft, ob sich die Datei auf einem Remote Storage System befindet und dort im Moment ausgelagert ist. Unklar ist bisher leider noch, wie sich die von MultinetGetConnectionPerformance zurückgegebene Geschwindigkeit einordnen lässt.