win32 button not showimg - c

I tried to create a single button in a 500x500 window, the problem is, the button does not appear in the windows, and clicking the windows alone triggers the procedure/handler for the button:
#include <windows.h>
LRESULT CALLBACK MainWindowHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ButtonHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam);
LPCSTR FrameClassName = "MainWindow";
LPCSTR ButtonClassName = "Button";
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX Frame;
HWND FrameHandle;
WNDCLASSEX Button;
HWND ButtonHandle;
MSG Msg;
Frame.cbSize = sizeof(WNDCLASSEX);
Frame.style = 0;
Frame.lpfnWndProc = MainWindowHandler;
Frame.cbClsExtra = 0;
Frame.cbWndExtra = 0;
Frame.hInstance = hInstance;
Frame.hIcon = LoadIcon(NULL, IDI_APPLICATION);
Frame.hCursor = LoadCursor(NULL, IDC_ARROW);
Frame.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
Frame.lpszMenuName = NULL;
Frame.lpszClassName = FrameClassName;
Frame.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
Button.cbSize = sizeof(WNDCLASSEX);
Button.style = 0;
Button.lpfnWndProc = ButtonHandler;
Button.cbClsExtra = 0;
Button.cbWndExtra = 0;
Button.hInstance = hInstance;
Button.hIcon = LoadIcon(NULL, IDI_APPLICATION);
Button.hCursor = LoadCursor(NULL, IDC_ARROW);
Button.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
Button.lpszMenuName = FrameClassName;
Button.lpszClassName = ButtonClassName;
Button.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&Frame))
{
MessageBox(NULL,"Registration Failure","ERROR",MB_ICONWARNING| MB_OK);
return 0;
}
if(!RegisterClassEx(&Button))
{
MessageBox(NULL,"Registration Failure","ERROR",MB_ICONWARNING| MB_OK);
return 0;
}
FrameHandle = CreateWindowEx(WS_EX_CLIENTEDGE,
FrameClassName,
"Application",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 500,
NULL, NULL, hInstance, NULL);
ButtonHandle = CreateWindowEx(0, ButtonClassName, "My Button",
WS_CHILD | WS_VISIBLE, 250, 250, 30, 20, FrameHandle,
(HMENU)FrameHandle, hInstance, NULL);
SendDlgItemMessage(ButtonHandle, 12, WM_SETFONT,
(WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
ShowWindow(FrameHandle, nCmdShow);
UpdateWindow(FrameHandle);
ShowWindow(ButtonHandle, nCmdShow);
UpdateWindow(ButtonHandle);
while(GetMessage(&Msg,NULL,0,0)>0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
LRESULT CALLBACK MainWindowHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
MessageBox(obj,"CLICKED!","BUTTON",0);
break;
case WM_CLOSE:
DestroyWindow(obj);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(obj, msg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ButtonHandler(HWND obj, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(obj);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(obj, msg, wParam, lParam);
}
return 0;
}
What did i miss?

That is not how you create a button.
A button control uses a special window class, pre-defined by the common controls library. You don't need to register the window class, it is already registered. Recommended reading on using common controls is here on MSDN.
All you need is the call to CreateWindow, just make sure you use the correct class name: WC_BUTTON (which is defined by the common controls header file to be "BUTTON").
For controls, you also generally want to include the WS_TABSTOP style, and for a button specifically, you need to include one of the button styles—e.g., BS_DEFPUSHBUTTON or BS_PUSHBUTTON.
Finally, you're passing the wrong value for the hMenu parameter when you call CreateWindow. For child windows (like controls), this is a unique identifier of the control, not the handle of its parent window. If it's the first control, you might give it an ID of 1. It's best to use constants in your code for this so that you can interact with the controls later programmatically.
#include <CommCtrl.h> // somewhere at the top of your code file
ButtonHandle = CreateWindowEx(0,
WC_BUTTON,
"My Button",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
250, 250, 30, 20,
FrameHandle,
(HMENU)1, // or some other unique ID for this ctrl
hInstance,
NULL);
And since you've included the WS_VISIBLE style, you don't need this code (and you probably should not use nCmdShow with your child windows anyway):
// unnecessary code:
ShowWindow(ButtonHandle, nCmdShow);
UpdateWindow(ButtonHandle);
Finally, I can't help but notice that you're using ANSI string literals. All Windows applications today should be built with Unicode support, which requires that you use wide string literals. To get those, prefix each of them with an L and use the LPCWSTR type: LPCWSTR FrameClassName = L"MainWindow"; Not doing so should have been generating a compiler error; the default settings for a new project define the UNICODE preprocessor symbol. If that's not done for your project, you should do it now.

When creating button with visual style under Windows XP, you need to load comctl32.dll.
#include <CommCtrl.h> // somewhere at the top of your code file
#pragma comment(lib, "Comctl32.lib") // if necessary
// create manifest to use XP visual style
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
// before creating button call:
InitCommonControls(); // necessary to enable Visual style on WinXP

Related

In WIndows API, under what "event" do I put child control creation or why aren't my controls appearing?

It's been years since I last worked with Windows API and I'm trying my hand at it again. I have a simple Window (with title "Test"). I put in the Window message handler under WM_CREATE, 2 CreateWindow calls to create a static and an edit control. I'm pretty sure the coordinates are decent (not overlapping or off the window rectangle). Am I putting the calls under the wrong event? It's just a simple window - not MDI or SDI or anything like that. Here is my code for the entire program. I hope it's sufficient to figure out what I'm doing wrong. I'm using Eclipse CDT with Cygwin's G++ compiler to build it....:
#include <windows.h>
BOOL InitApplication(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow);
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "";
wc.lpszClassName = "MainWindow";
return(RegisterClass(&wc));
}
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow)
{
HINSTANCE hCurInstance = hinstance;
HWND hWnd = CreateWindow("MainWindow", "Test", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND)(NULL), (HMENU)(NULL), hCurInstance, (LPVOID)(NULL));
if(!hWnd)
return(FALSE);
// Show the window and send a WM_PAINT message to the window
// procedure.
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return(TRUE);
}
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
CreateWindow("WC_STATIC", "&Test: ", SS_LEFT | WS_VISIBLE | WS_CHILD, 10, 10, 50, 20, hWnd, NULL, (HINSTANCE)(GetWindowLongPtr(hWnd, GWLP_HINSTANCE)), (LPVOID)(NULL));
CreateWindow("WC_EDIT", "", WS_BORDER | WS_TABSTOP | WS_VISIBLE | WS_CHILD | ES_LEFT, 60, 10, 50, 20, hWnd, NULL, (HINSTANCE)(GetWindowLongPtr(hWnd, GWLP_HINSTANCE)), (LPVOID)(NULL));
return(0);
default:
return(DefWindowProcA(hWnd, uMsg, wParam, lParam));
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmd, int nCmdShow)
{
BOOL fGotMessage;
MSG msg;
if(!InitApplication(hInstance))
return(FALSE);
if(!InitInstance(hInstance, nCmdShow))
return(FALSE);
while(((fGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0) && (fGotMessage != -1))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(msg.wParam);
}
WM_CREATE is the correct "event" message to create the child controls in.
You are simply using the wrong class names for the child controls. That is why you are not seeing them. Had you checked the result of those CreateWindow() calls for failures, you would have noticed that CreateWindow() was returning NULL, and GetLastError() was reporting ERROR_CANNOT_FIND_WND_CLASS (1407).
You need to replace "WC_STATIC" with "Static", and replace "WC_EDIT" with "Edit". Or, you can use the pre-defined WC_STATIC and WC_EDIT constants that are defined in <commctrl.h>.
You can also replace GetWindowLongPtr(hWnd, GWLP_HINSTANCE) with NULL when creating system-defined classes, as they are registered globally, not per-module. The HINSTANCE parameter of CreateWindow/Ex() is ignored for them.
On a side note: your GetMessage() loop can be simplified to just:
while (GetMessage(&msg, (HWND) NULL, 0, 0))
See: When will GetMessage return -1?

Why are my WINAPI messages not reaching my window procedure?

I am using a winapi dialog as my root HWND for a window class. The program compiles and displays perfectly, but when I click on the buttons, nothing is responsive, almost like the messages aren't reaching my window procedure, or said procedure is never being called. How can I ensure that the messages are working correctly and I'm handling them properly for what I'm trying to do?
Simplified WinMain in main.c:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
static char szAppName[] = TEXT ("AppName"); // Does not display, remove later
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = DlgProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = DLGWINDOWEXTRA;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wndclass.lpszMenuName = MAKEINTRESOURCE(IDC_MAINMENU);
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL,
TEXT("This program requires Windows NT!"),
szAppName,
MB_ICONERROR);
return 0;
}
hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Simplified DlgProc (written in C++ and registered for use in C):
LRESULT CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:
MessageBeep(0); // Does not sound, even if I change the case to WM_CREATE
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
// Handle buttons/statics inside the dialog, they do nothing
}
case WM_CLOSE:
EndDialog(hwnd, 0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return FALSE;
}
return TRUE;
}
dialog in resource file:
IDD_MAIN DIALOG DISCARDABLE 0, 0, 207, 156
STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
CAPTION "AppTitle"
FONT 8, "MS Sans Serif"
BEGIN
// Internal statics and buttons
END
Any help is appreciated. Thanks!
Follow the Using the code which is in Microsoft GitHub repository steps to complete your program. You should set your dialog Class Name = AppName in resource file and Change WM_INITDIALOG back to WM_CREATE in WndProc that you call DlgProc.

