So I have the following dialogbox template which I saved in a .rc file:
DIALOG_TEST DIALOG 0, 0, 186, 95
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "Ms Shell Dlg"
{
PUSHBUTTON "Cancel", IDD_CAN, 129, 24, 50, 14, 0, WS_EX_LEFT
DEFPUSHBUTTON "OK", IDD_OK, 129, 7, 50, 14, 0, WS_EX_LEFT
}
which I call using DialogBox in the following way:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND button;
switch (message) /* handle the messages */
{
case WM_CREATE:
button = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON",
"Test",
WS_VISIBLE | WS_CHILD | WS_BORDER,
200, 40, 200, 30,
hwnd, (HMENU) 1, NULL, NULL);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 1:
DialogBox(GetModuleHandle(NULL), TEXT("DIALOG_TEST"),
hwnd, AboutDlgProc);
break;
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
All works fine except that for some reason the window is not being drawn correctly:
it's like the dialogbox is being drawn twice, what am I doing wrong?
As for the Window Procedure for the dialogbox, the only thing it does is close the window when the "Cancel" is pressed.
BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
switch(HIWORD(wParam))
{
case BN_CLICKED:
switch (LOWORD (wParam))
{
case IDD_CAN:
EndDialog(hDlg, TRUE);
return TRUE ;
}
break;
}
break;
}
}
A button can send more than one kind of notification in a WM_COMMAND message, so if you want to create the dialog box only when the button is clicked you need to check to make sure that the notification code (in HIWORD(wParam)) is BN_CLICKED. See WM_COMMAND documentation.
Related
I've created a basic GUI using the windows library and I've come across a problem. The GUI builds and performs great but the issue is the button functions execute before the actual window loads. I wanted the button to execute the desired function on press rather than on load. Below is the code where I think the problem lies.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("T3chSpl01ts Version - 1.0");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_CREATE:
{
Button = CreateWindow("Button", "Inject",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 20, 20, 100, 30,
hWnd, (HMENU)ID_INJECT, GetModuleHandle(NULL), NULL);
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case ID_INJECT:
{
::test();
break;
}
}
}
}
return 0;
}
Your WM_CREATE handler is missing a break statement, so code flow "falls through" into your WM_COMMAND handler when the window is created.
In order to make the static control background transparent, I did handle the WM_CTLCOLORSTATIC like this:
// make label transparent
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkMode(hdcStatic, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
the label is created like this:
LRESULT CALLBACK Win2Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
hTab3_label =
CreateWindowW(L"Static", L"This is my dear text!",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
50, 90, 130, 25, hwnd, (HMENU) 18, NULL, NULL);
break;
// ...
}
}
the GUI is fine so far:
but when I set a new text to it from a button call, like this:
case WM_COMMAND:
switch(LOWORD(wParam))
{
// ....
case ID_TAB1_BUTTONB:
//MessageBox(NULL, L"Click on B button", L"", MB_OK);
SetWindowText(hTab3_label, L"This is the new text!");
break;
}
break;
the static control gets messed up, without replace the previous text for some reason, like the image below. If I remove the case WM_CTLCOLORSTATIC the text is replaced properly. What am I missing?
I want to change label background color within a function, I tried this code but nothing changed after calling changecolor function
HWND hWndLabel;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
hWndLabel = CreateWindowEx(WS_EX_TRANSPARENT,
L"STATIC", L"", WS_CHILD | WS_VISIBLE | SS_LEFT | WS_SYSMENU,
75, 75, 70, 70, hWnd, (HMENU)labelId, hInst, NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND: // all events are handled here
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
DWORD WINAPI changecolor(){
HDC hdc = GetDC(hWndLabel); // get context
SetBkColor(hdc, RGB(0, 0, 230)); // Code Copied from the above answer by cpx.
return 0;
}
I read that Static controls send their parent a WM_CTLCOLORSTATIC message just before they paint themselves. code is implemented within CALLBACK function, but where this code is called (changing color)?, how can I call SetTextColor within a function
code example :
case WM_CTLCOLORSTATIC:
if (the_button_was_clicked) {
HDC hdc = reinterpret_cast<HDC>(wParam);
SetTextColor(hdc, COLORREF(0xFF, 0x00, 0x00));
}
return ::GetSysColorBrush(COLOR_WINDOW); // example color, adjust for your circumstance
Try something more like this:
HWND hWndLabel;
HBRUSH hBrushLabel;
COLORREF clrLabelText;
COLORREF clrLabelBkGnd;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
hWndLabel = CreateWindowEx(0, L"STATIC", L"", WS_CHILD | WS_VISIBLE | SS_LEFT,
75, 75, 70, 70, hWnd, (HMENU)labelId, hInst, NULL);
hBrushLabel = NULL;
clrLabelText = GetSysColor(COLOR_WINDOWTEXT);
clrLabelBkGnd = GetSysColor(COLOR_WINDOW);
break;
case WM_DESTROY:
if (hBrushLabel) DeleteObject(hBrushLabel);
PostQuitMessage(0);
break;
case WM_CTLCOLORSTATIC: {
HDC hdc = reinterpret_cast<HDC>(wParam);
SetTextColor(hdc, clrLabelText);
SetBkColor(hdc, clrLabelBkGnd);
if (!hBrushLabel) hBrushLabel = CreateSolidBrush(clrLabelBkGnd);
return reinterpret_cast<LRESULT>(hBrushLabel);
}
case WM_COMMAND: // all events are handled here
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
DWORD WINAPI changecolor()
{
if (hBrushLabel) {
DeleteObject(hBrushLabel);
hBrushLabel = NULL;
}
clrLabelText = RGB(0xFF, 0x00, 0x00);
clrLabelBkGnd = RGB(0, 0, 230);
InvalidateRect(hWndLabel, NULL, TRUE);
return 0;
}
There is a similar example in the WM_CTLCOLORSTATIC documentation.
The following C++ example shows how to set the text foreground and background colors of a static control in response to the WM_CTLCOLORSTATIC message. The hbrBkgnd variable is a static HBRUSH variable that is initialized to NULL, and stores the background brush between calls to WM_CTLCOLORSTATIC. The brush must be destroyed by a call to the DeleteObject function when it is no longer needed, typically when the associated dialog box is destroyed.
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(255,255,255));
SetBkColor(hdcStatic, RGB(0,0,0));
if (hbrBkgnd == NULL)
{
hbrBkgnd = CreateSolidBrush(RGB(0,0,0));
}
return (INT_PTR)hbrBkgnd;
}
I have a main window hwndMain and a multiline Edit textbox:
hwndEdit = CreateWindowEx(0, L"EDIT", NULL, WS_CHILD | WS_VISIBLE | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 300, 200, hwndMain, 0, (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
I use this to detect CTRL+A in the textbox (because strangely, it's not available out-of-the-box):
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
{
if (wParam == VK_CONTROL) // something here missing for detecting "A"
{
SendMessage(hwndEdit, EM_SETSEL, 0, -1); // select all ; this code works on its own, tested
}
...
Unfortunately, nothing happens when I do CTRL+A or CTRL+B or CTRL+ anything.
What is wrong?
Note: Ok the code for detecting A is still missing (i still don't know how to do it), but the code here should work for any CTRL+key...
Just check for WM_KEYDOWN for A and than use GetKeyState
case WM_KEYDOWN:
{
if (wParam=='A' && (::GetKeyState(VK_CONTROL) & 0x8000)!=0)
{
SendMessage(hwndEdit, EM_SETSEL, 0, -1); // select all
}
Remember that WM_KEYDOWN is only sent to the window that has the focus and not to parent windows.
After you create all your windows:
hwndEdit = CreateWindowEx(.....)
...
//Subbclassing
SetWindowSubclass(hwndEdit, (SUBCLASSPROC)EditWndProc, 0, 1);
LRESULT CALLBACK EditWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwrefData){
switch(message){ //handle the messages
case WM_KEYDOWN:
//your code
break;
default: //for messages that we don't deal with
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return DefSubclassProc(hwnd, message, wParam, lParam);
}
First of all forgive me, but I am total newb. I am trying to write a program that recognize my combobox selection when I click on the screen (I pick the item I want to place there). However I cannot, because the SendMessage function always returns 0. How can I get the proper result?
HWND g_Combobox;
/* ... */
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
/* ... */
switch (message)
{
case WM_CREATE:
{
HWND g_Combobox = CreateWindowEx( WS_EX_CLIENTEDGE, L"COMBOBOX", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER |
CBS_DROPDOWNLIST, 5, 25, 180, 200, hWnd, (HMENU) ID_MYCOMBO, hInst, NULL );
SendMessage( g_Combobox, CB_ADDSTRING, 0,( LPARAM ) L"item 1" );
SendMessage( g_Combobox, CB_ADDSTRING, 0,( LPARAM ) L"item 2" );
SendMessage( g_Combobox, CB_ADDSTRING, 0,( LPARAM ) L"item 3" );
/* ... */
}
break;
case WM_LBUTTONDOWN:
{
switch (SendMessage(g_Combobox, CB_GETCURSEL, 0, 0))
{
case 0: //always picks this one
MessageBox( NULL, L"0", L"Oh noes!", MB_ICONEXCLAMATION );
break;
default:
MessageBox( NULL, L"something diffrent than 0", L"Yeah...", MB_ICONEXCLAMATION );
break;
}
}
What am I doing wrong?
HWND g_Combobox = CreateWindowEx(...
Replace with:
g_Combobox = CreateWindowEx(...
Your current code fills local variable, leaving global variable unchanged. This is why SendMessage working with global variable gives unexpected results.
To solve such kind of problems in the future:
Use debugger.
Use maximal available compiler warning level.