I'm creating a window that's supposed to contain buttons.
When I create the first window (the container) I use a WNDCLASS
to specify a WindowProc
callback function to lpfnWndProc
and it works as intended. When I do it the second time with a window, specifying a callback used to detect when the button is clicked, it doesn't work; the CreateWindowEx
call there returns NULL (comment below shows where).
When I don't create WNDCLAS wB
below and specify some other valid lpClassName
to CreateWindowEx
instead, such as Button
it works fine.
#pragma comment(linker, "/entry:wWinMainCRTStartup")
#include <windows.h>
#include <iostream>
HWND button;
LRESULT CALLBACK ButtonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine,
int nCmdShow) {
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"textedit";
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0, wc.lpszClassName, L"textedit", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 340, 240, NULL, NULL, hInstance, NULL);
if (hwnd == NULL) {
return 0;
}
HWND hWndEdit = CreateWindowEx(WS_EX_CONTROLPARENT, L"Edit", L"id here",
WS_BORDER | WS_CHILD | WS_VISIBLE, 94, 20, 140,
40, hwnd, NULL, NULL, NULL);
// if I leave wcB unused/remove it and
// specify L"Button" as the lpClassName to CreateWindowEx below, the button displays
WNDCLASS wcB = {};
wcB.lpfnWndProc = ButtonWindowProc;
wcB.hInstance = hInstance;
wcB.lpszClassName = L"modify";
RegisterClass(&wcB);
ShowWindow(hwnd, nCmdShow);
// doing the exact same thing I did when creating the first window
// but it fails to create the window
HWND hButton =
CreateWindowEx(0L, L"modify", L"modify", BS_FLAT | WS_VISIBLE | WS_CHILD,
94, 70, 140, 50, hwnd, NULL, hInstance, NULL);
ShowWindow(hButton, nCmdShow);
// here hButton is NULL <----------------------
if (hButton == NULL) {
return 0;
}
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK ButtonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case BN_CLICKED:
std::cout << "clicked";
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
return 0;
}
return 0;
return DefWindowProc(hwnd, uMsg, wParam, lParam);
};
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
GetLastError()
returns 1400, but I don't understand how the handle hwnd
could possible be invalid because as I mentioned before, when I just change the lpClassName
I pass to CreateWindowEx
, it works without errors.
I would appreciate any help in finding out why the window (the HWND of which is hButton
) does not initiate, and possible workarounds.
The solution to the problem in the title was solved by the comment by Igor Tandetnik:
ButtonWindowProc returns 0 for all messages it doesn't handle, and doesn't pass them to DefWindowProc. In particular, it returns 0 in response to WM_NCCREATE, which is a signal that the window creation has failed. You probably didn't mean to put return 0; right before return DefWindowProc(...);
After fixing that, the window was created but was invisible.
To fix that I used FillRect
with a valid brush handle
SetDCBrushColor(hdc, bkcolor);
SetBkColor(hdc, RGB(187, 189, 189));
FillRect(hdc, &ps.rcPaint, (HBRUSH)GetStockObject(DC_BRUSH));
To detect left mouse button clicks you need to check for the WM_LBUTTONDOWN
message.