WM_NOTIFY isn't posted to winProc function (parrent of child is correct, WM_COMMAND works excelent) - winapi

I am writing some library with using WIN API. I have a problem with receiving WM_NOTIFY message from WC_TABCONTROL class window in parent window WinProc function.
I check by "debug prints", that parent of child was set correctly. I receives WM_COMMAND messages and correctly in some function.
I have not idea what can be a reason for this. Tab control in window looks good and responds for mouse clicks with do visual tab item select change.
for example, when I click to unselected tab, I receive following messages http://pastie.org/6571509
You can check my WIN Proc function here http://goo.gl/knJ4Z , line 346.
Create tab control:
ps_ext->d_handle = CreateWindowExW(0, // no extended styles
WC_TABCONTROL, // class name
L"", // default text
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, // overlapped window
CW_USEDEFAULT, // default horizontal position
CW_USEDEFAULT, // default vertical position
CW_USEDEFAULT, // default width
CW_USEDEFAULT, // default height
HWND_MESSAGE, // no parent or owner window
(HMENU)WINSEM_Window_NextComponentID(), // class menu used
WINSEM_Window_hInstance,// instance handle
(LPVOID)&ps_ext->s_window); // no window creation data
After it, set correct parent by SetParent function call.
Tab is resized by something like:
uFlags = SWP_NOOWNERZORDER | SWP_NOZORDER;
if (SetWindowPos(ps_window->d_handle, NULL, s0_x, s0_y, s0_w, s0_h, uFlags)==0)
{
DWORD dErr;
dErr = GetLastError();
HaveWinLastError_Error(ps_pack, WINSEM_WINDOW_fromerror_windowPos+0, dErr, dErr);
break;
}
And showing window and clicking on tab control don't generate WM_NOTIFY message received by parent window winProc function.
This is my message receive code:
bRet = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE);
if (bRet==FALSE)
{
// no messages received
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Have anybody any idea about this problem? Thanks for you ideas and time.

I suspect that the tab control caches its parent window when it is created and never updates it. If you re-parent it, the messages will still go to the original parent - which is an invalid window in this case.
Why are you creating it with HWND_MESSAGE as a parent anyway? Why not just create it with its proper parent to begin with?

Related

How do I make a combobox show a tab control like VS' when setting a color?

I mean this control:
When you click on this, instead of regular options, a tab control with the colors is displayed. How can I do this? is this a owner-draw combobox or something else? I'm aware on how draw text, rectangles, images, etc with a owner-draw combobox but I don't know how add controls over there. I have no code to show yet because I have no idea how do that. I've tried something like call CreateWindow() in WM_DRAWITEM using the values from DRAWITEMSTRUCT.rcItem but I can't make a control inside the groupbox's client area, the button gets behind the control.
Looks like you are looking for CBN_DROPDOWN.
Sent when the list box of a combo box is about to be made visible. The
parent window of the combo box receives this notification code through
the WM_COMMAND message.
Some code:
HWND hWndComboBox = CreateWindow(
WC_COMBOBOX,
TEXT(""),
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST,
10, 20, 70, 17,
hWnd, (HMENU)IDB_COMBOX, hInstance, NULL);
...
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDB_COMBOX:
{
switch (HIWORD(wParam))
{
case CBN_DROPDOWN:
{
CHOOSECOLOR cc; // common dialog box structure
static COLORREF acrCustClr[16]; // array of custom colors
static DWORD rgbCurrent; // initial color selection
// Initialize CHOOSECOLOR
ZeroMemory(&cc, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.hwndOwner = hWnd;
cc.lpCustColors = (LPDWORD)acrCustClr;
cc.rgbResult = rgbCurrent;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
ChooseColor(&cc);
}
break;
...
Debug:

Can I make a property sheet without resource script?

I'd like to add controls to a property sheet without resource script, rather using pure code.
The reason for this I'd like to create a property sheet(mimicking C#'s property grid), calling C routines/WINAPI, from another language, binary-compatible to C; but I'd like to define everything with code, without need of a resource script. Is this possible or the way to go is write my own property-sheet-like, with underlying CreateWindow*() calls? (different approaches to do this are welcome, I'm new to WINAPI) which I suppose property sheet use behind the scenes
Found the solution! I found this post from Raymond Chen where he shows how do that.
the main code goes like this:
BOOL FakeMessageBox(HWND hwnd, LPCWSTR pszMessage, LPCWSTR pszTitle)
{
BOOL fSuccess = FALSE;
HDC hdc = GetDC(NULL);
if (hdc) {
NONCLIENTMETRICSW ncm = { sizeof(ncm) };
if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {
DialogTemplate tmp;
// Write out the extended dialog template header
tmp.Write<WORD>(1); // dialog version
tmp.Write<WORD>(0xFFFF); // extended dialog template
tmp.Write<DWORD>(0); // help ID
tmp.Write<DWORD>(0); // extended style
tmp.Write<DWORD>(WS_CAPTION | WS_SYSMENU | DS_SETFONT | DS_MODALFRAME);
tmp.Write<WORD>(2); // number of controls
tmp.Write<WORD>(32); // X
tmp.Write<WORD>(32); // Y
tmp.Write<WORD>(200); // width
tmp.Write<WORD>(80); // height
tmp.WriteString(L""); // no menu
tmp.WriteString(L""); // default dialog class
tmp.WriteString(pszTitle); // title
// Next comes the font description.
// See text for discussion of fancy formula.
if (ncm.lfMessageFont.lfHeight < 0) {
ncm.lfMessageFont.lfHeight = -MulDiv(ncm.lfMessageFont.lfHeight,
72, GetDeviceCaps(hdc, LOGPIXELSY));
}
tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfHeight); // point
tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfWeight); // weight
tmp.Write<BYTE>(ncm.lfMessageFont.lfItalic); // Italic
tmp.Write<BYTE>(ncm.lfMessageFont.lfCharSet); // CharSet
tmp.WriteString(ncm.lfMessageFont.lfFaceName);
// Then come the two controls. First is the static text.
tmp.AlignToDword();
tmp.Write<DWORD>(0); // help id
tmp.Write<DWORD>(0); // window extended style
tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE); // style
tmp.Write<WORD>(7); // x
tmp.Write<WORD>(7); // y
tmp.Write<WORD>(200-14); // width
tmp.Write<WORD>(80-7-14-7); // height
tmp.Write<DWORD>(-1); // control ID
tmp.Write<DWORD>(0x0082FFFF); // static
tmp.WriteString(pszMessage); // text
tmp.Write<WORD>(0); // no extra data
// Second control is the OK button.
tmp.AlignToDword();
tmp.Write<DWORD>(0); // help id
tmp.Write<DWORD>(0); // window extended style
tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE |
WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
tmp.Write<WORD>(75); // x
tmp.Write<WORD>(80-7-14); // y
tmp.Write<WORD>(50); // width
tmp.Write<WORD>(14); // height
tmp.Write<DWORD>(IDCANCEL); // control ID
tmp.Write<DWORD>(0x0080FFFF); // static
tmp.WriteString(L"OK"); // text
tmp.Write<WORD>(0); // no extra data
// Template is ready - go display it.
fSuccess = DialogBoxIndirect(g_hinst, tmp.Template(),
hwnd, DlgProc) >= 0;
}
ReleaseDC(NULL, hdc); // fixed 11 May
}
return fSuccess;
}