Why is the window painted strangely (without visual styles) after sending WM_NCDESTROY?

I get strange window painting after I send WM_NCDESTROY manually. This only happens when visual styles are on. When 'Classic style' is on it does not seem to affect the window. I do not pass WM_NCDESTROY to DefWindowProc() when I send it manually, but the window still gets painted strangely. It seems like SendMessage() is processing WM_NCDESTROY. Why is WM_NCDESTROY getting processed even though I do not pass it to DefWindowProc()?
#include <windows.h>
HINSTANCE g_hInst;
LRESULT CALLBACK WndProc2(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static BOOL bProcessMsg = FALSE;
switch(msg)
{
case WM_RBUTTONUP:
SendMessage(hwnd, WM_NCDESTROY, 0, 0);
//Size window manually after this message is processed to see the effects
break;
case WM_DESTROY:
bProcessMsg = TRUE;
break;
case WM_NCDESTROY:
if(!bProcessMsg) return 0;
MessageBox(0, L"Message processed", 0, MB_OK);
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_MBUTTONUP:
{
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = g_hInst;
wc.lpfnWndProc = WndProc2;
wc.lpszClassName = L"Testclass2";
if(!RegisterClassEx(&wc)) return 0;
CreateWindowEx(0, L"Testclass2", L"Test2", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 40, 40, 200, 200, hwnd, 0, g_hInst, 0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc = { 0 };
HWND hwnd;
MSG msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc1;
wc.lpszClassName = L"Testclass";
if(!RegisterClassEx(&wc)) return 0;
g_hInst = hInstance;
hwnd = CreateWindowEx(0, L"Testclass", L"Test1", WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, 0, 0, hInstance, 0);
if(!hwnd) return 0;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
Before right clicking on Test2
After right clicking on Test2
The WM_NCDESTROY message is rather special, it is guaranteed to be the last message that a window ever receives before it is destroyed. It is generated by the DestroyWindow() function.
Being last gives it a rather exalted status. It signals "stop doing what you've been doing". For example, you always use it when you subclass a window; this message tells you to stop subclassing it. And you'd always use it in a C++ wrapper class for a window, where it tells you when the C++ object needs to be destroyed. And it is pretty likely to be the notification that the Visual Styles renderer uses to stop making a window look different because it isn't around anymore.
Oops.
Messages like that are notifications that something interesting happened. As opposed to the kind of messages that are intended to make something interesting happen, like WM_LBUTTONDOWN, WM_KEYDOWN, WM_COMMAND. Most obvious in the WM_CLOSE vs WM_DESTROY message. WM_CLOSE is "please close the window". You can monkey with that and refuse to close the window, traditionally with the "Data not saved, are you sure" message. WM_DESTROY is "it is closed". That's a rock, it really did get destroyed, no point in ever monkeying with that one.
If you generate a fake notification, then you should be prepared to get a fake outcome. Don't mess with the important ones.

Why doesn't font size show for SYSTEM_FONT in Font dialog?

#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_RBUTTONUP:
{
HFONT hFont;
LOGFONT lf;
CHOOSEFONT cf = {0};
hFont = (HFONT)GetStockObject(SYSTEM_FONT);
GetObject(hFont, sizeof(LOGFONT), &lf);
cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
cf.hwndOwner = hwnd;
cf.lpLogFont = &lf;
cf.lStructSize = sizeof(CHOOSEFONT);
if(ChooseFont(&cf))
{
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wc = {0};
HWND hwnd;
MSG msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"MainClass";
if(!RegisterClassEx(&wc))
return 0;
hwnd = CreateWindowEx(0, wc.lpszClassName, L"First", WS_OVERLAPPEDWINDOW,
50, 30, 400, 200, 0, 0, hInstance, 0);
if(!hwnd)
return 0;
ShowWindow(hwnd, nShowCmd);
while(GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
The proper font size doesn't show in the edit box of the Size: combo box in Font dialog. This was tested in windows xp sp3. Don't know if this happens in other operating systems. Why doesn't the proper font size show?
SYSTEM_FONT appears to be a broken constant that Microsoft hasn't used for years, and it points to a font that is not TrueType or OpenType. SYSTEM_FONT and DEFAULT_GUI_FONT are very old and almost certainly deprecated; I suggest that you refrain from using them.
From the documentation for GetStockObject:
It is not recommended that you employ this method to obtain the current font used by dialogs and windows. Instead, use the SystemParametersInfo function with the SPI_GETNONCLIENTMETRICS parameter to retrieve the current font. SystemParametersInfo will take into account the current theme and provides font information for captions, menus, and message dialogs.
It also says:
It is not recommended that you use DEFAULT_GUI_FONT or SYSTEM_FONT to obtain the font used by dialogs and windows.
See also http://weblogs.asp.net/kdente/394499

Why doesn't the window set cursor correctly?

As MSDN describes:
When the mouse moves over a window, the window receives a WM_SETCURSOR message (unless another window has captured the mouse).
If the application passes WM_SETCURSOR to DefWindowProc, the DefWindowProc function uses the following algorithm to set the cursor image:
If the window has a parent, forward the WM_SETCURSOR message to the parent to handle.
Otherwise, if the window has a class cursor, set the cursor to the class cursor.
If there is no class cursor, set the cursor to the arrow cursor.
And here's my source code:
#include <tchar.h>
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInsTance, LPTSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex = { 0 };
HWND hWnd;
BOOL ret;
MSG msg;
wcex.cbSize = sizeof(wcex);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
// wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = TEXT("MainWindow");
wcex.hIconSm = wcex.hIcon;
RegisterClassEx(&wcex);
hWnd = CreateWindow(wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (ret = GetMessage(&msg, NULL, 0, 0))
{
if (ret == -1)
{
return EXIT_FAILURE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(EXIT_SUCCESS);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
When I move my cursor quickly over the window, the cursor doesn't change to an arrow, it become a resize arrow; if I set wcex.hCursor to LoadCursor(NULL, IDC_ARROW), everything will be all right. My question is: why doesn't my code work as MSDN says?
I mean, if I don't set wcex.hCursor, and I don't handle the WM_SETCURSOR message, the DefWindowProc should "set the cursor to the arrow cursor", but it seems it doesn't. Why is that?
See description of the hCursor member of the WNDCLASSEX:
A handle to the class cursor. This member must be a handle to a cursor
resource. If this member is NULL, an application must explicitly set
the cursor shape whenever the mouse moves into the application's
window.
WNDCLASSEX structure

Resources