Komfortabler Dateimanager mit vielen Funktionen

Windows XP Professional x64 – RC1

By Sven on 13.01.2005 - 19:25 in Windows XP

Was lange währt, wird hoffentlich endlich mal gut. Heute wurde im MSDN der RC1 von Windows XP Professional x64 freigegeben.

Ist eBay überall?

By Sven on 12.01.2005 - 23:12 in Webweites with 5 Kommentare

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:

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

By Sven on 10.01.2005 - 10:00 in Entwicklung with 2 Kommentare

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

By Sven on 08.01.2005 - 11:50 in Webweites with 2 Kommentare

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

By Sven on 06.01.2005 - 22:45 in Entwicklung

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.

Top