winapi - WM_DRAWITEM - comparing HMENU with HWND

I have implemented a custom drawn context menu (MFT_OWNERDRAW). When I create a context menu, I get an HMENU handle when calling CreatePopupMenu(). When I handle the WM_DRAWITEM message, I get an LPDRAWITEMSTRUCT:
LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam;
The DRAWITEMSTRUCT structure documentation describes the hwndItem field this way:
A handle to the control for combo boxes, list boxes, buttons, and static controls. For menus, this member is a handle to the menu that contains the item.
I need to check if the WM_DRAWITEM message belongs to my custom context menu. Does it mean that I can compare my context menu handle (HMENU) with the hwndItem (HWND) in this way?
//getHighlightMenuId returns HMENU returned by CreatePopupMenu
if((int)highlightMenu->getHighlightMenuId() == (int)drawItem->hwndItem))
{
}
Is it correct?
Yes, you would compare the DRAWITEMSTRUCT::hwndItem to your HMENU, eg:
LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam;
if (drawItem->CtlType == ODT_MENU)
{
HMENU hMenu = (HMENU)(drawItem->hwndItem);
if (highlightMenu->getHighlightMenuId() == hMenu)
{
// draw the menu item for drawItem->itemID within hMenu as needed ...
}
}

PollEvent() in Win32

