Fehler in FileDialog-Aufruf

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.

Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 19.05.2018, 12:48

Hallo, ich habe Probleme einen FileDialog fehlerfrei aufzurufen. Manchmal hängt sich das Programm. Der Fehler tritt nur in der Debug Version auf und das bei GetOpenFileName() und auch bei GetSaveFileName(). Es gehen beim Aufruf auch 104 Byte verloren, einmal 64 Byte und einmal 40 Byte. Irgendwie sehe ich den Fehler nicht.
Es wird mit ASCII - Einstellung unter VS 2017 compiliert.


Hier GetOpenFileName:

Code: Ansicht erweitern :: Alles auswählen

                OPENFILENAME    oOpenFileName;
                char                    _szFile[ 65536 ] = "";
                char                    _szDir[ 256 ];


                ZeroMemory(&oOpenFileName, sizeof(oOpenFileName));

                oOpenFileName.lStructSize = sizeof(oOpenFileName);
                oOpenFileName.hwndOwner = pMainFrame->GetHWnd();
                oOpenFileName.lpstrFile = _szFile;
                oOpenFileName.nMaxFile = sizeof(_szFile);
                oOpenFileName.nFilterIndex = 1;
                oOpenFileName.lpstrFileTitle = NULL;
                oOpenFileName.nMaxFileTitle = 0;
                oOpenFileName.lpstrInitialDir = _szDir;
                oOpenFileName.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ENABLESIZING | OFN_EXPLORER | ( bMultiSelect ? OFN_ALLOWMULTISELECT : 0 );

                strcpy_s( _szFile, &strPathFileName[ 0 ] );
                strcpy_s( _szDir, &strPathFileName.GetPath()[0] );

                if (m_strFilter.GetCount())
                        oOpenFileName.lpstrFilter=&m_strFilter[0];
                else
                        oOpenFileName.lpstrFilter=_T("All Files (*.*)\0*.*\0");


                if (!GetOpenFileName(&oOpenFileName))
                        return false;
 


und hier GetSaveFileName():
Code: Ansicht erweitern :: Alles auswählen

                OPENFILENAME    oOpenFileName;
                char                    _szFile[65536]="";


                ZeroMemory(&oOpenFileName, sizeof(oOpenFileName));

                oOpenFileName.lStructSize = sizeof(oOpenFileName);
                oOpenFileName.hwndOwner = pMainFrame->GetHWnd();
                oOpenFileName.lpstrFile = _szFile;
                oOpenFileName.nMaxFile = sizeof(_szFile);
                oOpenFileName.nFilterIndex = 1;
                oOpenFileName.lpstrFileTitle = NULL;
                oOpenFileName.nMaxFileTitle = 0;
                oOpenFileName.lpstrInitialDir = NULL;
                oOpenFileName.Flags = OFN_PATHMUSTEXIST | OFN_ENABLESIZING;

                strcpy_s(_szFile,&strPathFileName[0]);

                if (m_strFilter.GetCount())
                        oOpenFileName.lpstrFilter=&m_strFilter[0];
                else
                        oOpenFileName.lpstrFilter=_T("All Files (*.*)\0*.*\0");


                if (!GetSaveFileName(&oOpenFileName))
                        return false;
 
Zuletzt geändert von Krishty am 19.05.2018, 14:15, insgesamt 1-mal geändert.
Grund: Code-Tags auf C++ gesetzt
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 19.05.2018, 14:31

Der Fehler steht wahrscheinlich im Zusammenhang mit Visual Leak Detektor. Der ist nur in der Debug - Version drin.
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 19.05.2018, 14:32

Hmmm … gut möglich. Dein Code sieht auf den ersten Blick korrekt aus.

Der einzige Unterschied zu meinem eigenen Code ist OFN_EXPLORER | OFN_ALLOWMULTISELECT. Wofür brauchst du OFN_EXPLORER? Bei mir hat das keine Auswirkungen auf den Dialog; die Beschreibung im MSDN klingt aber danach, dass es Race Conditions auslösen könnte (macht den Dialog zu einem Child des Explorers).

