Wie verhindere ich, dass Windows blockiert Programm bei einem Fenster ziehen oder die Menü-Taste wird gedrückt?
Ich bin Neuling mit Win32, und ich verfolgt haben ein problem (wenn es aufgerufen werden kann, ein problem überhaupt) mit Windows blockiert Ihren Programm-Ablauf während der Veranstaltung, wenn ein Benutzer greift der Titelleiste des Fensters und zieht es auf den Bildschirm.
Ich habe keinen legitimen Grund, um dieses problem zu lösen, außer dass es mich stört. Ein paar Möglichkeiten, den Rahmen entfernen ganz, aber es scheint eine unbequeme hack. Einige Spiele (single player) nicht finden, das ein problem überhaupt. Ich habe gelesen, Sie jedoch, dass multiplayer-Spiele könnten Probleme auftreten, wenn das Programm einfriert, da es erwartet, dass die kontinuierliche Fluss von Informationen und können überwältigt werden, nachdem eine solche Verzögerung.
Ich habe versucht, das hinzufügen dieser zu meinem WindowProc
switch (uMsg)
{
case WM_SYSCOMMAND:
if (wParam == SC_CLOSE)
PostQuitMessage(0);
return 0;
...
...
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
- Und dies scheint ein quick hack, außer dass ich beim mousedown-über das schließen-Symbol kann ich ziehen Sie die Maus Weg und gehen lassen, ohne Sie schließen das Programm, und während dieser Zeit, wenn das schließen-Symbol gedrückt wird, wird das Programm wieder gesperrt wird.
Außerdem, ich weiß nicht, wie Sie manuell fügen Sie den code notwendig, um das Fenster zu verschieben, wenn der Benutzer klickt auf die Titelleiste und ziehen die Maus. Für den Anfang ich weiss nicht, welche uMsg
's und wParam
's zu handhaben.
Meine Frage ist dann, wie kann ich das unterbinden blockiert während der Fall, wenn der Benutzer klickt unten die Schaltfläche beenden (oder minimieren/maximieren-buttons), während noch die Behandlung des Falles, wenn die Maus geklickt wird, und veröffentlicht, über die Schaltfläche, und wie kann ich dem Benutzer erlauben, zu verschieben, ziehen Sie das Fenster, ohne es blockiert das Programm (oder was für eine Nachricht wird gesendet, wenn die Titelleiste angeklickt wird, ohne dass es eine Schaltfläche oder Menü)?
Ich bin erstellen Sie das Fenster mit WS_SYSMENU | WS_MINIMIZEBOX
.
Möchte ich noch das Programm zu reagieren, minimieren, maximieren und beenden Befehle.
Wenn multi-threading kann es beheben, dann ist das interessant, aber ich Frage mich, ob ich bekommen kann es arbeiten auf single-core-Prozessoren. Und ich habe gelesen, über die Haken, aber auf der MSDN-Seite ist immer noch schwer für mich zu interpretieren.
- durch
program is blocked
ich denke, du meinst, Sie erhalten nicht alle windows-Meldungen, was genau meinst du mitit expects continuous flow of information
? erwarten Sie, dass windows-Meldungen,WM_TIMER
Nachrichten, info aus einem Hafen, ...? - Es ist nicht blockiert, Sie haben lediglich ein problem mit der Maus erfassen. Vermeiden Sie es, durch abfangen der Art von Nachrichten, die Notwendigkeit, eine Maus erfassen, um richtig zu arbeiten. Mit dem Spy++ - Dienstprogramm ist ein guter Weg, um zu sehen, diese Nachrichten und wissen, welche Sie wollen, selbst zu behandeln.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Warum Ist Meine App Einfrieren?—Eine Einführung in Nachricht Loops & Threads
Dieses Phänomen nicht isoliert auf eine bestimmte Nachricht. Es ist eine grundlegende Eigenschaft des Windows-message-loop): wenn eine Nachricht verarbeitet wird, werden keine anderen Nachrichten verarbeitet werden können, zur gleichen Zeit. Es ist nicht exakt umgesetzt, aber Sie können denken, es als eine Warteschlange, wo die app zieht sich die Nachrichten aus der Warteschlange zu verarbeiten in der umgekehrten Reihenfolge, in der Sie eingefügt werden.
Daher, die Ausgaben zu lange die Bearbeitung alle Nachricht auszusetzen, die Verarbeitung von anderen Nachrichten, effektiv einfrieren Ihrer Anwendung (weil es nicht verarbeiten kann jedem Eingang). Der einzige Weg, dieses problem zu lösen, ist die offensichtliche ein: verbringen Sie nicht zu lange die Verarbeitung einer Nachricht.
Oft bedeutet das, dass die übertragung der Verarbeitung zu einem hintergrund-thread. Werden Sie noch brauchen, um alle Nachrichten auf dem main-thread, und der hintergrund-worker-threads melden müssen zurück an die main-Methode, wenn Sie fertig sind. Alle Interaktionen mit der GUI passieren muss, um auf einem einzigen thread, und das ist fast immer die Haupt-thread der Anwendung (das ist, warum es wird Häufig als der UI-thread).
(Und zu beantworten, eine Beanstandung in deiner Frage, ja, Sie können Sie bedienen mehrere threads auf Prozessor-Maschinen. Werden Sie nicht unbedingt finden Sie alle performance-Verbesserungen, aber es wird die Benutzeroberfläche schneller reagieren. Die Logik hier ist, dass ein thread kann nur eine Sache zu einer Zeit, aber ein Prozessor kann wechseln zwischen threads, sehr schnell, effektiv zu simulieren, dabei mehr als eine Sache zu einer Zeit.)
Weitere nützliche Informationen erhalten Sie hier in diesem MSDN-Artikel: Die Verhütung bleibt in Windows-Anwendungen
Besonderen Fällen: Modal Event Processing Loops
Bestimmte Fenster-Operationen auf Windows sind modal Operationen. Modal ist ein häufiges Wort in computing, bezieht sich im Grunde auf das sperren der Benutzer in einem bestimmten Modus, wo Sie nicht etwas anderes tun, bis Sie Sie ändern (D. H. aus) - Modi. Wenn ein modales Betrieb wird begonnen, eine eigene, neue message-processing loop gesponnen und message-handling geschieht es (anstatt Ihre main-message-loop) für die Dauer des Modus. Gängige Beispiele für diese modalen Operationen lassen sich per drag-and-drop, Fenster Größenänderung, und message-Boxen.
Bedenkt man hier das Beispiel der Anpassung der Fenstergröße, Ihr Fenster erhält eine
WM_NCLBUTTONDOWN
Nachricht, die Sie anDefWindowProc
für Standard-Verarbeitung.DefWindowProc
zahlen darauf hin, dass der Benutzer beabsichtigt zu starten, eine Bewegung oder Größenänderung, und trat ein verschieben/sizing message-loop befindet sich irgendwo tief in den Eingeweiden der Windows-eigenen code. So, Ihrer Anwendung (message-loop nicht mehr ausgeführt wird, weil Sie eingegeben haben, in eine neue verschieben/sizing-Modus.Windows läuft diese Bewegung/sizing-Schleife solange der Benutzer interaktiv bewegen/Dimensionierung der Fenster. Er tut dies so, dass es zum abfangen der Maus-Nachrichten und verarbeiten Sie entsprechend. Wenn der Umzug/sizing-operation abgeschlossen wird (z.B., wenn der Benutzer die Maustaste loslässt, oder drückt die Esc - Taste), wird die Steuerung zurück zu dem code der Anwendung.
Es ist darauf hinzuweisen, dass Sie sind darauf hingewiesen, dass diese Modusänderung erfolgt ist über die
WM_ENTERSIZEMOVE
- Meldung; die entsprechendenWM_EXITSIZEMOVE
- Meldung zeigt an, dass der modal-Ereignis-Verarbeitung der Schleife beendet. Das ermöglicht Ihnen, zu erstellen, einen timer, der weiterhin generierenWM_TIMER
Nachrichten, die von der Anwendung verarbeitet werden können. Die tatsächlichen details, wie diese implementiert ist, sind relativ unwichtig, aber die kurze Erklärung ist, dassDefWindowProc
weiter VersandWM_TIMER
Nachrichten an Ihre Anwendung innerhalb Ihrer eigenen modal event processing loop. Verwenden Sie dieSetTimer
- Funktion zum erstellen eines Timers in Reaktion auf dieWM_ENTERSIZEMOVE
Nachricht, und dieKillTimer
- Funktion zu zerstören, es in Reaktion auf dieWM_EXITSIZEMOVE
Nachricht.Ich nur hinweisen, der Vollständigkeit halber, obwohl. In den meisten Windows-Anwendungen, die ich geschrieben habe, habe ich nie gebraucht, das zu tun.
So, Was Ist Falsch An Meinem Code?
Abgesehen von all dem, das Verhalten, das Sie beschreiben, in Frage zu stellen, sind ungewöhnlich. Wenn Sie erstellen eines neuen, leeren Win32-Anwendung mithilfe der Visual Studio-Vorlage, die ich bezweifle, dass Sie in der Lage sein zu replizieren, dieses Verhalten. Ohne zu sehen, den rest Ihrer Fenster-Prozedur, kann ich nicht sagen, wenn Sie die Blockierung auf alle Nachrichten (wie oben beschrieben), aber der Teil, den ich kann sehen in der Frage ist falsch. Sie müssen immer nennen
DefWindowProc
für Nachrichten, die Sie nicht explizit Prozess selbst.In diesem Fall, Sie könnten getäuscht werden und denken, dass Sie tun, aber
WM_SYSCOMMAND
können sehr viele verschiedene Werte für diewParam
. Sie behandeln nur eine derer, dieSC_CLOSE
. Alle anderen bekommen nur ignoriert, weil Siereturn 0
. Das schließt alle Fenster verschieben und Größe ändern-Funktionalität (z.B.SC_MOVE
,SC_SIZE
,SC_MINIMIZE
,SC_RESTORE
,SC_MAXIMIZE
, etc. etc.).Und es gibt wirklich keinen guten Grund zu behandeln
WM_SYSCOMMAND
dich; lassDefWindowProc
übernehmen das für Sie. Die einzige Zeit, die Sie brauchen, um zu behandelnWM_SYSCOMMAND
ist, wenn der von Ihnen hinzugefügten benutzerdefinierten Elemente auf das Menü Fenster, und selbst dann, sollten Sie passieren jeden Befehl, die Sie nicht erkennen, aufDefWindowProc
.Einem einfachen window-Prozedur sollte so Aussehen:
Ist es auch möglich, dass die Nachricht Schleife ist falsch. Die idiomatischen Win32-message-loop (befindet sich in der Nähe der Unterseite Ihres
WinMain
- Funktion) sieht wie folgt aus:Brauchen Sie keine Haken jeglicher Art. In der MSDN-Dokumentation an, diese ist sehr gut, aber du hast Recht: Sie sind kompliziert. Bleiben Sie Weg, bis Sie ein besseres Verständnis für die Win32-Programmierung Modell. Es ist ein seltener Fall in der Tat, wo Sie müssen die Funktionalität, die von einem Haken.
Du kann Verwendung mehrerer threads auf einem single-core-Prozessor. Wäre die Leistung besser auf multi-core Systeme, aber das sollte nicht verhindern, dass Sie vom schreiben von Multithread-Anwendungen. Jedenfalls, go for it.
Durch den Druck werden alle Nachrichten, die
WindowProc
es erscheintWM_NCLBUTTONDOWN
gesendet Letzte vor dem block Auftritt. Sie könnten überprüfen Position der Maus, wenn das Ereignis Eintritt, aber es scheint eine unbequeme Lösung für ein einfaches problem.