MFCShellListCtrl Datei Filter



  • Hallo zusammen,

    ich muss einen FileOpenDialog bauen bei welchem ich die Navigation durch das FileSystem beliebig einschränken kann. Dazu habe ich das MFCShellListCtrl benutzt.

    Mein (vorerst noch rudimentärer) Datei Filter funktioniert so lange perfekt bis jemand ControlPanel->Appearance and Personalization->Folder Options->View->"Hide extensions for known file types" setzt, dann werden keine Dateien mehr angezeigt.

    Codeausschnitt aus MyShellListCtrl::EnumObjects (...)

    SHFILEINFO sfi;
    if (SHGetFileInfo ((LPCTSTR)item->pidlFQ, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_TYPENAME))
    {
      Tstring fileType = ToLower (sfi.szTypeName);
      Tstring fileName = _T("");
    
      if (SHGetFileInfo ((LPCTSTR)item->pidlFQ, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_DISPLAYNAME))
        fileName = ToLower (sfi.szDisplayName);
    
      if (fileType != _T("system folder") && fileType != _T("file folder"))
      {
        bool supported = false;
        StringList s = Split (fileName, _T('.'));
        if (s.size () > 1)
        {
          Tstring ext = s[1];
          supported = (mFilter == _T("*") || mFilter == ext);
        }
        if (!supported)
          continue;
      }
    }
    

    Das Problem ist, dass entgegen anderslautenden Aussagen im Internet, dieses Flag NICHT exklusiv für den Windows Explorer ist sondern auch SHGetFileInfo den Filenamen ohne Extension liefert.

    Leider habe ich keinen Einfluss darauf ob dieses "Hide extensions for known file types" Flag gesetzt ist oder nicht

    Weiss jemand, wie ich unabhängig vom Status dieses Flags an die Extension der Datei komme?

    Herzliche Grüsse
    Walter



  • Hallo zusammen,

    ich habe eine "Lösung" gefunden.

    Im Constructor von MyShellListCtrl lese ich unter HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced das Flag "HideFileExt" aus und speichere den Wert in einer Membervariablen.

    Dann setze ich das Flag in der Registry auf 0.

    In MyShellListCtrl::EnumObjects (...) entferne ich nach dem Filter bei gesetztem Flag die Extension.

    Im Destructor von MyShellListCtrl setze ich das Flag in der Registry wieder auf den alten Zustand.

    Herzliche Grüsse
    Walter


  • Mod

    Jo. Und jedes andere Programm, das zeitgleich läuft fliegt auf die Nase, weil es anderes tut und erwartet.

    Sorry, das ist keine Lösung, das ist Krampf.

    PS: Auch wenn ich keine bessere Lösung habe ist das gewisslich kein Weg.



  • Hallo Martin,

    Jo. Und jedes andere Programm, das zeitgleich läuft fliegt auf die Nase, weil es anderes tut und erwartet.

    Da könntest Du Recht haben. Der Explorer schluckt das aber ohne Murren. In meinem Fall spielen andere Programme aber keine Rolle da immer nur mein Programm läuft (Maschinensteuerung).

    Sorry, das ist keine Lösung, das ist Krampf.

    Deswegen auch Lösung in Anführungszeichen 😉

    Der eigentliche Krampf ist aber eigentlich von MS! Datendarstellung wird in der View (EnumObjects) gehandelt und nicht im Doc (ShellObj).

    So lange ich keine richtige Lösung habe, muss ich wohl oder übel mit diesem Hack leben.

    Herzliche Grüsse
    Walter


  • Mod

    Ichhabe mir noch mal Dein Problem durchgelesen.
    Sag mal: Warum holst Du Dir aus dem PIDL nicht selbst den vollen Dateienamen und bestimmst die Extension selbst?



  • Hallo Martin,

    Warum holst Du Dir aus dem PIDL nicht selbst den vollen Dateienamen und bestimmst die Extension selbst?

    Das war mein erster Ansatz. Ich habe in der MSDN gestöbert und Gegoogelt aber immer nur Infos über DisplayName und Typename gefunden. Ich habe auch verschiedene Kombinationen von Flags für SHGetFileInfo ausprobiert aber diese Funktion liefert weder den vollen Dateinamen noch zuverlässige Infos um ihn zu rekonstruieren.

    Das ganze Shell Interface erschliesst sich mir nicht wirklich und die Dokumentation ist ja auch nicht gerade der "Brüller".

    Wenn Du also weisst wie ich den vollen Dateinamen aus dem PIDL holen kann, dann wäre ich froh über Hinweise.

    Herzliche Grüsse
    Walter


  • Mod

    🕶
    Wieso braucht man dazu eine Funktion?
    http://msdn.microsoft.com/en-us/library/windows/desktop/cc144090(v=vs.85).aspx

    Lies mal. Und dann wirst Du sehen das eine ITEMIDLIST eine normale Struktur ist, die man tasächlich dereferenzieren kann.
    Der letzte Eintrag der liste ist dann der Name mit Deiner Extension.

    Manche Sachen sind gar nicht so mystisch wie man vielleicht denkt....
    🕶



  • Hallo Martin,

    sieht in der Doku ganz einfach aus...

    also ich habe diesen Code aus MCShellListCtrl:

    LPENUMIDLIST enumList = NULL;
    	HRESULT hr = parentFolder->EnumObjects(NULL, mTypes, &enumList);
    
    	if (SUCCEEDED (hr) && enumList != NULL)
    	{
    		LPITEMIDLIST		temp;
    		DWORD				fetched = 1;
    		LPAFX_SHELLITEMINFO item;
    
    		//enumerate the item's PIDLs
    		while (enumList->Next (1, &temp, &fetched) == S_OK && fetched)
    		{
    			LVITEM lvItem;
    			ZeroMemory (&lvItem, sizeof (lvItem));
    
    			//fill in the TV_ITEM structure for this item
    			lvItem.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
    
    			//AddRef the parent folder so it's pointer stays valid
    			parentFolder->AddRef();
    
    			//put the private information in the lParam
    			item = (LPAFX_SHELLITEMINFO)GlobalAlloc (GPTR, sizeof(AFX_SHELLITEMINFO));
    
    			item->pidlRel = temp;
    			item->pidlFQ = mShellManager->ConcatenateItem (parent, temp);
    

    hier müsste doch temp der Pointer auf das letzte Element der IDLIST sein und temp->mkid.abID den Namen der Datei enthalten. Da kommt aber als char betrachtet Müll und als TCHAR betrachtet irgendwas Chinesisches.

    Ich habe keine Ahnung wie ich den Eintrag in abID interpretieren soll.

    Herzliche Grüsse
    Walter


  • Mod



  • Hallo Martin,

    das Dingens ist so alt, dass man es nicht mal mehr kompilieren kann.

    Ich habe aber reingeschaut und einige Funktionen welche ich noch nicht kannte in meinem Code ausprobiert... alles ohne Erfolg.

    Ich gebs auf. Meine Lösung funktioniert für meinen Zweck, wenn ich noch mehr Zeit für Grundlagenforschung verwende, reisst mir mein Boss den Kopf ab.

    Herzliche Grüsse
    Walter



  • Hallo Martin,

    ich konnte es doch nicht lassen und habe gestern Abend zuhause noch ein wenig geforscht 😉

    1.) Die Funktion um an den kompletten Pfad, unabhängig vom Registry Flag "HideFileExt", zu kommen heisst SHGetPathFromIDList (IDList, path).

    In MFCShellListCtrl::EnumObjects muss als IDList item->pidlFQ benutzt werden.

    2.) die Dokumentation für das Shell Interface scheint total veraltet und auf jeden Fall nicht komplett zu sein.
    In SHITEMID, Nomen est omen 😉 steht in abID kein Klartext und cb hat fast immer den Wert 20, ich tippe daher auf einen Hash Schlüssel in irgend eine Systemtabelle.

    Herzliche Grüsse
    Walter


Anmelden zum Antworten