Komfortabler Dateimanager mit vielen Funktionen

Imageliste mit System

By Sven on 10.01.2005 - 10:00 in Entwicklung

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.

Es gibt 2 Kommentare zu diesem Beitrag

Trackback URL | RSS-Feed für Kommentare

  1. Uwe Keim sagt:

    Sehr gut beschrieben! Das wird hier noch eine richtige Referenz-Sanmmlung. Ich freu mich schon drauf wenn Sven eeeeeeeeeeendlich .NET macht. Das wird dann cool 🙂

  2. Sven sagt:

    Danke! Mit .NET habe ich schon ein wenig gespielt (zwecks AddIns für den SC11), aber mehr passiert damit vorerst auch nicht. 😉

Top