Konsolenanwendung <-> Threads
-
Rundherumgequatsche (lasst es aus wenns euch net interessiert)
Meine kleine Idee die Schriftart in der Konsole zu verändern indem ich das HWND der Konsole finde bringt mich immer tiefer in die WinAPI.Schritt #1: Ich dachte ich kann einfach ins HWND per TextOut schreiben und basta. Stimmt auch, doch sobald ich die Größe des Konsolenfensters verändere ist der Inhalt weg -> auf WM_PAINT kann ich ja leider nicht reagieren. Darauf reagiert die Win-Konsole damit ihren Inhalt neu zu zeichen -> nicht den den ich will. Der Versuch das Resizen der Konsole zu verhindern ist fehlgeschlagen, da Windows keinen Zugriff bietet.
Schritt #2: Na gut, dann ein Child-Window hinein und in das zeichnen wir, das wir die Größe des Child-Windows nicht verändern lassen ist klar. Dumm nur, wenn das Parent in der Größe verändert wird ist auch das Child ungültig -> WM_PAINT -> Inhalt weg.
Hier gehts los:
Frage A) Ist es möglich in einer Konsolenapplikation ein Child-Window zu erstellen, dass sich von seinem "Parent" löst und die Konsole dealloziert? Dann habe ich indirekt ein eigenes Fenster in der Konsole erstellt was direkt leider nicht funktioniert.Frage
Wenn A nicht funktioniert, lasse ich die Leute einfach ein WinAPI-Programm erstellen statt ein Konsolenprogramm und definiere bereits in der Libary die WinMain()-Funktion die schließlich ganz normal die main()-Funktion des Users aufruft. Dann könnte ich in der WinMain auch die Window-Schleife bearbeiten und auf WM_PAINT (viel wichtiger: Auf WM_QUIT) reagieren. Doch dazu muss ich die beiden Sachen gleichzeitig laufen lassen.
Wie? Mit Threads? Wenn ja ist es sicher, dass beide gleichzeitig auf meine Klasse zugreifen könnnen? Kann es da sicher zu keinen Überschneidungen kommen?
MfG SideWinder
-
Da ich absolu kein Plan von der Materie hab, werf ich einfach ein paar Wörter in den Raum:
Mutex
CriticalSection
-
dEUs schrieb:
Da ich absolu kein Plan von der Materie hab, werf ich einfach ein paar Wörter in den Raum:
Mutex
CriticalSectionCriticalSection klingt mir stark nach MFC, was ein Mutex ist weiß ich leider auch nicht, wenigstens gibts dazu was in der WinAPI *mal schlau machen*
MfG SideWinder
-
CriticalSections gibts auch in der WinAPI
-
Also dir geht es eigentlich nur darum, die Schrift in einer Konsole (externe Anwendung?) zu ändern, oder? WM_SETFONT klappt nicht, oder?
Das mit einem extra Thread sollte einfach so gehen: _beginthread(main, 0, NULL); wobei main als void main( void *dummy ) zu definieren ist
-
flenders schrieb:
Also dir geht es eigentlich nur darum, die Schrift in einer Konsole (externe Anwendung?) zu ändern, oder? WM_SETFONT klappt nicht, oder?
Das mit einem extra Thread sollte einfach so gehen: _beginthread(main, 0, NULL); wobei main als void main( void *dummy ) zu definieren ist1. WM_SETFONT - eh wie abfragen? Ich hab in der Konsole keine Messages die ich bekommen kann! Deswegen benötige ich ja das Fenster und ... lest oben weiter ;).
2. Der User soll von meiner Libary eigentlich nichts mitbekommen. Das er jetzt ein Windowsprogramm statt einer Konsolenapplikation erstellt wird ihm egal sein, aber sein Quellcode sollte unberührt bleiben. Sollte also weiterhin:
int main()
int main(int,char**)
int wmain()
int wmain(int,char**)möglich sein - wobei ich schon bei der Überladung Probleme habe, da sie laut Compiler nicht überladen werden dürfen. Aber ich kann ihm ja die CommandLine als globale Variablen zur Verfügung stellen, dann muss er nur diese 2 Schritte machen:
1. Win32-Anwendung erstellen und die Code-Dateien ins Projekt einfügen
2. Eventuell int main(int argc,char** argv) in int main() umändern.
Fertig.MfG SideWinder
-
Du musst WM_SETFONT nicht abfangen, sondern hinsenden -> SendMessage
Zu dem Thread-Problem: Du kannst ja einfach deine Thread-Funktion als void ThreadFunc( void *dummy ) definieren und darin dann main aufrufen - aber argc und argv müsstest du dir so erst selber "basteln", da du bei einer Win32-Anwendung einfach das Ganze als String bekommst
-
oh man. soviel aufwand nur zum ändern der schriftart? programmier mal lieber was sinnvolles.
-
Die "einfachste" und beste Möglichkeit ist dein erster Ansatz. Einfach auf die Konsole malen. Aber du musst WM_PAINT hooken. Das Resizen oder so zu verbieten ist quatsch (und ziemlich gemein).
Such mal nach Windows-Hooks.. denke hier wird schonmal genau beschrieben was du willst: http://www.beesknees.freeserve.co.uk/articles/hooks.html
-
DrGreenthumb schrieb:
Die "einfachste" und beste Möglichkeit ist dein erster Ansatz. Einfach auf die Konsole malen. Aber du musst WM_PAINT hooken. Das Resizen oder so zu verbieten ist quatsch (und ziemlich gemein).
Such mal nach Windows-Hooks.. denke hier wird schonmal genau beschrieben was du willst: http://www.beesknees.freeserve.co.uk/articles/hooks.html
Das dachte ich ja auch, aber ich wusste nicht das man Nachrichten klauen kann :D. Und deswegen wollte ich einfach alles verbieten was WM_PAINT auslösen könnte. Aber wenn man diese Nachrichten abfangen kann. Dann kann ich glatt noch WM_SETFOCUS und WM_KILLFOCUS abfangen, etc.
Eventl. dreh ich das Konzept nochmal um :D.
MfG SideWinder
-
...That's all very well, but how do you intercept a window's message function? This is what window subclassing is all about - using SetWindowLong on a window's GWL_WNDPROC does the job. Figure 5 shows how the new procedure is attached and detached. There are a number of things worth noting about this code...
Also gehts wieder nicht, da wir wie bereits bemerkt SetWindowLong() nicht benützen können.
MfG SideWinder
-
Das mit alles verbieten was WM_PAINT auslösen könnte, hätte dir eh nichts gebracht, da ja z.B. auch ein Fenster, was über die Konsole geschoben wird und nachher wieder weggeschoben WM_PAINT auslöst. Das mit dem verschwinden des Inhalts bei deinem eigenen Child-Window könntest du aber so machen, dass du entweder alles in einen memDC zeichnest und diesen in WM_PAINT einfach draufblitten. Oder du "merkst" dir einfach die Zeilen deiner Konsole und blittest immer alles (am Besten du kombinierst 1 & 2, dann kannst du z.B. auch scrollen einbauen)
-
flenders schrieb:
Das mit alles verbieten was WM_PAINT auslösen könnte, hätte dir eh nichts gebracht, da ja z.B. auch ein Fenster, was über die Konsole geschoben wird und nachher wieder weggeschoben WM_PAINT auslöst. Das mit dem verschwinden des Inhalts bei deinem eigenen Child-Window könntest du aber so machen, dass du entweder alles in einen memDC zeichnest und diesen in WM_PAINT einfach draufblitten. Oder du "merkst" dir einfach die Zeilen deiner Konsole und blittest immer alles (am Besten du kombinierst 1 & 2, dann kannst du z.B. auch scrollen einbauen)
Nein, egal. Ich erstelle nun ein Child-Window in der Konsole in welches gezeichnet wird (fällt dem User nicht auf, da es keine Titelleiste, keinen Rahmen, etc. hat). Ich speichere bei Ausgaben die derzeitigen Formatierungsdaten und den Text selbst in einem std::vector. Sobald mein Child-Fenster WM_PAINT bekommt zeichne ich diese Daten wieder (in der richtigen Reihenfolge versteht sich).
Damit ich die Nachrichten des Childs abfangen kann muss ich natürlich die Messageschleife gleichzeitig mit der main-Funktion machen. Dazu habe ich folgende WinMain bereits in der Libary definiert:
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int nShowCmd) { /* Damals bei CreateThread() benötigt, jetzt nicht mehr SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = con::FALSE; */ _beginthreadex(NULL,0,RealMain,NULL,0,NULL); MSG msg; while(GetMessage(&msg,con::Console.itsConHWnd,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return(0); }
RealMain ruft dann je nachdem main() bzw. wmain() auf. Die Unterstützung für Parameter kommt erst - wird aber höchstwahrscheinlich mit 2 globalen Variablen gelöst werden. Damit muss der User nur die 2 Schritte die ich im anderen Thread beschrieben habe durchführen und kann schon mit meiner Libary arbeiten.
Auf welche Nachrichten muss ich nun eigentlich alles reagieren?
WM_PAINT und WM_DESTROY habe ich bis jetzt - mehr aber auch noch nicht. WM_SIZE wird zur Sicherheit auch noch reinkommen und setzt die Größe des Fensters auf die Konsolengröße - damit passt das Fenster immer schön in die Konsole! Da man ja die Konsolengröße jederzeit abfragen kann ist es auch kein Problem in der GetMessage()-Schleife eine Abfrage einzubauen - wenn ja gleich noch ein SendMessage() mit WM_SIZE hinterher.
Gibts da sonst noch etwas zu beachten?
MfG SideWinder
-
Funktioniert - soweit so gut. Doch wie kann ich bei GetMessage() die Messages eines Child-Fensters bekommen? Muss ich bei "hwnd" das HWND des Child-Fensters übergeben?
Das funktioniert noch nicht so recht :(.
MfG SideWinder
-
Nimm doch einfach NULL - dann holt er sich alle Nachrichten
-
flenders schrieb:
Nimm doch einfach NULL - dann holt er sich alle Nachrichten
Habe ich - aber das Problem ist ich weiß nicht in welchen Thread meine Variable Console gehört.
Das erste Mal benützt wird sie schließlich in main() alsow gehört sie wohl auch zu diesem Thread. Das heißt, dass dieses Fenster in diesem Thread erstellt wird, was wiederrum heißt ich kann in WinMain() gar nicht die richtigen Nachrichten bekommen, weil GetMessage() nur Nachrichten des jetzigen Threads abholen kann.
Oder habe ich da wiedermal etwas übersehen?
MfG SideWinder
-
Bitte vergiss dein Vorhaben - das wird nichts.
-
=== schrieb:
Bitte vergiss dein Vorhaben - das wird nichts.
Danke wie aufmunternd. Ich hoffe dennoch, dass dieses Projekt etwas wird. Sobald es nun endlich funktioniert kann ich es optimieren. Immerhin ist es nur noch ein kleiner Schritt zum funktionsfähgien Programm ;).
MfG SideWinder
-
Durch Logging habe ich nun herausgefunden, das er meine WinMain() erst gar nicht aufruft
Statt dessen ruft er als erstes die Funktion wmain() im vom User definierten Hauptprogramm auf - es ist aber sicher eine Win32-Applikation und keine Konsolenapplikation.
Was habe ich da schon wieder falsch gemacht?
MfG SideWinder
-
Dein main-Überschreiben-Vorhaben ist auch irgendwie daneben. Mach einfach eine Funktion InitSidewindersConsole() die der Benutzer dann einmal nach dem Eintritt in main aufruft und gut.
Und wieso du SetWindowLong nicht verwenden kannst versteh ich nicht.. Du solltest es, wie gesagt, besser mit Hooks machen.. aber wie du meinst.