Win32: Modal dialog not returning focus - c++

I'm writing a win32 wrapper classes, mainly to learn more about win32 programming.
To get around the problem of c-style callbacks, the following method stores/retrieves the pointer using SetWindowLong/GetWindowLong and passes it to the actual winproc.
LRESULT CALLBACK WinClass::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// On window creation, WindowProc receives lParam as a LPCREATESTRUCT
// Store *this* pointer as long in GWL_USERDATA
if (msg == WM_NCCREATE)
::SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams));
// Retrieve the pointer
WinClass *wnd = reinterpret_cast<WinClass*>(::GetWindowLongPtr(hwnd, GWL_USERDATA));
// Call the actual winproc function
if (wnd)
return wnd->WndProc(hwnd, msg, wParam, lParam);
// Default to DefWindowProc message handler function
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
Winclass is the class wrapping the main window created by CreateWindowEx. The same WindowProc function is part of the MDlgClass wrapping the modal dialog. I'm calling the dialog like this
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(id), hwnd, DialogProc);
If I pass NULL as the hWndParent, the dialog works okay as a modeless dialog but if I pass hwnd, the handle to the main window as hWndParent the dialog works correctly as a modal dialog. However when i close the dialog it doesnt pass control back to the main parent window? Debugging in Visual Studio shows its hanging in the message pump in WinMain.
I thought of using a hashmap to map the pointers but I'd rather do it using GetWindowLong etc. Is this possible? I've tried storing the dialog pointer in DWL_USER but it doesnt help.
Any help would be appreciated, I'm still getting my head around Win32.
EDIT: I'm destroying the dialog using EndDialog
EDIT: I'm storing the pointer in the GWL_USERDATA region of the main window, which is not used by windows and I'm only modifying it in WinClass::WindowProc when the window is first created. If I don't instantiate a dialog class, I know the pointer is being accessed correctly since the application responds to menu commands processed via WindowProc and WM_COMMAND.

You can't use a WindowProc as a DialogProc. Window Procedures call DefWindowProc when they don't handle a message and return a meaningful result when they do.
Dialog Procedures return FALSE when they don't process a message, return TRUE when they DO, (except when they handle WM_INITDIALOG) and, if they have a meaningful result that they need to return from the outer window procedure, that is placed in DWL_MSGRESULT.
When you call the modal dialog box function, DialogBox, it enters a message pumping loop - which does dispatch messages to all windows in the thread so all windows continue to paint and process input - when the dialog is closed (using EndDialog), the DialogBox procedure should return.
When making a class to wrap dialog boxes, the usual method is to pass the 'this' pointer to One of the DialogBoxParam functions - which can be directly extracted from the WM_INITDIALOG message.

How are you closing the window? Are you using DestroyWindow? While the child window is live, the parent window will be disabled.

You're saving a pointer to lpCreateParams. Is it possible that the associated memory block is being freed or otherwise destroyed?

//static method
BOOL CALLBACK WinClass::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Store *this* pointer as long in GWL_USERDATA
if (msg == WM_INITDIALOG)
{
::SetWindowLongPtr(hwnd, DWLP_USER, reinterpret_cast(lParam));
m_hWnd = hWnd; // I assume you really don't want to keep passing the hwnd around
}
WinClass* wnd = reinterpret_cast(::GetWindowLongPtr(hwnd, GWL_USERDATA));
if (wnd)
return wnd->DlgProcImpl(umsg, wParam, lParam);
return FALSE;
}
BOOL WinClass::DlgProcImpl(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// your code goes here
return FALSE;
}
return FALSE;
}
INT_PTR WinClass:DoModalDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR template)
{
return ::DialogBoxParam(hInst, template, hwndParent, WinClass::DlgProc, this);
}

Related

How to handle mouse clicks in CMainFrame

