Schwere Schutzverletzung mittels Scrollbar-Style?
-
Hallöchen,
folgende Situation: Ich hab eine Programm mit mehreren Fenstern, Controls usw. Darunter auch ein Childfenster (allerdings mit eigener registrierter Fensterklasse) mit einem OpenGL-Render-Context und als Style jeweils eine Scrollbar an den Seiten. (Die Scollbars wurden vor dem Erstellen des Render-Context hinzugefügt).
Bisher hat immer alles wunderbar funktioniert, doch neuerdings schließen sich die Fenster scheinbar selbst. Immer wenn ich eine bestimmte Reihnfolge von Buttons drücke, sind plötzlich alle Fenster futsch (per Console hab ich dann erfahren, dass die Fenster die WM_DESTROY Message ausführen, woher immer die kommen mag) aber das Programm läuft noch, keine Fehlermeldung.
Jetzt nach stundenlanger Bugsuche hab ich endlich die Ursache gefunden. In einem der letzten Buttons hab ich den Scrollrange der Scrollbars des OpenGL-Windows verändert. Wenn ich diese Zeilen auskommentiere, funktioniert es wunderbar ohne Probleme.Das ist der Code für die Änderung der Scrollbars für das OpenGL-Fenster:
int bordersize = GetSystemMetrics(SM_CYEDGE); int scrollheight = GetSystemMetrics(SM_CXVSCROLL); int scrollwidth = GetSystemMetrics(SM_CYVSCROLL); RECT rect; GetWindowRect(glwindow.get_hwnd(), &rect); int temp_winsize_y = rect.bottom - rect.top; SCROLLINFO scrollinfo_VERT; scrollinfo_VERT.cbSize = sizeof(SCROLLINFO); //Fill Structure with informations scrollinfo_VERT.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL; scrollinfo_VERT.nMin = 0; scrollinfo_VERT.nMax = header.size_y * 32 + 2*bordersize + scrollheight -1; scrollinfo_VERT.nPage = temp_winsize_y; //Size of Thumbbox SetWindowPos(glwindow.get_hwnd(), HWND_TOP, NULL, NULL, NULL, NULL, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); SetScrollInfo(glwindow.get_hwnd(), SB_VERT, &scrollinfo_VERT, true); GetScrollInfo(glwindow.get_hwnd(), SB_VERT, &scrollinfo_VERT); //Get the real values directly from scrollbarHier ein Bild des Programms: http://derfeind2k.de/daten/testeditor.png <== Das rechte Fenster mit dem Gitter-Muster ist das OpenGL-Fenster.
Die Frage ist, wo ist da die Ursache dafür, dass sich das OpenFL-Fenster automatisch, offenbar durch Änderung der Scrollbars, schließt? Ist da irgendwo eine schwere Verletzung irgendwelcher Speicherstellen oder Rechte zu finden?
Ich hab mal Testweise den Teil der WM_DESTROY Message in der WndProc ausgeklammert, und siehe da, es schließt sich nur noch das OpenGL-Fenster automatisch. (Die anderen werden wohl durch die, dann gesendete PostQuitMessage(0) mitgezogen).
Eventuell sind Scrollbars ja auch bei OpenGL-fähigen Fenstern mit Render-Context verboten? (Erst Scrollbar und dann Render-Context erstellen funktioniert ja, warum sollte dann nicht auch nachträglich die Scrollbars ändern gehen?)Ich wär euch sehr dankbar, wenn ihr da einen Fehler finden könntet oder mir sagen könntet, warum dieser merkwürdige Fehler auftritt. Wenn ihr noch irgendwelche Codeteile braucht, meldet euch nur.
mfg.
Ynnus
-
Kleiner Nachtrag -> Ich hab eben noch herausgefunden, dass dieser Absturz nicht auftritt, wenn man eine Scrollbar unmittelbar vor dem Drücken des Buttons, welcher die Scrollranges verändert, anklickt. Also man muss die Scrollbar immer vorher mindestens einmal kurz angeklickt haben. Dabei ist es egal, ob man die Position ändert oder nicht.
Das ist alles recht verwirrent, warum stürzt das Programm plötzlich nicht mehr ab, wenn man die Scrollbar vorher einmal berührt hat?
(Noch ein Hinweis, vielleicht ist es ja wichig: Nachdem man den Scrollrange geändert hat, ist die Scrollbar irgendwie matt. Also, unter WindowsXP erhellt sich die Scrollleiste ja immer, wenn die Maus sich darüber befindet. Nach dem Resieze des Scrollranges aber bleibt das Erhellen aus. Wenn ich den Scrollrange erneut ändere (Nun durch den Button, der das Programm dann abstürzen lässt), blinkt sie wieder auf. Aber wieder nur solange bis ich erneut resize. Dann wieder nicht, bis ich wieder den Range ändere...)
-
Ich habe zwar eigentlich nicht wirklich einen Ahnung, warum du den Fehler bekommst, aber PostQuitMessage(0) gehört afaik nicht in die WndProc von Child-Windows.
Ansonsten: Ist nPage kleiner nMax? Müsste aber sonst laut Doku entsprechend korrigiert werden.
Und was soll der SetWindowPos-Aufruf? Warum setzt du dort die z-Order neu und gibst stattdessen nicht SWP_NOZORDER mit an?
-
Danke erstmal für die Hinweise, ich werd mein Programm dahingehend optimieren. Leider nützt dies für mein (mittlerweile wirklich sehr nerviges Problem) nicht so viel. Ich habe nun herausgefunden, dass beim letzten Button vor dem vermeidlichen Ändern des Scrollranges zwei UpDownClontrols erstellt werden, und diese irgendwie auch was damit zu tun haben. Lasse ich diese weg, tritt der Fehler nicht auf. Mit ihnen, geht's nicht.
Scheinbar liegt es also an der WM_VSCROLL Message, welche auch von diesen verwendet wird. Denn auch die Scrollbar nutzt diese ja und jeweils einen der beiden ausgeschaltet deaktiviert den Fehler. Komische Sache.Jedenfalls, wenn man die Message komplett dem System überlässt (also auskommentiert), dann tritt der Fehler nicht auf, man kann allerdings dann auch nicht scrollen um das möglichst ausführlich zu testen. (Der Fehler trat manchmal auch erst auf, wenn man wohin scrollte und dann den Button drückte, der die UpDownControls erstellt und die Scrollbargröße ändert).
Das bringt mich jetzt zu einer damit verbundenen Frage. Ich werte die WM_VSCROLL wie folgt aus:
case WM_VSCROLL: //For Scrollbar-Controls if (glwindow.get_hwnd() == hwnd) //Scrollbar of glwindow clicked { glwindow.sb_update(wParam, lParam, SB_VERT); screen.versatz_y = glwindow.sb_get_scrollpos(SB_VERT); } if (tilewindow.get_hwnd() == hwnd) //Scrollbar of glwindow clicked { tilewindow.sb_update(wParam, lParam, SB_VERT); tilescreen.versatz_y = tilewindow.sb_get_scrollpos(SB_VERT); //Invalidate the Tile-Region for redrawing the tile-bitmap RECT rect; rect.left = 0; rect.right = tilewindow.get_size_x(); rect.top = 0; rect.bottom = tilewindow.get_size_y(); InvalidateRect(tilewindow.get_hwnd(), &rect, false); } return 0;Irgendwo hab ich vorhin gelesen, dass jede Message die nicht verarbeitet wird, zum System mittels DefWindowProc() geleitet werden sollte. Hier arbeite ich ja nun nur die ab, welche sich auf dem Fenster tilewindow und glwindow befinden, da ich diese Window-Handle vorher aussortiere und andere garnicht abfrage. Könnte da eventuell der Fehler liegen? Dass ich alle anderen Messages die WM_VSCROLL sind, an die DefWindowProc()-Funktion weiterleiten muss? Oder ist das eher auszuschließen?
//EDIT: Habs gerade getestet, selbst wenn ich bei anderen HWNDs ein DefWindowProc() aufruf einmache ist der Fehler nach wie vor vorhanden... >_>
(Dieser Fehler wird langsam so komplex, es gibt jetzt schon etliche Wege zur Vermeidung, die aber alle irgendwelche programmnotwendigen Teile aussetzen würden, aber keinen Weg zur Beseitigung des Fehlers...)
//EDIT2:
Ich hab jetzt einfach mal die Funktion, mit der ich den Scrollrange verändere, gegen eine andere ausgetauscht. Da muss ich zwar noch etwas optimieren, aber so taucht der Fehler (bis jetzt) scheinbar nicht mehr wieder auf:ALter Code zum Resizen der Scrollranges:
RECT rect; GetWindowRect(hwnd, &rect); int temp_winsize_y = rect.bottom - rect.top; scrollinfo_VERT.cbSize = sizeof(SCROLLINFO); //Fill Structure with informations scrollinfo_VERT.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL; scrollinfo_VERT.nMin = min; scrollinfo_VERT.nMax = max; scrollinfo_VERT.nPage = temp_winsize_y; //Size of Thumbbox SetScrollInfo(hwnd, SB_VERT, &scrollinfo_VERT, true); SetWindowPos(hwnd, HWND_TOP, NULL, NULL, NULL, NULL, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); GetScrollInfo(hwnd, SB_VERT, &scrollinfo_VERT); //Get the real values directly from scrollbarNeuer Code:
SetScrollRange(hwnd, SB_VERT, min, max, true);Ist noch nicht ganz das gleiche, da die Page-Größe noch nicht mitgeändert wird, aber zum Testen muss das herhalten.
Die Frage nun, ist im alten oberen Code irgendwo ein Fehler welcher diesen Absturz begründen würde? Ich würd schon gern mit SerScrollInfo arbeiten, da ich dann ausgewählte Infos übergeben kann. Nur damit gibts ja leider einen Absturz an dieser Stelle.//EDIT3: Bis auf die Zeile mit SetWindowsPos() kann ich alle wieder hinzuschalten, ohne einen Fehler zu erhalten.
Vielleicht kann mir jemand erklären, wie es da zu einem solchen Fehler (selbstständiges Schließen des Fensters) kommen kann, wenn ich ein Child-Fenster mit besagtem OpenGL-Render-Context und 2 Scrollbars mit dieser Zeile "bearbeite": ?SetWindowPos(hwnd, HWND_TOP, NULL, NULL, NULL, NULL, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
-
Ich denke der Fehler dabei ist nur in Verbindung mit dem OpenGL dahinter wirklich zu finden (davon habe ich aber absolut keine Ahnung). Wofür brauchst du das SetWindowPos überhaupt?! Du änderst doch zuvor keine Styles per SetWindowLong o.ä., oder doch? Ist zwar nichts anderes, aber ich würde es lieber so schreiben:
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);