I'm trying to display 3 windows, however it fails to create window 2 of which I am not sure why. It creates the first window and i've done the same for the other two.
Here is the code:
#include <Windows.h>
// Store handles to the main window and application instance globally.
HWND ghMainWnd = 0;
HWND ghSecdWnd = 0;
HWND ghThrdWnd = 0;
HINSTANCE ghAppInst = 0;
//========================================================================================
// WINDOW 1
// Step 1: Define and implement the window procedure.
LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
// Handle left mouse button click message.
case WM_LBUTTONDOWN:
MessageBox(hWnd, "Left Mouse Button Click", "Message", MB_OK);
return 0;
// Handle key down message.
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
if( MessageBox(hWnd, "Are you sure?", "Quit", MB_YESNO) == IDYES )
DestroyWindow(ghMainWnd);
return 0;
// Handle destroy window message.
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
// Forward any other messages we didn't handle to the default window procedure.
return DefWindowProc(hWnd, msg, wParam, lParam);
}
//========================================================================================
// WINDOW 2
//========================================================================================
LRESULT CALLBACK
WndProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
// Handle down arrow pressed.
case WM_KEYDOWN:
if( wParam == VK_DOWN )
MessageBox(hWnd, "Down arrow pressed 2.", "Information", MB_OK);
return 0;
case WM_LBUTTONDOWN:
MessageBox(hWnd, "Window 2", "Window 2", MB_OK);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
//========================================================================================
// WINDOW 3
//========================================================================================
LRESULT CALLBACK
WndProc3(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
// Handle down arrow pressed.
case WM_KEYDOWN:
if( wParam == VK_DOWN )
MessageBox(hWnd, "Down arrow pressed 3.", "Information", MB_OK);
return 0;
case WM_LBUTTONDOWN:
MessageBox(hWnd, "Window 3", "Window 3", MB_OK);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// WinMain: Entry point for windows application.
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR cmdLine, int showCmd)
{
// Save handle to application instance.
ghAppInst = hInstance;
// Step 2: Fill out a WNDCLASS instance.
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ghAppInst;
wc.hIcon = ::LoadIcon(0, IDI_APPLICATION);
wc.hCursor = ::LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "MyWndClassName";
// Window 2
WNDCLASS wc2;
wc2.style = CS_HREDRAW | CS_VREDRAW;
wc2.lpfnWndProc = WndProc2;
wc2.cbClsExtra = 0;
wc2.cbWndExtra = 0;
wc2.hInstance = ghAppInst;
wc.hIcon = ::LoadIcon(0, IDI_APPLICATION);
wc2.hCursor = ::LoadCursor(0, IDC_ARROW);
wc2.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wc2.lpszMenuName = 0;
wc2.lpszClassName = "MyWndClassTwo";
// Window 3
WNDCLASS wc3;
wc3.style = CS_HREDRAW | CS_VREDRAW;
wc3.lpfnWndProc = WndProc3;
wc3.cbClsExtra = 0;
wc3.cbWndExtra = 0;
wc3.hInstance = ghAppInst;
wc3.hIcon = ::LoadIcon(0, IDI_APPLICATION);
wc3.hCursor = ::LoadCursor(0, IDC_ARROW);
wc3.lpszMenuName = 0;
wc3.lpszClassName = "MyWndClassThree";
// Step 3: Register with WNDCLASS instance with windows.
RegisterClass( &wc );
RegisterClass( &wc2 );
RegisterClass( &wc3 );
// Step 4: Create the window, and save the handle in global window handle variable ghMainWnd.
ghMainWnd = ::CreateWindow("MyWndClassName", "Window 1", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 0, 0, 500, 500, 0, 0, ghAppInst, 0);
ghSecdWnd = ::CreateWindow("MyWndClassTwo", "Window 2", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 510, 0, 500, 500, 0, 0, ghAppInst, 0);
ghThrdWnd = ::CreateWindow("MyWndClassThree", "Window 3", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 0, 510, 500, 500, 0, 0, ghAppInst, 0);
if( ghMainWnd == 0 )
{
::MessageBox(0, "Create Window 1 - Failed", 0, 0);
return false;
}
if( ghSecdWnd == 0 )
{
::MessageBox(0, "Create Window 2 - Failed", 0, 0);
return false;
}
if( ghThrdWnd == 0 )
{
::MessageBox(0, "Create Window 3 - Failed", 0, 0);
return false;
}
// Step 5: Show and update the window.
ShowWindow(ghMainWnd, showCmd);
UpdateWindow(ghMainWnd);
ShowWindow(ghSecdWnd, showCmd);
UpdateWindow(ghSecdWnd);
ShowWindow(ghThrdWnd, showCmd);
UpdateWindow(ghThrdWnd);
// Step 6: Enter the message loop and don't quit until a WM_QUIT message is received.
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while( GetMessage(&msg, 0, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Return exit code back to operating system.
return (int)msg.wParam;
}
It doesn't throw any errors, but on the ghSecdWnd == 0 it displays that error message.
There are two problems: The one you're experiencing, and one with window 3.
Calling GetLastError() after creating the second window (but before creating the third) results in "Cannot find the window class.". Looking at the class setup, you've done the following:
wc.hIcon = ::LoadIcon(0, IDI_APPLICATION);
What you actually need is to set the icon of wc2. Even checking the return value of RegisterClass when you register the second class results in an error of "The parameter is incorrect.", indicating a problem with wc2. It's also an earlier location in your code to catch the error, which is always a good thing.
Secondly, there's a problem with the third window. You haven't set the background brush on it. Add this line to the wc3 setup:
wc3.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
You should always check the documentation to find out what functions do when they fail and take appropriate action. For example, if CreateWindow fails, the return value is NULL, and you can call GetLastError to get more info. You should do this on a per-function basis. Here's an example with the two main functions for Window 2. Keep in mind that others, such as GetStockObject, can fail as well.
if (!RegisterClass(&wc2)) { //returns 0 if failed
std::cout << "Failed to register class: ";
std::cout << GetLastError() << '\n'; //or however you want to show it
}
if (!(ghSecdWnd = CreateWindow( /*...*/)) { //or ghSecdWnd = ...; if (!ghSecdWnd)
std::cout << "Failed to create window: ";
std::cout << GetLastError() << '\n'; //look at FormatMessage for a message
}
First, looking at RegisterClass, you see under Return value that it returns 0 on failure and states that you can call GetLastError() for extended error information, so I output that. CreateWindow says the same, but it's NULL instead because HWND is a pointer. You can take the error codes you get and check them against the MSDN System Error Codes article, or use FormatMessage with FORMAT_MESSAGE_FROM_SYSTEM to do that for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With