How can I detect in an "empty" CMainFrame mouse clicks? With empty I mean a MDI which has not yet any document/view.
I have tried to detect mouse clicks with:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg);
MDI main frame windows have an 'invisible' client window that occupies the client area of the main frame. This window is inaccessible using 'normal' class override techniques but, if that main frame window is derived from either CMDIFrameWnd or CMDIFrameWndEx, you can use its m_hWndMDIClient member (the HWND of that invisible window) to subclass it, by overriding its WindowProc.
I do this (actually, to draw in that client area) in an override of the main frame's UpdateWindow procedure, using a bool member variable (set to false on construction) to keep track of whether or not the subclassing has already been done.
Here's a possible solution (adapted from my own code) that will likely work for intercepting mouse clicks. (I tested it and did actually get the Beep() diagnostic on mouse clicks!)
// Local function pointer to store the 'original' (default) window procedure...
LRESULT (CALLBACK *DefCliPrc)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = nullptr;
// Static definition of our override procedure...
static LRESULT CALLBACK ClientProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT answer = DefCliPrc(hWnd, uMsg, wParam, lParam); // First, call default proc.
if (uMsg == WM_LBUTTONDOWN) {
Beep(1000,1000); // Make a sound to show that it's working!
// <Insert your handling code here>
}
//...
// Intercept/handle other messages, as required ...
//...
return answer;
}
// Override of the UpdateWindow function, to enact the subclassing...
void MyMainFrame::UpdateWindow(void)
{
if (!funchange) { // Only do the sub-classing ONCE ...
DefCliPrc = (WNDPROC)(intptr_t)(::GetWindowLongPtr(m_hWndMDIClient, GWLP_WNDPROC));
::SetWindowLongPtr(m_hWndMDIClient, GWLP_WNDPROC, (intptr_t)(ClientProc));
funchange = true; // Set this 'flag' to prevent repetition!
}
CMDIFrameWnd::UpdateWindow(); // Should always call base class
return;
}

Subclassing an edit control from a user defined class/pointer-to-member-function