Mein Code zur Vollständigkeit:
Code: Ansicht erweitern :: Alles auswählen

                        // Shows a dialog asking the user for a path to load a file from.
                        //  • “yes” indicates the user has chosen a path which is written to “path”
                        //  • “no” indicates the user having aborted the dialog; “path” is undefined
                        // Example for filters:
                        //     UTF16("Bitmaps (.BMP)\0*.BMP;.DIB\0Text Files (.TXT)\0*.TXT\0")
                        // Applies the default file extension only if the user doesn’t type one.
                        bool askUserForOpenPath(
                                Window * const  toParentWindowIfModalOrNull,
                                UTF16Unit (&    path)[pathLengthLimit],
                                UTF16Unit const filters[],
                                UTF16Unit const defaultExtensionWithoutDotOrNull[]
                        ) {
                                MUST(nullptr == toParentWindowIfModalOrNull || isSameThread_DEBUG(*toParentWindowIfModalOrNull));

                                path[0] = 0; // … or “GetOpenFileNameW()” fails
                                OPENFILENAMEW parameters = {
                                        sizeof parameters,
                                        toParentWindowIfModalOrNull,
                                        nullptr,                         // no template
                                        filters,
                                        nullptr, 0,                      // no customized filters
                                        1,                               // select the first filter
                                        path, UInt4B(CAPACITY_OF(path)),
                                        nullptr, 0,                      // do not provide the stand-alone file name
                                        nullptr,                         // default directory
                                        nullptr,                         // default title bar for the dialog
                                        // Do not let the user type an invalid path.
                                        0x1800,                          // “OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST”
                                        0, 0,                            // do not return a file extension
                                        defaultExtensionWithoutDotOrNull,// default file extension to apply if the user doesn’t type one
                                        0, nullptr, nullptr,             // no hooks
                                        nullptr, 0, 0                    // reserved
                                };

                                return 0 != GetOpenFileNameW(&parameters);
                        }

                        // Shows a dialog asking the user to pick a directory (but no folder like “Control Panel”).
                        //  • “yes” indicates the user has chosen a path which is written to “path”
                        //  • “no” indicates the user having aborted the dialog; “path” is undefined
                        bool askUserForDirectoryPath(
                                Window * const toParentWindowIfModalOrNull,
                                UTF16Unit (&   path)[pathLengthLimit]
                        ) {
                                MUST(nullptr == toParentWindowIfModalOrNull || isSameThread_DEBUG(*toParentWindowIfModalOrNull));

                                UTF16Unit buffer[260]; // title of the selected folder; forced but needless
                                BROWSEINFOW parameters = {
                                        toParentWindowIfModalOrNull,
                                        nullptr,    // start at default path
                                        buffer,
                                        nullptr,    // no title
                                        65,         // “BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS”
                                        nullptr, 0, // no customization
                                        0
                                };
                                if(auto toFolder = SHBrowseForFolderW(&parameters)) {
                                        auto result = SHGetPathFromIDListW(toFolder, path);
                                        ILFree(toFolder);
                                        return 0 != result;
                                }
                                return no;
                        }
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 19.05.2018, 14:52

Danke für Deine schnelle Antwort. Der Fehler tritt auch in der GetSaveFileName() - Funktion auf ( glaube ich zumindest ). Ich habe jetzt OFN_EXPLORER bei GetOpenFileName() raus genommen. Leider tritt der Fehler nur zeitweise auf. Beim ersten Testen ging es, aber wie bereites gesagt tritt der Fehler nicht immer auf. Wäre schön wenn es das wäre. Ich muss es aber über längere Zeit ausprobieren.
Wie auch immer das Testen ausfällt - Danke für deine Hilfsbereitschaft. Leider wird auch noch immer Speicher nicht freigegeben. Mit Google hatte ich den Hinweis auf Visual Leak Detektor gefunden. Ich schaue mal ob es inzwischen eine neuere Version vom VLD gibt.

Edit: Der Fehler tritt immer noch auf.
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 19.05.2018, 15:36

Klingt mir fast nach einer defekten Shell Extension … hast du in dieser Richtung neulich was gemacht (Thumbnail Handlers oder so)?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 19.05.2018, 15:49

Nee, ich habe noch nie was in der Richtung gemacht. Der Fehler ist schon seit mehreren Jahren im Framework, vielleicht schon immer. Ich setze auch meinen Rechner mehrfach im Jahr neu auf um definierte Konfigurationen zu haben. Als Thumbnail Handler habe ich nur VLC Player aktiv. Zumindest ist das der einzige der mir im Moment einfällt.
Es gibt 2 Fehlervarianten. Einmal öffnet das Filedialogfenster nicht und ein anderes Mal öffnet das Fenster, aber beim Zeichnen des Inhalts hängt er sich auf. Das betrifft auch das Zeichnen des Abbruch Buttons ( oder wie der heißt ).
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 19.05.2018, 16:02

