Open-/Save-Dialog: Liste zuletzt geöffneter Dateien leeren



  • Hallo Gemeinschaft,

    Ich möchte in den Datei-Öffnen- / -Speichern-Dialogen (Win-Standarddialoge) die Liste zuletzt geöffneter Dateien leeren. Die Liste erscheint, wenn man im Dialog die ComboBox mit dem Dateinamen "downdroppen" lässt.
    Ich arbeite mit BorlandDeveloperStudio2006 und habe mittels WinAPI die Dialoge für eine Anwendung so eingeschränkt, dass der Anwender das Verzeichnis nicht mehr wechseln kann. Nun kann der Anwender das Verzeichnis noch über die zuletzt geöffneten Dateien (indirekt) wechseln. Wird eine Datei aus der Liste zuletzt geöffneter Dateien gewählt, ist beim nächsten Öffnen des Dialog der Ordner der zuletzt mit dem Dialog geöffneten Datei geöffnet.
    => Screenshot der Liste zuletzt geöffneter Dateien (*.jpg auf bilder space.de) 😞
    InitialDir wird zwar vor jeder Anzeige der Dialoge neu gesetzt, aber das scheint den Dialogen egal zu sein...
    Das ist mein Versuch, die Liste zu leeren:

    HANDLE hFileCmb= GetDlgItem(GetParent(OpenDialog->Handle), 0x047C);
    SendMessage(hFileCmb, CB_RESETCONTENT, NULL, NULL);
    

    Leider wird die Liste nicht geleert. Ist OnShow() vielleicht nicht der richtige Zeitpunkt? Wer kann weiterhelfen?

    MfG



  • Also ich würde für das Element "lpfnHook" der Struktur "OPENFILENAME" einen Eventhandler übergeben bei dem ich WM_INITDIALOG abfange und hier die Einträge für die Combobox löschen.
    Das Löschen würde ich auch nicht mit CB_RESETCONTENT, sondern mit CB_GETCOUNT und in einer Schleife mit CB_DELETESTRING durchführen, damit würdest du verhindern, daß eine etwaige Vorauswahl die du über "lpstrFile" getoffen hast aus dem Editfeld der Combobox gelöscht wird.



  • Ich habe mir schon gedacht, dass ich um einen Hook nicht herumkomme. Ich hatte mich dazu bereits informiert und das erstmal nicht gemacht, da es in Borland C++ relativ viel Zusatzaufwand gegenüber der normalen Nutzung von Standard-Dialogen bedeutet. Im Verhältnis zum Nutzen war mir das zuviel. Nun muss ich mich entscheiden: Wenn ich die Liste nicht leere, war der Aufwand die Komponenten zum Verzeichniswechsel auszublenden vergebens - das wäre nur eine halbe Lösung... Ich werde mich daher mal an den Hook wagen.
    Schade dass Borland diese Möglichkeit nicht bietet, bzw. die Benachrichtigungen auf die man standardmäßig reagieren kann (Event-Methoden) so gering gehalten hat. Das ist bestimmt so ein Punkt warum oft gesagt wird, dass die VCL etwas für Einsteiger ist (relativ leicht überschaubar, dafür beschränkt in den Möglichkeiten)!
    Eine Schleife mit CB_DELETESTRING hatte ich bereits getestet:

    while(SendMessage(hFileCmb, CB_DELETESTRING, 0, NULL) > 0)
        ShowDialog(0,1,0, 7,36, 0,0, "Eintrag gelöscht!");       // Funktion ruft eigenes Formular zur Ausgabe von Meldungen auf (vergleichbar mit MsgBox)
    

    Das funktioniert sogar ohne CB_GETCOUNT, da CB_DELETESTRING die Anzahl verbleibender Einträge zurückgibt. 🙂
    Es wurden mit dieser Schleife alle 10 Einträge gelöscht, leider vor WM_INITDIALOG - wenn der Dialog angezeigt wird, sind die Einträge wieder neu drin...
    So, bin dann mal am hooken 😉



  • Ich habe mich belesen und herausbekommen, dass ich einen Hook ohne Dll implementieren kann, solange ich mich in meiner Anwendung bewege (application-defined callback function). Soweit, so gut... Beim Füllen der OPENFILENAME-Struktur bin ich jetzt an der Stelle wo ich einen Zeiger auf meine Hook-Prozedur (OFNHookProc) angeben soll (lpfnHook).

    AnsiString FullFileName= "";
    		OPENFILENAME OpnDlg;
    		OpnDlg.lStructSize= sizeof(OpnDlg);
    		OpnDlg.hwndOwner= FrmMain->Handle;
    //		OpnDlg.hInstance= NULL;													// Handle zu Dialogbox-Template -> ungenutzt, wenn entsprechende Flags nicht gesetzt sind
    		OpnDlg.lpstrFilter= "Textdateien (*.txt)\0*.txt\0\0";
    		OpnDlg.lpstrCustomFilter= NULL;											// 2 Strings -> voreingestellter & zuletzt gewählter Filter
    //		OpnDlg.nMaxCustFilter= NULL;											// ignored if lpstrCustomFilter is NULL
    		OpnDlg.nFilterIndex= 0;													// if zero and lpstrCustomFilter is NULL, first filter in lpstrFilter is used
    		OpnDlg.lpstrFile= &FullFileName[0];
    		OpnDlg.nMaxFile= 1024;
    		OpnDlg.lpstrFileTitle= NULL;											// Puffer für Dateinamen ohne Pfad
    //		OpnDlg.nMaxFileTitle= NULL;												// ignored if lpstrFileTitle is NULL
    		OpnDlg.lpstrInitialDir= &(ExtractFilePath(Application->ExeName) + "Daten")[0];
    		OpnDlg.lpstrTitle= "TextDatei öffnen";
    		OpnDlg.Flags= OFN_DONTADDTORECENT | OFN_ENABLEHOOK | OFN_ENABLESIZING | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NONETWORKBUTTON;
    		OpnDlg.nFileOffset= NULL;
    		OpnDlg.nFileExtension= NULL;
    		OpnDlg.lpstrDefExt= "txt";
    		OpnDlg.lCustData= NULL;
    		OpnDlg.lpfnHook= ...;                                            // <== an dieser Stelle bin ich
    

    Nun habe ich gelesen, wie OFNHookProc prinzipiell auszusehen hat und habe in den private-Bereich des Hauptfenster-Header

    UINT_PTR CALLBACK DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd);
    

    eingefügt ohne die Prozedur in der .cpp auszuführen (also nur den Prototyp angegeben).
    Auch einen Zeiger auf diese Prozedur habe ich dort erstellt:

    UINT_PTR CALLBACK (*pDlgHook)(HWND, UINT, WPARAM, LPARAM);
    

    Dann wollte ich den Zeiger im Konstruktor meiner Anwendung auf die Prozedur setzen

    pDlgHook= &DlgHook;
    

    , um später mit

    <OPENFILENAME>.lpfnHook= pDlgHook;
    

    die Hook-Prozedur dem Dialog zuzuordnen.
    Leider scheitert es schon beim Compilieren an der Stelle

    pDlgHook= &DlgHook;
    

    mit der Fehlermeldung

    Compiler schrieb:

    [C++ Fehler] Main.cpp(119): E2034 Konvertierung von 'unsigned int (__stdcall * (_closure )(void *,unsigned int,unsigned int,long))(void *,unsigned int,unsigned int,long)' nach 'unsigned int (__stdcall *)(void *,unsigned int,unsigned int,long)' nicht möglich

    .
    Wo liegt mein Denkfehler? Wonach muss ich suchen? Ist DlgHook falsch veröffentlicht? Ist der Zeiger auf DlgHook falsch? Oder die Zuweisung? für mich sieht das soweit Alles logisch und richtig aus... 😞

    Danke für Hinweise und Anregungen
    MfG

    Edit: Ich hab' jetzt viel gelesen, über Funktionszeiger und OFNHookProc, Einiges probiert aber nichts wirklich erfolgreich... überall sehen die Beispiele so aus, wie ich es gemacht habe... ich bekomme die Adresse meiner selbstdefinierten Hook-Prozedur nicht an lpfnHook oder einen Funktionszeiger übergeben! Immer bekomme ich die bereits gepostete oder ähnliche Fehlermeldungen vom Compiler. 😞 Kann mir dazu prinzipiell jemand Hinweise geben (zur Compilermeldung oder zum Übergeben der Adresse der Hook-Prozedur)? Danke!



  • Ich habs jetzt grad mal nur für den Standartdialog Fontselection parat, aber mit den Filedialogen sollte es ebenso funktionieren:

    UINT CALLBACK DialogFontSelection_EventHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    
    	switch(message){
    		case WM_INITDIALOG:{
    //			do something here
    			break;
    		}
    	}
    	return 0;
    }
    
    boolean DialogFontSelection_Create(char *headline){
    
    	CHOOSEFONT		cf;
    
    	memset(&cf, 0, sizeof(cf));
    	cf.lStructSize = sizeof(CHOOSEFONT);
    	cf...... = .....;
    	cf...... = .....;
    	cf...... = .....;
    	cf.lpfnHook =  (LPCCHOOKPROC)DialogFontSelection_EventHandler;
    	cf.lpTemplateName = headline;
    	cf...... = .....;
    	cf...... = .....;
    	if(ChooseFont(&cf) != 0){
    		return TRUE;
    	}else{
    		return FALSE;
    	}
    }
    


  • Jepp, Danke für das Beispiel nochmal - nach dem Schema sind auch alle anderen Beispiele im Netz aufgebaut, welche ohne dll auskommen - aber der Compiler des BDS2006 mag es irgendwie nicht oder ich mache irgendeinen dummen Fehler. Hier der aktuelle Aufbau in meinem Programm (die Problemstelle ist markiert, die Fehlermeldungen poste ich unter dem Quelltext):

    Main.h:

    class TFormMain : public TForm
    {
    __published:
        //...
    private:
        //...
        UINT_PTR CALLBACK DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd);
    public:
        //...
    };
    

    Main.cpp:

    void __fastcall TFormMain::MenuLoadFileClick(TObject *Sender)
    {
        //...
        char FullFileName[1024];
        OPENFILENAME OpnDlg;
        OpnDlg.lStructSize= sizeof(OpnDlg);
        OpnDlg.hwndOwner= FrmMain->Handle;
        OpnDlg.hInstance= NULL;                                // Handle zu Dialogbox-Template -> ungenutzt, wenn entsprechende Flags nicht gesetzt sind
        OpnDlg.lpstrFilter= "Textdateien (*.txt)\0*.txt\0\0";
        OpnDlg.lpstrCustomFilter= NULL;                        // 2 Strings -> voreingestellter & zuletzt gewählter Filter
        OpnDlg.nMaxCustFilter= NULL;                           // ignored if lpstrCustomFilter is NULL
        OpnDlg.nFilterIndex= 0;                                // if zero and lpstrCustomFilter is NULL, first filter in lpstrFilter is used
        OpnDlg.lpstrFile= &FullFileName[0];
        OpnDlg.nMaxFile= 1024;
        OpnDlg.lpstrFileTitle= NULL;                           // Puffer für Dateinamen ohne Pfad
        OpnDlg.nMaxFileTitle= NULL;                            // ignored if lpstrFileTitle is NULL
        OpnDlg.lpstrInitialDir= &(ExtractFilePath(Application->ExeName) + "Daten")[0];
        OpnDlg.lpstrTitle= "Textdatei öffnen";
        OpnDlg.Flags= OFN_DONTADDTORECENT | OFN_ENABLEHOOK | OFN_ENABLESIZING | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NONETWORKBUTTON;
        OpnDlg.nFileOffset= NULL;
        OpnDlg.nFileExtension= NULL;
        OpnDlg.lpstrDefExt= "txt";
        OpnDlg.lCustData= NULL;
        OpnDlg.lpfnHook= (LPOFNHOOKPROC)DlgHook;               // => Fehler 1
        OpnDlg.lpfnHook= (LPOFNHOOKPROC)&DlgHook;              // => Fehler 2
        OpnDlg.lpTemplateName= NULL;
        OpnDlg.pvReserved= NULL
        OpnDlg.dwReserved= 0;
        OpnDlg.FlagsEx= NULL;
        //...
    }
    
    //...
    
    UINT_PTR CALLBACK TFormMain::DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd)
    {
    	return(0);
    }
    //------------------------------------------------------------------------------
    

    Fehler 1 schrieb:

    [C++ Fehler] Main.cpp(465): E2235 Elementfunktion muß aufgerufen oder ihre Adresse übernommen werden

    Fehler 2 schrieb:

    [C++ Fehler] Main.cpp(465): E2031 Typumwandlung von 'unsigned int (__stdcall * (_closure )(void *,unsigned int,unsigned int,long))(void *,unsigned int,unsigned int,long)' nach 'unsigned int (__stdcall *)(void *,unsigned int,unsigned int,long)' nicht zulässig

    Das ganze habe ich auch mit einem Funktionszeiger als Zwischenschritt versucht:

    Main.h:

    class TFormMain : public TForm
    {
    __published:
        //...
    private:
        //...
        UINT_PTR CALLBACK DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd);
        UINT_PTR CALLBACK (*pDlgHook)(HWND, UINT, WPARAM, LPARAM);                // Funktionszeiger
    public:
        //...
    };
    

    Main.cpp:

    void __fastcall TFormMain::FormShow(TObject *Sender)
    {
        //...
        pDlgHook= DlgHook;             // => Fehler 1
        pDlgHook= &DlgHook;            // => Fehler 2
        //...
    }
    
    //...
    
    void __fastcall TFormMain::MenuLoadFileClick(TObject *Sender)
    {
        //...
        char FullFileName[1024];
        OPENFILENAME OpnDlg;
        OpnDlg.lStructSize= sizeof(OpnDlg);
        OpnDlg.hwndOwner= FrmMain->Handle;
        OpnDlg.hInstance= NULL;                                // Handle zu Dialogbox-Template -> ungenutzt, wenn entsprechende Flags nicht gesetzt sind
        OpnDlg.lpstrFilter= "Textdateien (*.txt)\0*.txt\0\0";
        OpnDlg.lpstrCustomFilter= NULL;                        // 2 Strings -> voreingestellter & zuletzt gewählter Filter
        OpnDlg.nMaxCustFilter= NULL;                           // ignored if lpstrCustomFilter is NULL
        OpnDlg.nFilterIndex= 0;                                // if zero and lpstrCustomFilter is NULL, first filter in lpstrFilter is used
        OpnDlg.lpstrFile= &FullFileName[0];
        OpnDlg.nMaxFile= 1024;
        OpnDlg.lpstrFileTitle= NULL;                           // Puffer für Dateinamen ohne Pfad
        OpnDlg.nMaxFileTitle= NULL;                            // ignored if lpstrFileTitle is NULL
        OpnDlg.lpstrInitialDir= &(ExtractFilePath(Application->ExeName) + "Daten")[0];
        OpnDlg.lpstrTitle= "Textdatei öffnen";
        OpnDlg.Flags= OFN_DONTADDTORECENT | OFN_ENABLEHOOK | OFN_ENABLESIZING | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NONETWORKBUTTON;
        OpnDlg.nFileOffset= NULL;
        OpnDlg.nFileExtension= NULL;
        OpnDlg.lpstrDefExt= "txt";
        OpnDlg.lCustData= NULL;
        OpnDlg.lpfnHook= (LPOFNHOOKPROC)pDlgHook;
        OpnDlg.lpTemplateName= NULL;
        OpnDlg.pvReserved= NULL
        OpnDlg.dwReserved= 0;
        OpnDlg.FlagsEx= NULL;
        //...
    }
    
    //...
    
    UINT_PTR CALLBACK TFormMain::DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd)
    {
    	return(0);
    }
    //------------------------------------------------------------------------------
    

    Die Compilerfehler bleiben erhalten... Ich denke ich mache irgendwas Grundlegendes falsch, aber wenn im geposteten Quelltext Nichts zu erkennen ist, dann weiß ich auch nicht!
    Vielleicht fällt Jemandem noch Etwas auf!?

    MfG



  • Hm warum setzt du es nicht einfach so um wie ich es dir gepostet habe?



  • Du mußt natürlich für die Hook-Funktionen eine freie Funktion bzw. statische Klassenmethode benutzen...



  • ...... schrieb:

    Hm warum setzt du es nicht einfach so um wie ich es dir gepostet habe?

    Ist nicht persönlich gemeint - ich habe einfach den Gesamtzusammenhang an deinem Beispiel nicht gesehen und den Hook nach meinem Verständnis in meine Anwendung implementiert. 😉

    Th69 schrieb:

    Du mußt natürlich für die Hook-Funktionen eine freie Funktion bzw. statische Klassenmethode benutzen...

    Super, mit static funktionierts, Danke! 👍

    Allerdings ist mir der Zusammenhang nicht ganz klar... wikibooks schreibt (Link):

    Da statische Elemente unabhängig von Instanzen ihrer Klasse sind, existieren sie während der gesamtem Programmlaufzeit. Sie verhalten sich also wie globale Variablen, sind aber (sofern private) nur innerhalb der Klasse sichtbar.

    Warum muss OFNHookProc statisch sein? 😕

    Und da sind wir schon beim nächsten Problem:

    UINT_PTR CALLBACK TFormMain::DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd)
    {
    	if(Msg != WM_INITDIALOG) return(0);
    	PostMessage(hDlg, CDM_HIDECONTROL, 0x0471, NULL);
    	PostMessage(hDlg, CDM_HIDECONTROL, 0x0443, NULL);
    	HANDLE hToolBar= FindWindowEx(hDlg, NULL, "ToolbarWindow32", NULL);
    	if(hToolBar){
    		SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
    		SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
    		SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
    	}
    	return(0);
    }
    //------------------------------------------------------------------------------
    

    Die Hook wird zwar angesprungen und der Inhalt auch vor dem Anzeigen des Dialog exakt einmal (wenn WM_INITDIALOG in Msg steht) durchlaufen (wobei hToolBar leider NULL bleibt?!), aber die angegebenen Controls werden nicht ausgeblendet / gelöscht... Muss ich an dieser Stelle die Nachrichten an den Dialog auf andere Art versenden?

    MfG

    Edit: Hm... also wenn ich Alles richtig gelesen habe, muss ich auf CDN_INITDONE warten, welches in Form einer WM_NOTIFY kommt...

    Edit2: Den richtigen Zeitpunkt um die ComboBox-Liste zu löschen habe ich scheinbar schon gefunden:

    UINT_PTR CALLBACK TFormMain::DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd)
    {
        if(Msg != WM_NOTIFY) return(0);
        NMHEADER* pNMHDR= (NMHEADER*)(lAdd);
        if(pNMHDR->hdr.code != CDN_INITDONE) return(0);
        //...
    }
    

    Jetzt muss ich "nur noch" die passenden Nachrichten an die ComboBox senden, damit die zuletzt verwendeten Dateien nicht mehr zu sehen sind. Und ich muss herausfinden, warum die Controls zum Verzeichniswechsel nicht mehr ausgeblendet / gelöscht werden... Das hatte ich vorher in der OnShow()-(Borland-)Eventmethode mit

    void __fastcall TFormMain::DlgShow(TObject *Sender)
    {
    	HANDLE hDlg= GetParent(Sender == OpenDlg ? OpenDlg->Handle : SaveDlg->Handle);
    	PostMessage(hDlg, CDM_HIDECONTROL, 0x0471, NULL);
    	PostMessage(hDlg, CDM_HIDECONTROL, 0x0443, NULL);
    	HANDLE hToolBar= FindWindowEx(hDlg, NULL, "ToolbarWindow32", NULL);
    	if(hToolBar){
    		SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
    		SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
    		SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
    	}
    }
    

    erreicht, aber den VCL-Standarddialog nutze ich ja nun nichtmehr und habe folglich auch die Borland-Eventmethode nichtmehr zur Verfügung... Das Ausblenden / Löschen kann ich doch hoffentlich auch in der Hook-Prozedur erledigen!?!

    **Edit3:**Komisch, das Handle hat scheinbar nicht gestimmt. Ich habe jetzt die Nachrichten nach erhaltenem CDN_INITDONE an ((LPNMHDR)lParam)->hwndFrom geschickt und plötzlich werden die Controls ausgeblendet (wie vorher im OnShow()). Das verwundert mich deshalb, weil in der Hilfe zu OFNHookProc steht:

    hdlg
    [in] Handle to the child dialog box of the Open or Save As dialog box.

    Das hätte doch eigentlich schon das korrekte Handle sein müssen, oder?
    Jetzt noch die Liste zuletzt verwendeter Dateien leeren...



  • Ohhh nein... viel gelernt, aber Alles umsonst 😞 😞 😞

    UINT_PTR CALLBACK TFormMain::DlgHook(HWND hDlg, UINT Msg, WPARAM wAdd, LPARAM lAdd)
    {
        if(Msg != WM_NOTIFY || ((LPNMHDR)lAdd)->code != CDN_INITDONE) return(0);        // Hook-Prozedur verlassen, wenn es sich nicht um CDN_INITDONE handelt
        HANDLE hChildDialog= ((LPNMHDR)lAdd)->hwndFrom;
        SendMessage(hChildDialog, CDM_HIDECONTROL, 0x0471, NULL);
        SendMessage(hChildDialog, CDM_HIDECONTROL, 0x0443, NULL);
        HANDLE hToolBar= FindWindowEx(hChildDialog, NULL, "ToolbarWindow32", NULL);
        if(hToolBar == NULL) return(0);
        SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
        SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
        SendMessage(hToolBar, TB_DELETEBUTTON, 0, NULL);
        HANDLE hFileCmb= GetDlgItem(hChildDialog, 0x047C);
        if(hFileCmb == NULL) return(0);
        SendMessage(hFileCmb, CB_SHOWDROPDOWN, true, NULL);                             // <= 
        while(SendMessage(hFileCmb, CB_DELETESTRING, 0, NULL) > 0) ;
        return(0);
    }
    //------------------------------------------------------------------------------
    

    Die Einträge in der Liste der zuletzt verwendeten Dateien in der Dateiauswahl-Combobox des Dialog bleibt erhalten!!! Um mit CB_DELETESTRING überhaupt weiter zu kommen muss ich die ComboBox-Liste downdroppen, was zur Laufzeit unschöner Weise für den Anwender sichbar ist... Tja, und wenn die CB_DELETESTRING-Schleife durch ist, sind trotzdem noch die zuletzt verwendeten Dateien in der Liste...! F**K! *kopfschüttel*
    So, nun vermute ich, dass die besagte Liste in einer Art "OnBeforeDropDown"-Ereignis gefüllt wird... kann das sein? wie könnte ich da herankommen???

    Danke an Alle, die meine Romane bis hierhin lesen! 😉

    Edit1: Ich versuche mir mal mittels CB_GETCOMBOBOXINFO ein Handle der Liste zu holen... vielleicht habe ich damit mehr Erfolg...

    Edit2: Ok, von der Liste bekomme ich kein Handle...

    COMBOBOXINFO CmbInfStruct;
    //F SendMessage(hFileCmb, CB_GETCOMBOBOXINFO, NULL, (LPARAM)&CmbInfStruct);		// [C++ Fehler] Main.cpp(2033): E2451 Undefiniertes Symbol 'CB_GETCOMBOBOXINFO'
        GetComboBoxInfo(hFileCmb, &CmbInfStruct);
        HANDLE hDamnList= CmbInfStruct.hwndList;
        if(hDamnList == NULL) return(0);                                               // <= hier wird die Hook-Prozedur verlassen
        SendMessage(hDamnList, LB_RESETCONTENT, NULL, NULL);
    

    Nun habe ich gesehen, dass in COMBOBOXINFO die Koordinaten des DropDown-Button stehen... vielleicht kann ich den ja einfach deaktivieren...!?! 🕶



  • Also, Frage in aller Kürze: Ich möchte die Liste zuletzt geöffneter Dateien in der "Dateiname"-ComboBox eines "Datei öffnen"-Standarddialog leeren oder den entsprechenden DropDown-Button deaktivieren / ausblenden. Ich habe habe zur Verfügung:

    * eine lokale Hook-Prozedur für den Standarddialog
    * das Handle der entsprechenden ComboBox
    * die Koordinaten des DropDown-Button

    Ich kann nicht:

    * die DropDown-Liste mittels CB_RESETCONTENT / LBRESETCONTENT / CB_DELETESTRING / LB_DELETESTRING leeren
    * ein Handle der DropDown-Liste bekommen
    * ein Handle des DropDown-Button bekommen

    Was kann ich tun um mein Ziel zu erreichen?

    MfG



  • Es ist einfach zum Mäuse melken 😡

    Ich habe ein Handle auf das Edit und ein Handle auf die ComboBox:

    HANDLE hFileCB= GetDlgItem(hDlg, 0x047C);
    HANDLE hCmb= (HWND)SendMessage(hFileCB, CBEM_GETCOMBOCONTROL, NULL, NULL);
    if(hCmb)
      SendMessage(hCmb, CB_SHOWDROPDOWN, true, NULL);
    HANDLE hEdit= (HWND)SendMessage(hFileCB, CBEM_GETEDITCONTROL, NULL, NULL);
    if(hEdit)
      SetWindowText(hEdit, "Test");
    

    Ergebnis: Die ComboBox wird sichtbar ausgeklappt und im Edit steht "Test"!

    1.) Warum ist es nicht möglich die ComboBox mit CB_RESETCONTENT komplett zu leeren?

    2.) Wird die ComboBox (Liste zuletzt verwendeter Dateien) jedes Mal beim Ausklappen neu gefüllt? Wie kann ich das verhindern?

    3.) Wie kann ich ein Handle auf den DropDown-Button der ComboBox bekommen / ihn ausblenden / ihn deaktivieren?

    Irgendeine Möglichkeit MUSS es doch geben!? Wer kann helfen?



  • Ich weiss ja nicht zu welcher Zeit der Inhalt der Combobox gefüllt wird. Aber fang doch mal den CBN_DROPDOWN Event ab und lösche die Items genau dann.



  • CBN_DROPDOWN kann ich laut MSDN nicht mit dem Hook abfangen 😞 Das ist ja das Dilemma: mit dem Hook der von MS für OPENFILENAME vorgesehen ist kann ich rein garnichts anfangen! Alles was ich dort machen / abfangen kann, kann ich auch anderweitig erledigen. Auch Mausklicks im Dialog oder einer untergeordneten Komponente werden nicht durch den Hook gereicht, sondern umgehen ihn. Je länger ich mich damit beschäftige, desto mehr empfinde ich den Hook als Programmiererver*rsche!


Log in to reply