I think I've fallen in the same trap as many before me where I try to impose a nice OO methodology on win32 API programming. No MFC, no AFX, I'm not even using VC++, I'm using C::B with gcc.
I think what I'm trying to do is impossible, but since MFC exists (although I'm not using it) there must be some way.
I've created a class to contain several window controls. It implements handlers for WM_CREATE and WM_COMMAND, and keeps track of all the associated data around my small group of controls (ID codes and HWNDs).
It works great for buttons, static controls, even light GDI methods, but it all breaks down when I try to subclass an edit control.
Really, I just want to capture the "enter" key, but as anybody who's been down that road before will attest, when an edit control has focus, the parent window doesn't receive WM_KEYDOWN or WM_COMMAND, we are left to implement our own proc. Super lame.
OK, so subclassing an edit control is fine, if the editProc is global or static. I know that is because SetWindowLongPtr needs a function address, and that concept is nebulous for a member function.
So the object of my class is declared as "static" inside the parent WndProc. But the function is not "static" because then I wouldn't have access to non-static data members (completely defeating the purpose of this exercise). I'm hoping that because the objest is itself static, I should be able to properly define the address of one of its member functions.
Readers that have tried this before will either have given up and used MFC or something else, or perhaps have found a clever work-around.
I'll let this sample code do the rest of the talking: (simplified - will not compile as such)
/**** myprogram.c ****/
#include "MyControlGroup.h"
int winMain(){ // etc... }
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// object is static becuse it only needs to be initialized once
static MyControlGroup myControl;
if (msg == WM_CREATE)
myControl.onWMCreate(hWnd);
else if (msg == WM_COMMAND)
myControl.onWMCommand( wParam, lParam );
else if (msg == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProcW(l_hWnd, l_msg, l_wParam, l_lParam);
}
The header file for my class:
/**** MyControlGroup.h ****/
class MyControlGroup
{
private:
HWND m_hWndParent;
HWND m_hWndEditBox;
int m_editBoxID;
public:
MyControlGroup();
void onWMCreate(HWND);
void onWMCommand(WPARAM, LPARAM);
// want to find a way to pass the address of this function to SetWindowLongPtr
LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
...and the implementation:
/**** MyControlGroup.cpp ****/
static int staticID = 1;
MyControlGroup::MyControlGroup()
{
m_editBoxID = staticID++;
}
void MyControlGroup::onWMCreate(HWND hWnd)
{
// My control group has buttons, static controls, and other stuff which are created here with CreateWindowW. It also has an edit control:
m_hWndEditBox = CreateWindowW(L"EDIT", L"initial text", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 150, 20, hWnd, (HMENU)m_editBoxID, NULL, NULL);
/*
To subclass the edit control, I need a pointer to my customized proc. That means I
need a pointer-to-member-function, but SetWindowLongPtr needs a pointer to global or
static function (__stdcall or CALLBACK, but not __thiscall).
*/
// I'd like to do something like this, adapted from a great write-up at
// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
LERSULT (MyControlGroup::*myEditProcPtr)(HWND, UINT, WPARAM, LPARAM);
myEditProcPtr = &MyControlGroup::myEditProc;
// Up to now it compiles ok, but then when I try to pass it to SetWindowLongPtr, I get
// an "invalid cast" error. Any ideas?
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProcPtr);
}
void MyControlGroup::onWMCommand(WPARAM wParam, LPARAM lParam){ /* process parent window messages. Editboxes don't generate WM_COMMAND or WM_KEYDOWN in the parent :''( */}
LRESULT MyControlGroup::myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// process messages like IDOK, WM_KEYDOWN and so on in the edit control
}
Even once I get this done, I'll still need to figure out a way to pass the address of the parent WndProc to myEditProc for the return value, but until I get past this there is no point in worrying about that.
Thanks in advance for reading!
myEditProc needs to be a static function.
Once you've done that you can pass the address of the function directly without going through the intermediate variable:
static LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
...
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProc);
To access your class data from the static function, you can save it in the userdata field of the edit control, e.g.:
// before sub-classing the control
SetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA, (LPARAM)this);
// in the sub-class procedure
MyControlGroup* pThis = (MyControlGroup*)GetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA);
But as #K-ballo suggested, SetWindowSubclass is definitely the way to do this unless you want compatibility with pre-XP. It handles the sub-classing procedure for you automatically, lets you associate a userdata pointer (e.g. this) that is automatically passed to the sub-class procedure, and safely handles removing the sub-class at the end.

How to use DialogBoxParam?