… Moment, da ist noch ein Unterschied: Du schreibst einen Dateinamen in die Struktur, sogar wenn du nach einem Pfad fragst, der geöffnet werden soll. Hast du mal versucht, den Dateinamen vorher einfach leer zu lassen? Ich erinnere mich, dass ich da schwer zu findende Fehler hatte (deshalb nullt mein Code auch den ersten Buchstaben des Pfades, bevor GetOpenFileName() aufgerufen wird).

(Ist auch logisch schwer nachvollziehbar – wenn du eh schon einen Dateinamen hast, musst du den User doch nicht noch fragen, oder?)

(Außerdem wird Windows für dich automatisch das zuletzt genutzte Verzeichnis speichern und den Dialog dort beim nächsten Mal wieder starten lassen, wenn du das Verzeichnis leer lässt. Das weißt du vielleicht und möchtest es lieber manuell verwalten. Aber falls nicht, kannst du so wieder Code sparen.)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 19.05.2018, 16:24

Der Fehler tritt auch auf wenn ich einen Leerstring übergebe in File. Die Übergabe macht Sinn, wenn man einen vorgewählten Dateinamen haben möchte. Der Code ist noch aus meinen Anfängen unter Windows. Aber da ist tatsächlich ein Bug, ich trage nämlich den ganzen Dateinamen mitsamt Directory im File ein. File sollte aber nur der eigentlich Dateiname sein. Dieses Feld wird aber nur im Edit Control angezeigt. Dieser Bug ist auch in Visual Studio 2017 unter "{Dateiname} speichern unter ...". Dieser Bug führt aber nicht zum Absturz sondern nur zu einer unübersichtlichen Bedienung.
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 19.05.2018, 22:20

Hat der Application Verifier mal was gesagt?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 20.05.2018, 10:00

Nee, der Application Verifier erzeugt nur eine fast leere Log-Datei. Das Programm stürzt auch nicht direkt ab, sondern es bleibt beim Zeichnen des FileDialogs einfach stehen oder es kommt erst gar nicht zum Zeichnen. Der Fehler tritt wie gesagt nur in der Debug Version auf. Release klappt immer.
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 20.05.2018, 11:24

Wie sieht denn der Call Stack aus, wenn es stehenbleibt?

Hast du daran gedacht, dass das Elternfenster während des Dialogs weiter zeichnen muss (re-entrancy)? Hast du bedacht, dass die WinAPI Exceptions einfach verschluckt, die während des Zeichnens auftreten, und das Programm dadurch in einen inkonsistenten Zustand gelangen kann?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 20.05.2018, 11:47

Ich habe eben 10 Minuten probiert und der Fehler ist nicht aufgetreten. Ich habe aber nix geändert, also muss er noch drin sein. Wenn ich das Programm anhalte, wird beim CallStack nur externer Code ohne CallName angezeigt. Aber das im Callback des Mainframes etwas verkehrt läuft ist plausibel. Ich werde mal sehen ob ich da Messages bekomme.
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 20.05.2018, 11:56

Naja, die Namen für Calls im externen Code bekommst du ja, wenn du Debug-Symbole runterlädst, während der Code dort angehalten hat.

Optionen -> Debugging -> Symbols -> Häkchen beim Microsoft Symbol Server -> Download All Symbols -> warten -> danach Häkchen wieder weg und Optionen wieder schließen. So siehst du dann, wo er hängt. Vielleicht ein Hinweis, warum.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 20.05.2018, 12:34

Wenn das Programm die GetOpenFileName() Funktion aufruft und diesmal gar nicht erst zeichnet kommt unterer CallStack. Die 2 MemoryBereiche die nicht freigegeben werden treten auch in AllocateHeap auf.
FileAufrufError.png
FileAufrufError.png (11.06 KiB) 971-mal betrachtet

Unten der Callstack von den beiden Speicherleaks, wie sie von VLD erzeugt werden:
FileAufrufError2.png
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 20.05.2018, 14:02

RtlpAllocateHeap() bedeutet, dass gerade allokiert wird. Der Heap ist multi-threaded und wird durch Critical Sections synchronisiert. Wenn das Programm dabei stehen bleibt, bedeutet das, dass die Critical Section des Heaps kaputt ist (nicht mehr freigegeben wurde).

Das passiert entweder manuell (indem jemand HeapLock() aufruft und HeapUnlock() vergisst), oder wenn ein Thread während einer Speicheroperation abstürzt.

