GetMessage loop in neuem std::thread



  • So, mein Problem ist, dass ich eine Memberfunktion "Run()" habe, die einen C++11 thread startet. Die beiden Funktionen sehen erst mal so aus:

    void ezwin::Window::RunThread()
    {
    	ShowWindow(hwnd, iCmdShow);
    
    	while(GetMessage(&msg, 0, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	MessageBox(0, L"EndThread", L"Test", MB_ICONERROR);
    }
    
    void ezwin::Window::Run()
    {
    	winThread = new std::thread(&ezwin::Window::RunThread, this);
    }
    

    Nun wird jedoch der Thread nicht richtig ausgeführt. Wenn ich z.B. in der Main
    die Run Funktion ausführe passiert nichts. Der Thread läuft angeblich aber es erscheint kein Fenster. Wenn ich den Inhalt der RunThread
    Funktion in die Run Funktion packe funktioniert alles wie gewollt. Was mir noch aufgefallen ist, ist dass wenn ich in der Main hinter der Run Funktion noch eine MessageBox packe
    das Fenster erscheint und so lange läuft, wie die MessageBox am leben ist. Schließt man die dann hängt sich auch das Fenster auf.

    Hier nochmal die Main und der Destructor:

    ezwin::Window::~Window()
    {
    	if(winThread) 
    	{
    		if(winThread->joinable()) winThread->join();
    		delete winThread;
    	}
    }
    
    int WINAPI wWinMain(HINSTANCE	 hInstance,
    			        HINSTANCE	 hPrevInstance,
    			        PWSTR		 szCmdLine,
    			        int			 iCmdShow)
    {
    	Window *w = new Window(hInstance, iCmdShow, WndProc);
    	w->Initialize("NurEinTest");
    	MessageBox(NULL, L"StartRun", L"Test", MB_OK);
    	w->Run();
    	MessageBox(NULL, L"AfterRun", L"Test", MB_OK);
    	delete w;
    }
    

    Irgendwelche Ideen wieso's net klappt?



  • Schau dir deinen Code nochmal an. Diese while Schleife, die die Messaages abfängt blockiert das Programm. Deswegen beendet es sich nicht. Bei dir läuft diese while Schleife aber in einem anderen Thread, also wird der Main Thread nach der 2. Messagebox beendet und somit auch dein Thread.

    Lass das mit den verschiedenen Threads einfach und benutze den Mainthread zum verarbeiten der Messages



  • Frolo schrieb:

    Schau dir deinen Code nochmal an. Diese while Schleife, die die Messaages abfängt blockiert das Programm. Deswegen beendet es sich nicht. Bei dir läuft diese while Schleife aber in einem anderen Thread, also wird der Main Thread nach der 2. Messagebox beendet und somit auch dein Thread.

    Lass das mit den verschiedenen Threads einfach und benutze den Mainthread zum verarbeiten der Messages

    Wär schön wenn's so leicht wär. Aber leider ist es nicht so 😞 Bevor der Main Thread beendet wird, wird der Destructor ausgeführt indem der winThread gejoint wird. Dadurch wartet die Main solange bis der winThread beendet wurde.

    std::thread::join() waits for a thread to finish its execution

    Der Prozess des Programms muss dann auch über den TaskManager geschlossen werden weil er eben weiterläuft. Ersetz ich jedoch das ShowWindow und die GetMessage loop durch eine einfache while(1) loop in der immer eine MessageBox erstellt wird läuft dies wieder wunderbar. vorher wurden die MessageBoxen nicht erstellt. Es scheint also, dass GetMessage dem Thread irgendwie Probleme bereitet. Die Frage ist nur wieso. Kann das vllt an dem WndProc liegen? Ich übergebe den WndProc als funcion pointer über den Constructor an die Window Class. dort wird die Adresse dann in den Member function pointer geschrieben und beim Initialize in die WNDCLASSEX. ist da vllt irwo noch ein Denkfehöer?

    ezwin::Window::Window(HINSTANCE hInstance, int iCmdShow, LRESULT (CALLBACK *WndProc)(HWND, UINT, WPARAM, LPARAM))
    {
    	//Convert::ctowc(wcClassName, "MyWindowClass");
    	Convert::ctowc(wcWindowName, "MyWindow");
    	hwnd = 0;
    	ZeroMemory(&msg, sizeof(MSG));
    	ZeroMemory(&wndclass, sizeof(WNDCLASSEX));
    	this->WndProc = WndProc;
    	this->hInstance = hInstance;
    	this->iCmdShow = iCmdShow;
    	winThread = 0;
    
    	dwExStyle = WS_EX_APPWINDOW;
    	dwStyle = WS_OVERLAPPEDWINDOW;
    	winSize.right = 800;
    	winSize.bottom = 600;
    	hwndParent = 0;
    	hMenu = 0;
    	pParam = 0;
    }
    
    LRESULT ezwin::Window::Initialize(const char *winClass)
    {
    	Convert::ctowc(wcClassName, winClass);
    
    	wndclass.style			= CS_HREDRAW | CS_VREDRAW;
    	wndclass.lpfnWndProc	= WndProc;
    	wndclass.cbClsExtra		= 0;
    	wndclass.cbWndExtra		= 0;
    	wndclass.hInstance		= hInstance;
    	wndclass.hIcon			= LoadIcon(0, IDI_APPLICATION);
    	wndclass.hCursor		= LoadCursor(0, IDC_ARROW);
    	wndclass.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);
    	wndclass.lpszMenuName	= 0;
    	wndclass.lpszClassName	= wcClassName;
    	wndclass.cbSize			= sizeof WNDCLASSEX;
    
    	if(!RegisterClassEx(&wndclass))
    	{
    		WCHAR wcszError[32];
    		DWORD dwError = GetLastError();
    		wsprintf(wcszError, L"RegClassError: %d", dwError);
    		MessageBox(0, wcszError, L"REGCLASSERROR", MB_ICONERROR);
    	}
    
    	int cScreenWidth = GetSystemMetrics(SM_CXSCREEN);
    	int cScreenHeight = GetSystemMetrics(SM_CYSCREEN);
    
    	AdjustWindowRectEx(&winSize, dwStyle, hMenu!=0, dwExStyle);
    
    	hwnd = CreateWindowExW(dwExStyle,
    						  wcClassName,
    						  wcWindowName,
    						  dwStyle,
    						  cScreenWidth/2-winSize.right/2,
    						  cScreenHeight/2-winSize.bottom/2,
    						  winSize.right,
    						  winSize.bottom,
    						  hwndParent,
    						  hMenu,
    						  hInstance,
    						  pParam);
    
    	if(!hwnd)
    	{
    		WCHAR wcszError[32];
    		DWORD dwError = GetLastError();
    		wsprintf(wcszError, L"Error: %d", dwError);
    		MessageBox(0, wcszError, L"HWNDNULLERROR", MB_ICONERROR);
    	}
    	return 0;
    }
    

    Aber eigentlich darf da kein Fehler sein, da das Fenster mit der GetMessage loop in dem Main Thread ja normal funktioniert 😕


  • Mod

    Das kann nicht funktionieren. Jede Messageloop liefert nur die Nachrichten von Fenstern, die auch in diesem Thread erzeugt wurden.

    Du erzeugst das Fenster im Main Thread, aber startest einen neuen Thread mit der Messageloop.
    Fenster sind threadafin.



  • Dann werd ich heut ma versuchen alles in den Thread auszulagern oder die Threads
    aus der WinAPI zu benutzen.



  • Die Threading-Funktionen der WinAPI bringen dich auch nicht weiter. Damit sind die Fenster trotzdem immer noch an den Thread gebunden der sie erstellt hat.

    Soweit ich weiss existiert auch wirklich keine Möglichkeit daran etwas zu ändern.
    Wird zumindest hier mehrfach behauptet: http://stackoverflow.com/questions/4347404/changing-a-windows-message-loop-thread

    Ich würde sagen so lange du keinen besseren Grund hast von std::thread wegzugehen, bleib dabei. Ist viel angenehmer zu verwenden als die Win32 threading Funktionen.



  • So hab jetzt alles in den neuen std::thread gepackt und funktioniert wunderbar 😉
    Danke für die Hilfe. Wär allein nie darauf gekommen 😉


Anmelden zum Antworten