I have a pre-made template resource dialog, and I want to use DialogBoxParam to display it, but I can't find any good examples over the internet. The dialog is a simple login dialog, so can someone explain how to build my lpDialogFunc and what to put in dwInitParam?
You've tagged this question as C++, but havn't specified any particular framework (such as ATL or MFC).
So, in the spirit of providing a c++ / OOP answer to the question, without using a framework, the first thing to do is to create a class to wrap the dialog box, as well as provide a way for the dialog proc to reliably retrieve the pointer to the class. The windows API is a C API and cannot call class members directly so it is necessary to create static methods that can then retrieve the classes this pointer from somewhere.
class MyDialog {
HWND _dlg;
public:
int RunModal(HINSTANCE resModule, UINT resId,HWND parent){
return DialogBoxParam(resModule,MAKEINTRESOURCE(resId),parent,&StaticDialogProc,(LPARAM)this);
}
protected:
static INT_PTR CALLBACK StaticDialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){
MyDialog* self;
if(uMsg == WM_INITDIALOG){
self = (MyDialog*)lParam;
self->_dlg = hwndDlg;
SetWindowLongPtr(hwndDlg,DWLP_USER,lParam);
}
else
self = (MyDialog*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
if(self)
return self->DialogProc(uMsg,wParam,lParam);
return FALSE;
}
virtual UINT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam){
switch(uMsg){
case WM_INITDIALOG:
OnInitDialog();
break;
case WM_COMMAND:
OnCommand(LOWORD(wParam),HIWORD(wParam),(HWND)lParam);
break;
default:
return FALSE;
}
return TRUE;
}
virtual void OnInitDialog(){
}
virtual void OnCommand(int id, USHORT notifyCode,HWND control){
EndDialog(_hdlg,id);
}
};
Now, there are hundreds of window messages that Windows can send to a dialog. Add handlers for each message to DialogProc and call a specific virtual function so derived classes can handle the message differently by overriding the virtual.
The critical messages to handle are usually WM_INITDIALOG which is sent as soon as the dialog is created, so is an ideal time to initialize any controls on the dialog - to populate drop down controls, or SetWindowText to initielize text boxes with default values.
and WM_COMMAND, which is sent by controls like buttons, when they are clicked, passing in their id, and this is where you would handle the OK and CANCEL buttons.
Once DialogBoxParam returns, the dialog and all its child controls has been destroyed, so you would typically extract all the input fields in the OnCommand handler and store them in class members before calling EndDialog.
Another use case for the second part of the question: "what to put in dwInitParam"?
If you prefer OO programming and do not want to use the global scope for your dialog box, you can pass this to the formal parameter dwInitParam.
Obtaining a pointer to the caller:
template< typename CallerT >
inline CallerT *GetDialogCaller(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (WM_INITDIALOG != uMsg) {
// Retrieves information about the specified window.
// 1. A handle to the window and, indirectly, the class to which the window belongs.
// 2. Retrieves the user data associated with the window.
return reinterpret_cast< CallerT * >(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
}
CallerT * const caller = reinterpret_cast< CallerT * >(lParam);
// Changes an attribute of the specified window.
// 1. A handle to the window and, indirectly, the class to which the window belongs.
// 2. Sets the user data associated with the window.
// 3. The replacement value.
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, reinterpret_cast< LONG_PTR >(caller));
return caller;
}
Delegating the message to the caller:
class Widget {
public:
static INT_PTR CALLBACK DialogProcDelegate(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// Retrieve a pointer to the instance of Widget
// that called DialogBoxParam.
Widget * const widget = GetDialogCaller< Widget>(hwndDlg, uMsg, wParam, lParam);
// Delegate the message handling.
return widget->DialogProc(hwndDlg, uMsg, wParam, lParam);
}
INT_PTR Show() const {
return DialogBoxParam(nullptr, MAKEINTRESOURCE(IDD_WIDGET_SETTINGS), nullptr, DialogProcDelegate, reinterpret_cast< LPARAM >(this));
}
private:
INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// Note that this method is not affected by our approach,
// i.e. this method will still receive a WM_INITDIALOG.
switch (uMsg) {
...
}
return FALSE;
}
};
The alternative puts the caller in global scope and is restricted to a single caller for all dialog boxes.
you can do something like this. The dwInitParam Specifies the value to pass to the dialog box in the lParam parameter of the WM_INITDIALOG message. You can pass any value or simply pass NULL
INT_PTR CALLBACK editDlg(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
return 1;
break;
}
return 0;
}
if(DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_EDIT),hwndMain,editDlg,NULL)==IDOK)
{
}

Pass extra wParam/lParam parameters?