I'm trying to mimic SFML's PollEvent(Event &event) function in Windows. It seems far more complicated that I imagined. Note that I already encapsulated the window procedure function in my class.
There could be many "window events" in my program - WindowMoved, WindowResized etc.
My first attempt was to have a private data member in the class, defined as WindowEvent *_lastWindowEvent. This variable will be set if PeekMessage() returns a non-zero value, just before DispatchMessage() is called. Then, winProc() will edit _lastWindowEvent, depending on the message it will receive.
The drawback here is that I noticed that winProc() may be called with a MSG parameter regardless of DispatchMessage(), like with the WM_SETCURSOR message.
Then I thought about having instead a std::queue<WindowEvent> in my class, when winProc() continuously pushes WindowEvents to it. The problem here is that sometimes the window procedure function keeps getting messages and won't return. This happens when I drag-move the window (then the WM_MOVING message is continuously called, along with other messages). The code after DispatchMessage() will not run until I release my mouse. This also happens when resizing the window.
Did I grasp anything wrong? How do you think such PollEvent function can be implemented?
Given that PollEvent is primarily for a game loop style design, you can probably poll for what you need while simultaneously servicing the Windows event loop:
class Window
{
HWND _hwnd; // Win32 handle to the window
RECT _lastWindowSize; // last known window size
POINT _lastMousePos; // last known mouse position on window
BYTE _lastKeyboardState[256]; // last known key state
std::list<Event> _events; // unprocessed events
public:
bool PollEvent(Event* pEvent);
};
bool Window::PollEvent(Event* pEvent)
{
// return any previously queued events
if (_events.size() > 0)
{
*pEvent = _events.pop_front();
return true;
}
// process 1 windows event message
if (PeekMessage(&msg, _hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.msg == WM_QUIT)
{
*pEvent = EXIT_EVENT; // special handling for WM_QUIT
return true;
}
}
// -----------------------------------------
// poll keyboard state
BYTE kbState[256];
GetKeyboardState(kbState);
bool isKeyboardEvent = false;
if (memcmp(_lastKeyboardState, kbState, 256) != 0)
{
// not shown
// compute diff of kbState and _lastKeyboardState
// generate a keyboard event and add to the queue
Event kbevt;
kbevt.type = KeyEvent;
kbevt.code = <computed code based on diff above>
_events.push_back(kbevt);
}
memcpy(_lastKeyboardState, kbState, 256);
// -----------------------------------------
// -----------------------------------------
// poll window size changes
RECT rectWindowSize;
int width, height, oldwidth, oldheight;
GetClientRect(&rectWindowSize);
width = rectWindowSize.right - rectWindowSize.left;
height = rectWindowSize.bottom - rectWindowSize.top;
oldwidth = _lastWindowSize.right - _lastWindowSize.left;
oldheight = _lastWindowSize.bottom - _lastWindowSize.top;
if ((width != oldwidth) || (height != oldheight))
{
Event sizeEvent;
sizeEvent.type = SizeEvent;
sizeEvent.width = width;
sizeEvent.height = height;
_events.push_back(kbevt);
}
_lastWindowSize = rectWindowSize;
// -----------------------------------------
// not shown - computing mouse position, joystick position, text stuff
// if at least one event was queued - return it now
if (_events.size() > 0)
{
*pEvent = _events.pop_front();
return true;
}
return false;
}

How do I get MessageBox icon using WinAPI

I have a WH_CALLWNDPROC hook code which handles WM_INITDIALOG message to get information about message boxes. I could get "Message", "Title", "Buttons" but I couldnt get "icon" information. I'm trying to use a function like below:
long getIcon(HWND hwnd) { // handle of messagebox dialog
HWND hlbl = GetDlgItem(hwnd,20);
wcout << "LABEL HWND: " << hlbl << endl;
if (hlbl != NULL) {
LRESULT r = SendMessage(hlbl,WM_GETICON,0,0);
return (long)r;
}
return 0;
}
function always returns 0. I have checked by MS Spy++ and I saw that icon handle is 0.
What is the correct way to get icon?
The icon that is displayed on the message box dialog is implemented using a STATIC control with SS_ICON style. You can obtain the icon handle by sending that control the STM_GETICON message.
In the code in your question, the variable named hlbl is actually the window handle of the STATIC control that contains the icon. I'd name it hIconWnd. With that name change, the code to obtain the icon would look like this:
HICON getIcon(HWND hwnd) { // handle of messagebox dialog
HWND hIconWnd = GetDlgItem(hwnd, 20);
if (hIconWnd != NULL) {
return (HICON)SendMessage(hIconWnd, STM_GETICON, 0, 0);
}
return NULL;
}

Resources