Meine Vermutung:
  • an komplett anderer Stelle ist dein Heap kaputt
  • wenn du GetOpenFileName() aufrufst, löst das viele Allokationen aus (denn so ein Explorer-Dialog braucht halt ’ne Menge Ressourcen quer durchs System)
  • bei einer dieser Allokationen fällt auf, dass der Heap beschädigt ist, und das Programm rauscht in einen Haltepunkt
  • da der Code da aber gerade innerhalb eines Callbacks ist, verschluckt Windows die Exception
  • … und hinterlässt den Heap im gesperrten Zustand
  • … und hinterlässt zwei Memory Leaks
  • … und die nächste Allokation hängt sich auf oder löst eine weitere Exception aus.
Ruf vor GetOpenFileName() mal HeapValidate(NULL) auf und schau, ob es dir was ausspuckt. Danach füg deine Anwendung auch im Application Verifier hinzu. (Erst danach, weil HeapValidate() und Application Verifier inkompatibel sind.) Erweiter rechts „Basics“ und klick rechts auf „Heaps“ und wähl „Properties“. Mach Haken bei Size und Protect. Save. Wenn du das Programm im Debugger startest, muss sehr weit oben im Debug Output Page heap: pid 0xDA0: page heap enabled stehen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 20.05.2018, 15:09

Im Moment tritt der Fehler wieder nicht auf. Doch ich habe inzwischen eine Fehlermeldung von ApplicationViewer. Sehe ich das richtig das innerhalb von RenderUserChain() meine GUIApplication destruiert wird ? Im Nichtfehlerfall ist der Heap ok, also der von GetProcessHeap().

FileAufrufError3.png
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 20.05.2018, 16:11

~fxGUIApplication … DestroyWindow … FreeLibrary … ja, das sieht so aus.

Was der Application Verifier dort anmerkt ist, dass die DLL, die freigegeben wird, ein Speicherleck hat. Das passiert bei der einen oder anderen Fremdkomponente (Direct3D macht das gern, bzw. Nvidias Grafiktreiber). Im Output des Debuggers müsstest du xxx.dll unloaded direkt vor dieser Meldung sehen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 20.05.2018, 16:48

Im Moment habe ich keine Idee wie ich den Fehler finden soll. Unter ApplicationVerifier scheint es keine entsprechenden Fehler zu geben. Ich habe jetzt die Stackbelastung reduziert in dem szFile von 65536 auf 1024 reduziert habe. Aber es ist unwahrscheinlich das der Stack so knapp ist. Aber auf dem Amiga hatte ich einen ähnlichen Fall. Da war der Stack aber nur 4096 groß ( im Standardfall ).
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 20.05.2018, 16:54

Nein, das dürfte nicht der Fehler sein. Dir steht ein Megabyte zur Verfügung. Du würdest auch ganz andere Fehlermeldungen bekommen.

Lass den Application Verifier von jetzt an standardmäßig eingeschaltet. Früher oder später wird er sich melden.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 20.05.2018, 17:10

Ja, ich werde ihn drinne lassen. Aber jetzt erscheinen keine Memory Leaks mehr im VLD, dafür meldet Visual Studi etliche 144 Byte nicht freigegeben. Für heute mache ich den Rechner aus. Nochmals Danke an Krishty für deine Hilfe. Den AppViewer kannte ich nocht nicht. Von Dir kann man immer was lernen. :)
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 21.05.2018, 08:04

Hier noch ein MemoryLeak in GetOpenFileName(); Vielleicht liegt es ja doch an VLD

https://stackoverflow.com/questions/807 ... ode-vs2010

FileAufrufError4.png
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon gdsWizard » 21.05.2018, 11:48

Eben ist der Fehler unter ApplicationViewer wieder aufgetreten. Ich hatte vor den GetOpenFileName() einen bedingten BreakPoint auf HeapValidate() falls es false liefert. Der Debugger hat nicht angehalten. Das bedeutet das der Heap ok war. ApplicationViewer hat nix in die LogDatei geschrieben. Ich musste ja den DebugMode abbrechen, da der MainThread nicht returned ist.
gdsWizard
Thomas Mittelsdorf
Establishment
 
Beiträge: 233
Registriert: 04.02.2005, 10:12
Wohnort: Meiningen
Benutzertext: www.gamedevstudio.com

Re: Fehler in FileDialog-Aufruf

Beitragvon Krishty » 21.05.2018, 11:56

Dann bin ich total ratlos …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
 
Beiträge: 6561
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: Fehler in FileDialog-Aufruf

Beitragvon Essex20 » 24.05.2018, 18:32

Krishty hat geschrieben:Dann bin ich total ratlos …


Ich bin schockiert! Wirklich!
Benutzeravatar
Essex20
 
Beiträge: 49
Registriert: 18.04.2015, 13:45
Wohnort: Alzey (Rheinhessen)


Zurück zu Programmiersprachen, Quelltext und Bibliotheken

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast