I have a parameterized generic dialog that I create with DialogBoxParam
that accepts a param data object,
INPUT_PARAMS* inputParams = new INPUT_PARAMS();
inputParams->caption = ...;
inputParams->text = ...;
inputParams->okFunc = ...
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_INPUT), InputDlgProc, (LPARAM)inputParams);
In the dialog proc, the custom data is available to me in WM_INITDIALOG
as LPARAM
, but not in any of the other messages.
INT_PTR CALLBACK InputDlgProc(HWND hWndDlg, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_INITDIALOG:
{
INPUT_PARAMS* inputParams = (INPUT_PARAMS*)lParam;
// ... Set dialog attributes based on params
SetWindowText(hWndDlg, inputParams->caption.c_str());
// etc.
return TRUE;
}
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
{
// ... Still need to use data object here for OK logic, not available
EndDialog(hWndDlg, LOWORD(wParam));
break;
}
}
break;
}
return DefWindowProc(hWndDlg, message, wParam, lParam);
}
Throughout the dialog's duration I need to have the object available so that the IDOK
WM_COMMAND
can use it for its logic. I wish I could store it like a data attribute in an overarching class, but I'm not using C++ or MFC here. Any good solutions?
Also, the only place to free the object would seem to be WM_INITDIALOG
but that's too early. The dialog always needs that param object to live alongside itself.
You can use SetWindowLongPtr()
to store the object pointer inside the dialog HWND
, and GetWindowLongPtr()
to retrieve it, eg:
INT_PTR CALLBACK InputDlgProc(HWND hWndDlg, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_INITDIALOG:
{
INPUT_PARAMS* inputParams = reinterpret_cast<INPUT_PARAMS*>(lParam);
SetWindowLongPtr(hWndDlg, DWLP_USER, reinterpret_cast<LONG_PTR>(inputParams));
// ...
return TRUE;
}
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
{
INPUT_PARAMS* inputParams = reinterpret_cast<INPUT_PARAMS*>(GetWindowLongPtr(hWndDlg, DWLP_USER));
// ...
EndDialog(hWndDlg, LOWORD(wParam));
return TRUE;
}
}
break;
}
return FALSE;
}
Also, DialogBoxParam()
is a blocking function - it does not exit until the dialog is closed:
The
DialogBoxParam
function uses theCreateWindowEx
function to create the dialog box.DialogBoxParam
then sends aWM_INITDIALOG
message (and aWM_SETFONT
message if the template specifies theDS_SETFONT
orDS_SHELLFONT
style) to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies theWS_VISIBLE
style), disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.When the dialog box procedure calls the
EndDialog
function,DialogBoxParam
destroys the dialog box, ends the message loop, enables the owner window (if previously enabled), and returns thenResult
parameter specified by the dialog box procedure when it calledEndDialog
.
So, there is no need to allocate the object dynamically at all. Just declare it locally, pass a pointer to it, and let it go out of scope after the dialog is finished, eg:
INPUT_PARAMS inputParams;
inputParams.caption = ...;
inputParams.text = ...;
inputParams.okFunc = ...;
DialogBoxParam(..., reinterpret_cast<LPARAM>(&inputParams));
Also, DO NOT call DefWindowProc()
inside of your InputDlgProc()
function, per the documentation:
Typically, the dialog box procedure should return TRUE if it processed the message, and FALSE if it did not. If the dialog box procedure returns FALSE, the dialog manager performs the default dialog operation in response to the message.
If the dialog box procedure processes a message that requires a specific return value, the dialog box procedure should set the desired return value by calling
SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult)
immediately before returning TRUE. Note that you must callSetWindowLong
immediately before returning TRUE; doing so earlier may result in theDWL_MSGRESULT
value being overwritten by a nested dialog box message....
You should use the dialog box procedure only if you use the dialog box class for the dialog box. This is the default class and is used when no explicit class is specified in the dialog box template. Although the dialog box procedure is similar to a window procedure, it must not call the
DefWindowProc
function to process unwanted messages. Unwanted messages are processed internally by the dialog box window procedure.