Reputation: 71
I've got a simple WIN3API application, It was working completely at first, when I decided to do a code clean-up by adding comments and spaces to make the code more readable due for myself so I could easily add more functionality, next thing I know the code does not work. When the main function runs the 'Mainhwnd' returns 'NULL' and closes, I assumed that it might've been the class registering although it does not seem to be the problem, any help would be utmost appreciated! Thanks, Here's a code snippet:
int main(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
const wchar_t MainWndClass[] = L"MainWndClass"; // Creating And Registering Main Class
WNDCLASS MainClass = { };
MainClass.lpfnWndProc = WindowProc;
MainClass.hInstance = hInstance;
MainClass.lpszClassName = MainWndClass;
if (!RegisterClass(&MainClass))
{
MessageBox(NULL, L"Error Registering Window Class", L"Error Registering Window", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
Mainhwnd = CreateWindowEx
(
0, // Optional window styles.
MainWndClass, // Window class
L"Main Wnd", // Window text
WS_VISIBLE, // Window style
CW_USEDEFAULT, // XPos
CW_USEDEFAULT, // YPos
MainWindWidth, // Width
MainWindHeight, // Height
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (Mainhwnd == NULL) // Quit If Error
{
MessageBox(NULL, L"Error Creating Window; Window Handle Is NULL", L"Error Creating Window", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
Full Code
// Includes
#include <iostream>
#include <windows.h>
// Definitions
#define BUTTON_ONE_ID 0001
#define BUTTON_TWO_ID 0002
#define BUTTON_THREE_ID 0003
#define BUTTON_FOUR_ID 0004
#ifndef UNICODE
#define UNICODE
#endif
// Global Variables
HWND Mainhwnd;
HMENU hMenu;
HWND ButtonOne;
HWND ButtonTwo;
HWND ButtonThree;
HWND ButtonFour;
INT MainWindWidth = 800;
INT MainWindHeight = 600;
INT ButtonWidth = MainWindWidth/4;
INT ButtonHeight = 100;
// Prototypes
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void AddMenus(HWND);
void AddControls(HWND);
// Entry Point
int main(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
const wchar_t MainWndClass[] = L"MainWndClass"; // Creating And Registering Main Class
WNDCLASS MainClass = { };
MainClass.lpfnWndProc = WindowProc;
MainClass.hInstance = hInstance;
MainClass.lpszClassName = MainWndClass;
if (!RegisterClass(&MainClass))
{
MessageBox(NULL, L"Error Registering Window Class", L"Error Registering Window", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
Mainhwnd = CreateWindowEx
(
0, // Optional window styles.
MainWndClass, // Window class
L"Main Wnd", // Window text
WS_VISIBLE, // Window style
CW_USEDEFAULT, // XPos
CW_USEDEFAULT, // YPos
MainWindWidth, // Width
MainWindHeight, // Height
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (Mainhwnd == NULL) // Quit If Error
{
MessageBox(NULL, L"Error Creating Window; Window Handle Is NULL", L"Error Creating Window", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
ShowWindow(Mainhwnd, nCmdShow); // Show Window
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// Create Window Procedure
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (wParam)
{
case BUTTON_ONE_ID:
std::cout << "B1" << std::endl;
return 0;
case BUTTON_TWO_ID:
std::cout << "B2" << std::endl;
return 0;
case BUTTON_THREE_ID:
std::cout << "B3" << std::endl;
return 0;
case BUTTON_FOUR_ID:
std::cout << "B4" << std::endl;
return 0;
}
return 0;
case WM_CREATE:
AddMenus(hwnd);
AddControls(hwnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 2));
EndPaint(hwnd, &ps);
}
default:
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void AddMenus(HWND hwnd) // Add Menus Function
{
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
SetMenu(hwnd, hMenu);
}
void AddControls(HWND hwnd) // Add Controls Function
{
ButtonOne = CreateWindowW
(
L"Button", L"Button1", WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_ONE_ID, NULL, NULL
);
ButtonTwo = CreateWindowW
(
L"Button", L"Button2", WS_CHILD | WS_VISIBLE | WS_BORDER, ButtonWidth, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_TWO_ID, NULL, NULL
);
ButtonThree = CreateWindowW
(
L"Button", L"Button3", WS_CHILD | WS_VISIBLE | WS_BORDER, ButtonWidth * 2, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_THREE_ID, NULL, NULL
);
ButtonFour = CreateWindowW
(
L"Button", L"Button4", WS_CHILD | WS_VISIBLE | WS_BORDER, ButtonWidth * 3, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_FOUR_ID, NULL, NULL
);
}
Upvotes: 1
Views: 1693
Reputation: 71
Fixed Working Code:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (wParam)
{
case BUTTON_ONE_ID:
std::cout << "B1" << std::endl;
break;
case BUTTON_TWO_ID:
std::cout << "B2" << std::endl;
break;
case BUTTON_THREE_ID:
std::cout << "B3" << std::endl;
break;
case BUTTON_FOUR_ID:
std::cout << "B4" << std::endl;
break;
}
break;
case WM_CREATE:
AddMenus(hwnd);
AddControls(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 2));
EndPaint(hwnd, &ps);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void AddMenus(HWND hwnd) // Add Menus Function
{
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
SetMenu(hwnd, hMenu);
}
void AddControls(HWND hwnd) // Add Controls Function
{
ButtonOne = CreateWindowW
(
L"Button", L"Button1", WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_ONE_ID, NULL, NULL
);
ButtonTwo = CreateWindowW
(
L"Button", L"Button2", WS_CHILD | WS_VISIBLE | WS_BORDER, ButtonWidth, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_TWO_ID, NULL, NULL
);
ButtonThree = CreateWindowW
(
L"Button", L"Button3", WS_CHILD | WS_VISIBLE | WS_BORDER, ButtonWidth * 2, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_THREE_ID, NULL, NULL
);
ButtonFour = CreateWindowW
(
L"Button", L"Button4", WS_CHILD | WS_VISIBLE | WS_BORDER, ButtonWidth * 3, 475, ButtonWidth, 100, hwnd, (HMENU)BUTTON_FOUR_ID, NULL, NULL
);
}
Upvotes: 0
Reputation: 51511
The outcome of calling CreateWindowExW falls into one of three categories: "Failure", "cancellation", or "success". The following table lists those categories based on the function's return value, and the return value of GetLastError:
Return value | GetLastError |
Description |
---|---|---|
NULL |
non-zero | Window creation failed due to an error |
NULL |
zero | Window creation was cancelled by client code |
non-NULL |
<indeterminate> | Window creation succeeded |
Since it isn't relevant to the discussion here, let's get the final row out of the way: The function call returned a non-NULL
value, singalling successful window creation. The return value of GetLastError
is meaningless in this case, and can literally be any value.
The first row marks a true error condition. The window creation request couldn't be satisfied, either due to a programming error (e.g. passing in an invalid window class, window handle, ...) or an environmental issue like resource exhaustion.
The second row in the table above is the one that frequently causes confusion. Window creation didn't happen, but there's no error reported either. Wait, what? How can this fail without an error!?
It is failing on request!
Unintuitive as it may appear, the window procedure responsible for the behavior of an instance of a window class is already involved in the process of creating that instance. There are two1 window messages sent to the window procedure associated with a window class during window construction. Either one can abandon the request prematurely2: WM_NCCREATE
and WM_CREATE
.
The semantics of WM_CREATE
's return value include the following:
If the application returns -1, the window is destroyed and the
CreateWindowEx
orCreateWindow
function returns aNULL
handle.
Prior to that, a WM_NCCREATE
message is sent. The semantics of its return value are documented as well:
If the application returns
FALSE
, theCreateWindow
orCreateWindowEx
function will return a NULL handle.
That's all the information needed to answer the question:
default:
return 0;
This returns 0 (which is interpreted as FALSE
) for any unhandled message, including WM_NCCREATE
. Since there is no explicit message handler for the WM_NCCREATE
message that's what the window procedure returns, thereby terminating the request to create the window.
To fix this3 you would either need to add default processing to the default:
label, i.e.
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
and remove the trailing return statement4, or remove the default
label altogether.
1 Future visitors may find this to be inaccurate. Sorry, I don't have access to a time machine.
2 Literally.
3 Your compiler probably warned you about this.
4 Make sure to fix the (possibly unintended) WM_PAINT
fall-through into default
along the way.
Upvotes: 4