Is there a way to set true full focus on a push button (button window class) in WinAPI?
SetFocus() somewhat sets focus (the button gets an inner dotted border), but the button is actually partially focused and still cannot be pressed with the Enter key, only the Spacebar key works. At the same time, if I move focus to a sibling button with the Tab key, then this sibling button (as well as the first button if I then return focus to it using Shift+Tab) gets a true focus (visually, not just inner dotted focus border is added to the really focused button, but its main outer border becomes blue [Windows 7]), and now it reacts to Enter as intended.
How to make a button such fully focused programmatically?
Screenshot of the three button states:
Some background for clarity: there is a window (created with the regular combination of WNDCLASSEX / RegisterClassEx / CreateWindowEx() with WS_OVERLAPPEDWINDOW as its style) with a multiline edit box (edit window class with ES_MULTILINE style) and several push buttons. To implement keyboard navigation using the Tab key, I process the WM_KEYDOWN event in the edit box's procedure (subclassed via SetWindowLong()), otherwise I could navigate between buttons and from buttons to the edit box, but not from the edit box to a button. All the controls have WS_TABSTOP style. The issue with the button focus takes place when I set focus using SetFocus() when the Tab key is pressed on the edit box having focus and caret.
Minimal relevant C++ code:
HWND mainWindow;
WNDPROC defaultEditCallback = NULL;
int WINAPI WinMain(HINSTANCE instance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEXW wc;
wchar_t windowClass[] = L"testcase";
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = 0;
wc.lpfnWndProc = mainWindowCallback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = instance;
wc.hIcon = NULL;
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCWSTR)windowClass;
wc.hIconSm = NULL;
RegisterClassExW(&wc);
mainWindow = CreateWindowW(
(LPCWSTR)windowClass, (LPCWSTR)windowClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, instance, NULL
);
HWND edit = CreateWindowExW(
WS_EX_CLIENTEDGE, (LPCWSTR)L"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | WS_TABSTOP,
0, 0, 0, 0, mainWindow, (HMENU) 10,
(HINSTANCE) GetWindowLongPtrW(mainWindow, GWLP_HINSTANCE),
NULL
);
defaultEditCallback = (WNDPROC)SetWindowLongPtrW(edit, GWLP_WNDPROC, (LONG)editCallback);
HWND firstButton = createButton(mainWindow, 20, L"First", buttonWidth, buttonHeight);
HWND secondButton = createButton(mainWindow, 30, L"Second", buttonWidth, buttonHeight);
HWND thirdButton = createButton(mainWindow, 40, L"Third", buttonWidth, buttonHeight);
// [Skipped] Sizing and positioning controls.
ShowWindow(mainWindow, nCmdShow);
UpdateWindow(mainWindow);
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
if (!IsDialogMessage(mainWindow, &msg)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK mainWindowCallback(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_DESTROY == msg) {
PostQuitMessage(0);
}
return DefWindowProcW(window, msg, wParam, lParam);
}
LRESULT CALLBACK editCallback(HWND control, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_KEYDOWN == msg && VK_TAB == wParam) {
HWND next = GetNextDlgTabItem(mainWindow, control, (int)(GetKeyState(VK_SHIFT) & 0x8000));
SetFocus(next);
return 0;
}
return CallWindowProc(defaultEditCallback, control, msg, wParam, lParam);
}
HWND createButton(HWND parentWindow, int id, wchar_t* caption, int width, int height) {
return CreateWindowW(
(LPCWSTR)L"button", (LPCWSTR)caption, WS_VISIBLE | WS_CHILD | WS_TABSTOP,
0, 0, width, height, parentWindow, (HMENU)id, NULL, NULL
);
}
Thanks.
The question does not make it clear whether the WS_OVERLAPPEDWINDOW main window is either a dialog, or subclassed to work like a dialog (i.e. based on DefDlgProc). Some hints about TAB navigation and DM_SETDEFID in the OP and following comments appear to indicate that it's a dialog(-styled) window.
For dialogs, the correct way to move the input focus between child controls is by sending the WM_NEXTDLGCTL message, rather than calling SetFocus directly. As noted in the docs:
This message performs additional dialog box management operations beyond those performed by the SetFocus function WM_NEXTDLGCTL updates the default pushbutton border, sets the default control identifier, and automatically selects the text of an edit control (if the target window is an edit control).
More details at How to set focus in a dialog box, including this part:
As the remarks to the DM_SETDEFID function note, messing directly with the default ID carelessly can lead to odd cases like a dialog box with two default buttons. Fortunately, you rarely need to change the default ID for a dialog.
A bigger problem is using SetFocus to shove focus around a dialog. If you do this, you are going directly to the window manager, bypassing the dialog manager. This means that you can create “impossible” situations like having focus on a pushbutton without that button being the default!
To avoid this problem, don’t use SetFocus to change focus on a dialog. Instead, use the WM_NEXTDLGCTL message.
[EDIT] After the OP edit, the main window turns out to be a regular window, not a dialog. The newly posted code, however, does not remember the focused child (nor does it remove/restore the default pushbutton style) after the main window is deactivated and reactivated, relegates keyboard navigation such as VK_TAB to child controls etc. Those introduce inconsistencies with the default dialog-like behaviors.
In order to make the main window behave like a dialog (and do it right), the WNDPROC would need to mimic the relevant parts of DefDlgProc, at least those that pertain to navigation. From Dialog Box Programming Considerations, among the messages such a WNDPROC would need special handling for are DM_GETDEFID, DM_SETDEFID, WM_ACTIVATE, WM_NEXTDLGCTL, WM_SHOWWINDOW, WM_SYSCOMMAND. Once that's done, my original answer still applies.
Related
I'm make window in c++ with supporting winapi(not MFC), and I made gif animation on window with gdi++, and I create TextBox, it showing, but some part is behind gif. Image in this link : 1
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
hMWDC = GetDC(hwnd);
pGphcs = new Graphics(hMWDC);
WCHAR path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
PathRemoveFileSpecW(path);
PathAppendW(path, L"gifs\\test.gif");
pImg = new Image(path);
if (pImg) {
nFrmCnt = pImg->GetFrameCount(&FrameDimensionTime);
SetTimer(hwnd, DRAW_ANIM, 100, NULL);
}
break;
case WM_TIMER:
if (wParam == DRAW_ANIM)
{
pImg->SelectActiveFrame(&FrameDimensionTime, nFrm);
Rect DRC(0, 0, pImg->GetWidth(), pImg->GetHeight());
pGphcs->Clear(Color(128, 128, 128));
pGphcs->DrawImage(pImg, DRC);
if (nFrm < (nFrmCnt - 1)) nFrm++; else nFrm = 0;
}
break;
hwndText = CreateWindow(L"EDIT",
L"",
WS_CHILD | WS_VISIBLE,
350, 480, 55, 20,
hWnd, NULL, NULL, NULL);
I expected gif as background and TextBox will be front of it.
But nothing, :(
For performance reasons by default device context for given HWND does not clip a child window from the parent window's client area.
If parent window draws something in the same location as the child window, it draws also over child window. Accepting some (nowadays minimal) performance hit you can automatically clip children windows form main frame window painting area, by adding WS_CLIPCHILDREN style when creating main frame window. With this style any HDC obtained for main frame window will have area occupied by child control excluded form painting area. This protects child window from overpainting by it's parent window activity.
Setting WS_CLIPCHILDREN for main frame window should solve your problem.
hwnd = CreateWindow( class_name, title, some_styles | WS_CLIPCHILDREN, ... );
Sometimes child windows overlap each other and then they can overdraw each other. In this case WS_CLIPSIBLINGS applied to child windows (of the same parent window), protects one child form another painting.
I'm trying to change text/background color for the static control. I can do this just fine the following way:
// This is the 'main' window
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW &~WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT, 0, 1035, 764, nullptr, nullptr, hInstance, nullptr);
...
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
case WM_CTLCOLORSTATIC:
{
MessageBox( NULL, "CTLCOLORSTATIC called", "", MB_OK );
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(200, 200, 20));
SetBkColor(hdcStatic, RGB(10, 10, 10));
return (INT_PTR)CreateSolidBrush(RGB(30, 30, 30));
}
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
But if I place the window inside another window, the child control text/background color stays default:
// This is the 'parent' window, which resides in the 'main' window
HWND parent = CreateWindowEx
(
0,
_TEXT("STATIC"),
"",
WS_TABSTOP | WS_VISIBLE | BS_SOLID | WS_CLIPCHILDREN,
10, 10, 500, 500,
hwnd,
NULL,
(HINSTANCE)GetWindowLong(hwnd, GWLP_HINSTANCE),
NULL
);
// This is the 'child' window which resides in the 'parent' window
HWND child = CreateWindowEx
(
0,
_TEXT("STATIC"),
"SubItem",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_SOLID,
10, 10, 100, 100,
parent,
NULL,
(HINSTANCE)GetWindowLong(parent, GWLP_HINSTANCE),
NULL
);
To conclude, I have 3 windows:
HWND hwnd; // the 'main' application window (color changes fine)
HWND parent; // the 'parent/container' window which is inside the 'main' window (color changes fine)
HWND child; // the 'child' window which is inside the 'parent' window (color DOES NOT change)
Even though if I put MessageBox inside the WM_CTLCOLORSTATIC, I see it triggering every time the children is drawn, yet the color is not being changed for the child, only for the parent.
As far as I understood I need to handle the message in the main window procedure, but I'm not entirelly clear how to do this. if I compare the (HWND)lParam to the childrens HWND, they're the same (within the default switch case), so I can get the reference in the 'default' section, but I'm not sure how I should handle it from there..
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
case WM_CTLCOLORSTATIC:
{
if ((HWND)lParam == child )
MessageBox( NULL, "Reference Match for CTLCOLORSTATIC", "", MB_OK ); // <-- THIS NEVER TRIGGERS
}
....
default:
if ((HWND)lParam == child )
MessageBox( NULL, "Reference Match for DEFAULT", "", MB_OK ); // <-- THIS DOES TRIGGER
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
The reason I'm placing one window inside another is so that I can use WS_CLIPCHILDREN property in the parent (becase the child will move/scroll).
WM_CTLCOLORSTATIC is sent by a static control to its parent window, not the top level window.
hwndMain: WM_CTLCOLORSTATIC for hwnd1
|
\--hwnd1: WM_CTLCOLORSTATIC for hwnd2 (You might have to subclass hwnd1)
|
\--hwnd2
You are also leaking brushes, store the brush from CreateSolidBrush somewhere when you create the window and delete it when the window is destroyed.
By reading the MSDN document, I know a function, SetWindowsLongPtr, whose parameter GWLP_WNDPROC can set a new address for the window procedure.
This function can change the text color and background color of the child window, that is to say, it can trigger WM_CTLCOLORSTATIC.
But after testing, I found that it is invalid to the secondary window, that is to say, it can not change the text color of the parent window.
I also consulted a lot of information, and very few documents related to three-tier windows.
So, I think to solve this problem and make all three windows change the color of the text, you may have to rewrite WndProc by yourself, but this is very complicated and involves a lot of things.
Edit: If you just need to change the text color and background color
of the static control, you can customize a control so that you can
handle all its operations.
Hope to help you.
I'm trying to get the button press event in c++ win32 using WM_Command
HWND hBtn;
HWND hBtnParent = HWND("UploadVideo");
HWND SelectVideoBTN, UploadBTN;
HWND hWnd;
HINSTANCE hUpload;
WNDCLASSEX wcexUpload;
int nCmdShowUpload = 1;
using namespace std;
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
loader::alert("rrr");
switch (message)
{
case WM_COMMAND:
if (LOWORD(wParam) == WORD(SelectVideoBTN)) {
loader::alert("hello");
}
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
SelectVideoBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Select Video's", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
UploadBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Upload", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
390, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
I've been looking at this example - http://forums.devshed.com/programming-42/create-button-clicked-148407.html - but I can't quite get it to work, it won't even call the CALLBACK WindowProcedure - is there anyone who could help me?
The buttons are present on the window I've created, I create the window by doing -
WNDCLASSEX vidUploader;
vidUploader.cbSize = sizeof(WNDCLASSEX);
vidUploader.style = CS_HREDRAW | CS_VREDRAW;
vidUploader.lpfnWndProc = WndProc;
vidUploader.cbClsExtra = 0;
vidUploader.cbWndExtra = 0;
vidUploader.hInstance = hUpload;
vidUploader.hIcon = LoadIcon(hUpload, MAKEINTRESOURCE(IDI_P2GOVIDEOUPLOADER20));
vidUploader.hCursor = LoadCursor(NULL, IDC_ARROW);
vidUploader.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
vidUploader.lpszMenuName = MAKEINTRESOURCE(IDC_P2GOVIDEOUPLOADER20);
vidUploader.lpszClassName = (LPCWSTR)(L"UploadVideo");
vidUploader.hIconSm = LoadIcon(wcexUpload.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&vidUploader);
hInst = hUpload; // Store instance handle in our global variable
and then to create the window
hWnd = CreateWindow((LPCWSTR)(L"UploadVideo"), (LPCWSTR)(L"Upload Video's"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hUpload, NULL);
if (!hWnd)
{
MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShowUpload);
UpdateWindow(hWnd);
Child windows (i.e. windows with the WS_CHILD window style) are identified by a unique numeric value, often called control ID or window ID. It is passed to the parent when it receives a WM_COMMAND message, for example. You never assigned a control ID to your button controls, though, and the parent window cannot identify them. In case of a child window, the hMenu parameter in the call to CreateWindow is overloaded to carry the unique identifier:
hMenu
For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.
In other words, your application picks a numeric value to assign to controls. Since the lower IDs are used by the dialog manager already (e.g. IDOK), it is common practice to start assigning control IDs starting at 100 (see Why do dialog editors start assigning control IDs with 100?).
In your WM_COMMAND handler you can then compare LOWORD(wParam) to the identifier assigned to your button controls.
You need to apply the following changes to your code.
// Declare control IDs. This is usually done in a file called Resource.h
#define IDC_SELECT_VIDEO (100)
Change your window creation code:
SelectVideoBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Select Video's", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
(HMENU)IDC_SELECT_VIDEO, // Assign appropriate control ID
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
Check for the control ID in your WM_COMMAND handler:
switch (message)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDC_SELECT_VIDEO) {
loader::alert("hello");
}
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
If your window procedure isn't called at all, this could mean that you aren't dispatching messages on the calling thread. A GUI thread always needs a message loop. The standard message loop suffices:
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
I am having trouble using the function SHAutoComplete. It simply does not work correctly when I use it on a edit box whose parent window is not a dialog box.
The auto-complete functionality seems to be working fine, but the rendering of the drop-down list with the possible candidates based on what was typed on the edit box is very messed up. Basically only the borders of the drop-down are shown. The borders are rendered wide enough to fit the possible suggestions, but the suggestions themselves are never drawn. Even the drop-down list background color is wrong. It is as if it was never painted and remains with the original parent window color.
And if the number of suggestions is big enough so the drop-down needs a scroll-bar, the scrollbar also does not get rendered correctly - the arrows do not get drawn.
On both cases, with or without scrollbars, the drop-down list does not accept mouse input, i.e., I cannot click on the items. If I press the "down" key on the keyboard while the drop-down is being shown, it kind of works as expected. After the second or third press the items finally start to appear. But the scrollbar still is does not get rendered correctly.
If instead of registering my own windows class I simply use a dialog with ::DialogBoxParam(), then it all goes as expected. The auto-complete works without any problems at all.
Here is what I am doing. This code will register a window class, create the main window, create an edit box and then call SHAutoComplete on it. It must be linked with Shlwapi.lib
// this code must be linked with Shlwapi.lib
#include <Windows.h>
#include <Shlwapi.h>
// name of the class that will be created for the main window
static const char WindowClassName[] = "SHAutoCompleteDoesNotWorkWithoutADialogWindowClassName";
// the main window procedure
static LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_CHILD | WS_VISIBLE,
10,
10,
300,
25,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 0;
}
case WM_DESTROY:
::PostQuitMessage(1);
return 0;
default:
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
// the app entry point
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
::CoInitialize(NULL);
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW ;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = WindowClassName;
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
ATOM atom = ::RegisterClassEx(&wcex);
HWND hwnd = ::CreateWindowEx(
0,
MAKEINTATOM(atom),
"SHAutoComplete Test",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
MSG msg;
while(::GetMessage(&msg, hwnd, 0, 0) > 0)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::UnregisterClass((LPCTSTR)atom, NULL);
::CoUninitialize();
return 0;
}
That code produces the following:
the drop-down when a scroll bar is needed
http://www.abload.de/img/shautocomplete_2i1sk4.jpg
the drop-down after a couple of presses to the "down" key. Notice how the scroll bar still is not rendered correctly.
http://www.abload.de/img/shautocomplete_3efsgw.jpg
Now, when I switch to Dialog Boxes, works like a charm. In the code below, IDD_DIALOG1 is simply an empty dialog box resource, created automatically by the IDE.
Here is the relevant part of the rc file
IDD_DIALOG1 DIALOGEX 0, 0, 316, 185
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
And here is the code that uses it
// this code must be linked with Shlwapi.lib
#include <windows.h>
#include <Shlwapi.h>
#include "Resource.h"
BOOL CALLBACK DialogProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_VISIBLE | WS_CHILD,
0,
0,
300,
20,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 1;
}
case WM_CLOSE:
::EndDialog(hwnd, 0);
return 1;
default:
return 0;
}
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
::CoInitialize(NULL);
::DialogBoxParam(
NULL,
MAKEINTRESOURCE(IDD_DIALOG1),
NULL,
DialogProc,
0);
::CoUninitialize();
return 0;
}
Could you please point out where I am going wrong? As far as I can see, other than the creation and destruction of the main window, there seems to be no difference at all between the two of them. Am I missing something on the SHAutoComplete docs that states it can only be used on edit boxes inside dialogs?
You are using a filtered message loop so any messages for the drop down are not being processed. Pass NULL as the second parameter to GetMessage
I create a simple window with a comboboxex (with inserting few bitmaps), I need to know when user has selected an item from combo-box(I need CBEN_ENDEDIT I think). But Parent window don't get any WM_NOTIFY from that combo-box except one value. Can anyone help me with this please? Why I can't get the notifications ?
//Window creating
WNDCLASSEX wcx={0};
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WndProc;
wcx.hInstance = hInst;
RegisterClassEx(&wcx)
HWND parent =CreateWindowEx()//-Created with some args
//WndProc
switch (uMsg)
{
case WM_CREATE:
{
//-Creating comboboxex
DWORD dwStyle = CBS_DROPDOWNLIST | WS_CHILD |WS_VISIBLE;
HWND child = CreateWindowEx(0, WC_COMBOBOXEX,0, dwStyle, x, y, w, h, parent, IDC_CMBX, hinst, 0)
}
case WM_NOTIFY :
{
LPNMHDR nmhdr = (LPNMHDR)lParam;
//Here nmhdr->code value is always 4294967279 -I think it is NM_SETCURSOR ?
}
}
Thank you very much.
What you probably want is CBN_SELCHANGE.
From MSDN:
The CBN_SELCHANGE notification message is sent when the user changes the current selection in the list box of a combo box. The user can change the selection by clicking in the list box or by using the arrow keys. The parent window of the combo box receives this notification in the form of a WM_COMMAND message with CBN_SELCHANGE in the high-order word of the wParam parameter.
So in this case you have to handle WM_COMMAND instead of WM_NOTIFY and check if the high-order word of the wParam parameter is CBN_SELCHANGE.