A standard window procedure function takes this prototype:
LRESULT CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
When a message such as WM_MOUSEMOVE or WM_CHAR, the WndProc function will receive the window the message originated from, and any extra parameters, which will be with msg and wParam/lParam.
What I have now is a class. Say
class Random
{
public:
void Initialize ();
private:
void Draw ();
HWND hWnd;
friend LRESULT CALLBACK RandomProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
After the hWnd is initialized and created by Initialize (), it will send messages such as WM_LBUTTONDOWN to RandomProc. Once a message is received, I would like RandomProc to use Draw () to redraw the window of the class Random.
The thing is, I will have multiple Random variables, and each will have a window. All the windows will send their messages to RandomProc, and will want it to redraw the corresponding windows of the hWnd. I do not know which random variable sent the message based upon the hWnd parameter nor the msg/wParam/lParam, and so cannot access the appropriate Draw () function and cannot redraw the correct window.
Is there a way to pass a pointer to the class of the window to the Procedure every time a message is sent or is there another way to access the Random class whose hWnd sent the message?
Aren't you looking for the GetWindowLongPtr/SetWindowLongPtr functions?
This function assigns/retrieves arbitrary pointer to/from the window handle. You might assign the pointer to your Random class instance to each window you create. In the RandomProc you just use the GetWindowLongPtr and cast the pointer to Random*.
As Chris says in a comment, use the GWLP_USERDATA attribute to assign the pointer.

sending lparam as a pointer to class, and use it in WndProc()

i have this abstract code :
i want to use lParam (last parameter) in CreateWindowEx() to save a pointer to a class thats declared in the begining of main - SaveArr. then, i want to use it in the function WndProc.
in the begining i did a global array, and then i could use it anywhere, but its not so "clever" as far as c++ concern, so im trying to upgrade it a bit.
class Samples
{
int arr[ITERATIONS+1];
int index;
...
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
Samples * SaveArr;
...
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
ClsName,
WindowCaption,
WS_OVERLAPPEDWINDOW,
INITIAL_WIN_LOCAT_X,
INITIAL_WIN_LOCAT_Y,
WIN_WIDTH,
WIN_HIGHT,
NULL,
NULL,
hInstance,
NULL); //here i want to pass SaveArr, so that i can use it in the WndProc(...) function
...
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
... //here i would like to use lParam as the class pointer, meaning using the
SaveArr declared in the main function.
}
}
Adding caller information to the window:
m_window = CreateWindow(..., this);
Similar for the extended CreateWindowEx.
Obtaining a pointer to the caller:
template< typename CallerT >
[[nodiscard]]
CallerT* WindowCaller(HWND window, UINT message, LPARAM lParam) noexcept
{
if (message == WM_NCCREATE) [[unlikely]]
{
const auto caller = reinterpret_cast< CallerT* >(
reinterpret_cast< CREATESTRUCT* >(lParam)->lpCreateParams);
// Change the user data of the window for subsequent messages.
::SetWindowLongPtr(window, GWLP_USERDATA,
reinterpret_cast< LONG_PTR >(caller));
return caller;
}
else
{
// Retrieve the user data of the window.
return reinterpret_cast< CallerT* >(
::GetWindowLongPtr(window, GWLP_USERDATA));
}
}
This method needs to be called in your message callback.
Best way would be
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
Samples *savearr = (Samples*)GetWindowLong(hWnd,GWL_USERDATA)
switch(Msg)
{
case WM_CREATE:
SetWindowLong(hWnd, GWL_USERDATA, (LONG)lParam);
break;
}
}
The next time the WndProc is called the value would be in savearr, and can be used.
From the reference:
lpParam [in, optional]
Type: LPVOID
Pointer to a value to be passed to the window through the
CREATESTRUCT structure (lpCreateParams member) pointed to by the
lParam param of the WM_CREATE message. This message is sent to the
created window by this function before it returns.
If an application calls CreateWindow to create a MDI client
window, lpParam should point to a CLIENTCREATESTRUCT structure. If an
MDI client window calls CreateWindow to create an MDI child window,
lpParam should point to a MDICREATESTRUCT structure. lpParam may be
NULL if no additional data is needed.
You're expecting the lParam to be always passed to WndProc, but it is only passed with WM_CREATE.
Note, that even then it's not passed directly, but rather through a structure which is the actual lParam for WM_CREATE.
Your only chance to read the lParam is during WM_CREATE. If you want to keep using the value later then you must store it somewhere. Maybe as a static of the WndProc or otherwise assign it to something else which is going to be scoped.
Why all the insistence on using that last, lpParam value set to X, then catching it on WM_CREATE (through all that indirect struct stuff, no less!) and then setting GWL_USERDATA?!
Why not cut to the chase and do this:
HWND H=CreateWindow(.....)
SetWindowLong(H,GWL_USERDATA,X)
In other words, just put X there directly, yourself, right after the window creation statement.
In my tests it works, and so long as you test the window handle against some list of known handles, you can prevent some errant message picked up by your program, and prevent inappropriate use of something else's userdata.