Probleme mit CreateWindow



  • Moin,
    ich habe mich in den letzten Tagen mal ein bisschen in das Thema mit dem CreateWindow Befehl eingearbeitet. Dabei habe ich, bevor das Fenster kreiert wird, den Befehl assert(RegisterClass(); eingebaut. Insgesamt sieht der Code nun so aus:

    #include <Windows.h>
    #include <cassert>
    
    LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    	switch (uMsg) {
    	case WM_CLOSE:
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    
    	HWND hWnd;
    	WNDCLASS wc;
    	MSG msg;
    	
    	wc.style = CS_HREDRAW | CS_VREDRAW;
    	wc.lpfnWndProc = MessageHandler; 
    	wc.cbClsExtra = 0;
    	wc.hInstance = hInstance;
    	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	wc.lpszMenuName = NULL;
    	wc.lpszClassName = (LPCWSTR)"WINAPITest";
    
    	assert(RegisterClass(&wc));
    
    	hWnd = CreateWindow((LPCWSTR)"WINAPITest", (LPCWSTR)"WinAPI fenster erstellen", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, 0, 0, hInstance, 0);
    	
    	ShowWindow(hWnd, nCmdShow);
    	SetForegroundWindow(hWnd);
    	SetFocus(hWnd);
    	UpdateWindow(hWnd);
    
    	while (true) {
    		BOOL result = GetMessage(&msg, 0, 0, 0);
    		if (result > 0) {
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    		else {
    			return result;
    		}
    	}
    }
    

    Das Erste, was mir nun hier schon komisch vorkam, war, dass das WinMain grüne unterstrichen ist. Dasselbe auch bei (LPCWSTR)"WINAPITest" und dem CreateWindow an sich.

    Woran liegt das? Hab ich etwas nicht beachtet?

    Des Weiteren bekam ich dann beim Ausführen des Programms eine Fehlermeldung:

    Assertion failed!
    Program: ...ser\source\repos\Window Test\Debug\Window Test.exe
    File: C:\Users\User\source\repos\Windows Tes...\Window Test.cpp
    Line: 31
    Expression: RegisterClass(&wc)
    For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts
    (Press Retry to debug the application - JIT must be enable)

    Was hat mir diese Fehlermeldung zu sagen und was sollte ich nun machen?

    Im Voraus Danke und Grüße
    Jannis



  • Es ist nie gut, den Compiler zu belügen. Deine Zeichenketten sind jeweils const char*, durch die Casts sagst du allerdings, dass sie vom Typ const wchar_t* seien. Also alle Casts rausnehmen und durch das TEXT-Makro ersetzen.

    Zum Beispiel hier:

    wc.lpszClassName = (LPCWSTR)"WINAPITest";
    
    // ->
    
    wc.lpszClassName = TEXT("WINAPITest");
    

    Für alle Konfigurationen, in denen UNICODE definiert ist, wird dies für den Compiler L"WINAPITest", sonst "WINAPITest".

    Funktionsaufrufe gehören normalerweise nicht in ein assert (es sei denn, es ist wirklich so gewollt), da dieser Aufruf so nur in Debugbuilds ausgeführt wird.
    RegisterClass muss allerdings immer aufgerufen werden.

    assert(RegisterClass(&wc));
    
    // ->
    
    if(!RegisterClass(&wc))
    {
      // evtl. eine Meldung ausgeben und abbrechen
    
      // Edit: Eine Meldung könnte dann mit einem MessageBox-Aufruf so aussehen:
      MessageBox(nullptr, TEXT("Die Fensterklasse konnte nicht registriert werden"), TEXT("Fehler"), MB_OK|MB_ICONERROR);
      // oder einen anderen Wert möglichst ungleich 0, 0 bedeutet bei der Rückgabe
      // aus main oder WinMain "kein Fehler"
      return 1;
    }
    


  • @yahendrik sagte in Probleme mit CreateWindow:

    Zum Beispiel hier:
    wc.lpszClassName = (LPCWSTR)"WINAPITest";

    // ->

    wc.lpszClassName = TEXT("WINAPITest");

    Das klappt einwandfrei. Vielen Dank!

    Nun habe ich dann das assert(RegisterClass(&wc)); ersetzt.
    Das ist nun der Code:

    #include <Windows.h>
    #include <cassert>
    
    
    LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    	switch (uMsg) {
    	case WM_CLOSE:
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    
    	HWND hWnd;
    	WNDCLASS wc;
    	MSG msg;
    	
    	wc.style = CS_HREDRAW | CS_VREDRAW;
    	wc.lpfnWndProc = MessageHandler; 
    	wc.cbClsExtra = 0;
    	wc.hInstance = hInstance;
    	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	wc.lpszMenuName = NULL;
    	wc.lpszClassName = TEXT("WINAPITest");
    
    	if (!RegisterClass(&wc))
    	{
    		
    		MessageBox(NULL, TEXT("ERROR!"), TEXT("Error"), MB_OK | MB_ICONERROR);
    
    		return 1;
    	}
    
    	hWnd = CreateWindow(TEXT("WINAPITest"), TEXT("WinAPI fenster erstellen"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, 0, 0, hInstance, 0);
    	
    	ShowWindow(hWnd, nCmdShow);
    	SetForegroundWindow(hWnd);
    	SetFocus(hWnd);
    	UpdateWindow(hWnd);
    
    	while (true) {
    		BOOL result = GetMessage(&msg, 0, 0, 0);
    		if (result > 0) {
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    		else {
    			return result;
    		}
    
    	}
    
    }
    

    Das klappt soweit auch. Allerdings bekomme ich nun beim Ausführen immer nur das Fenster angezeigt:

    MessageBox(NULL, TEXT("ERROR!"), TEXT("Error"), MB_OK | MB_ICONERROR);
    Ich wollte eigentlich das ich trotzalledem ich das selbst kreirte Fenster engezigt bekomme. Also habe ich es dann so gemacht:

    if (!RegisterClass(&wc))
    	{
    		
    		hWnd = CreateWindow(TEXT("WINAPITest"), TEXT("WinAPI fenster erstellen"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, 0, 0, hInstance, 0);
    
    		Sleep(10000);
    
    		return 1;
    	}
    

    Dann wird das Programm zwar erfolgreich ausgeführt und die Leiste unten wird orange, mir wird allerdings nichts angezeigt. Nach 10sek wird das ausgeführte Programm wieder beendet.

    Hab ich irgendwas falsch gemacht? Oder es nicht richtig verstanden?



  • Der Ablauf sieht so aus:

    Fensterklasse registrieren, bei Fehlschlag abbrechen
    Fenster dieser Klasse erstellen (+ bei Fehlschlag abbrechen)
    Nachrichtenschleife betreten
    

    Wenn das Registrieren fehlschlägt, wird CreateWindow immer scheitern. Und das ist die Frage, warum RegisterClass fehlschlägt.

    Ahh jetzt sehe ich es:

    typedef struct tagWNDCLASSA {
    		UINT        style;
    		WNDPROC     lpfnWndProc;
    		int         cbClsExtra;
    		int         cbWndExtra;
    		HINSTANCE   hInstance;
    		HICON       hIcon;
    		HCURSOR     hCursor;
    		HBRUSH      hbrBackground;
    		LPCSTR      lpszMenuName;
    		LPCSTR      lpszClassName;
    	} WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;
    

    So ist die WNDCLASSA aufgebaut: 10 Member. Du initialisierst jedoch nur 9 (cbWndExtra nicht).

    Das Einfachste wäre:

    WNDCLASS wc = { }; // alle Member mit 0 initialisieren
    

    Dann müssen auch nur die nötigen Werte (also alle ungleich 0) zugewiesen werden.



  • Ohja, jetzt geht es.
    Vielen vielen Dank!!


Anmelden zum Antworten