I need to make some changes to a TaskDialog before it is shown to the user. It's fairly simple to use Windows API calls to work with each of the controls on the dialog box. I need to be more sure which button I have found. I would have expected to find a place where I could read the result the button would give if pressed.
in other words, if I pressed a button that would cause a return value (in Delphi, it's called a modal result) of 100, I would have expected there to be an API call I could call to find out what the button's "return value" would be. I haven't yet found any such call.
I don't want to rely on the button text..
Here's what I have so far.
function EnumWindowsProcToFindDlgControls(hWindow: HWND; _param:LPARAM): BOOL; stdcall;
var
sClassName:string;
hBMP:THandle;
i:integer;
begin
SetLength(sClassName, MAX_PATH);
GetClassName(hWindow, PChar(sClassName), MAX_PATH);
SetLength(sClassName, StrLen(PChar(sClassName)));
if sClassName='Button' then
begin
// always 0...
i:=GetDlgCtrlID(hWindow);
if (i=100) or (i=102) then
begin
hBmp := LoadImage(HInstance, 'DISA', IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE or LR_LOADTRANSPARENT );
SendMessage(hWindow, BM_SETIMAGE, WPARAM(IMAGE_BITMAP), LPARAM(hBmp));
end;
end;
// keep looking
Result:=true;
end;
procedure TForm2.TaskDialog1DialogConstructed(Sender: TObject);
begin
EnumChildWindows(TaskDialog1.Handle, @EnumWindowsProcToFindDlgControls, 0);
end;
I suspect it's not entirely "respectable" to do things like this with a dialog.
This is a Delphi 10 Win32 application using Delphi's VCL TTaskDialog component which is a wrapper around Windows task dialog feature. before it's shown, the OnConstructed event fires, executing this code.
Thank you for your help!
Win32 buttons do not have "return values", which is why there is no API to retrieve such a value from them. What you are thinking of is strictly a VCL feature.
In Win32 API terms, a button can have a control ID, and in the case of MessageBox()
, for example, standard ID values like IDOK
, IDCANCEL
, etc are assigned to the dialog buttons. When a button is clicked and the dialog is closed, the button's control ID is used as the function return value.
But task dialogs do not use control IDs, which is why you do not see any assigned to the dialog buttons.
To identify a particular task dialog button, I can think of two ways:
during child enumeration, retrieve each button's caption text (GetWindowText()
), and compare that to captions you are interested in. Just know that the standard buttons (from the TTaskDialog.CommonButtons
property) use localized text, which does not make this a well-suited option for locating standard buttons unless you have control over the app's locale settings.
send the dialog a TDM_ENABLE_BUTTON
message to temporarily disable the desired button that has a given ID, then enumerate the dialog's controls until you find a disabled child window (using IsWindowEnabled()
), and then re-enable the control. You can then manipulate the found window as needed.
For Task Dialog messages and Task Dialog Notifications that operate on buttons (like TDN_BUTTON_CLICKED
, which triggers the TTaskDialog.OnButtonClicked
event), the standard buttons use IDs like IDOK
, IDCANCEL
, etc while custom buttons (from the TTaskDialog.Buttons
property) use their ModalResult
property as their ID.
You can send TDM_ENABLE_BUTTON
directly via SendMessage()
for standard buttons, or via the TTaskDialogBaseButtonItem.Enabled
property for custom buttons.
For #2, this works when I try it:
uses
Winapi.CommCtrl;
function FindDisabledDlgControl(hWindow: HWND; _param: LPARAM): BOOL; stdcall;
type
PHWND = ^HWND;
begin
if not IsWindowEnabled(hWindow) then
begin
PHWND(_param)^ := hWindow;
Result := False;
end else
Result := True;
end;
procedure TForm2.TaskDialog1DialogConstructed(Sender: TObject);
var
hButton: HWND;
begin
// common tcbOk button
SendMessage(TaskDialog1.Handle, TDM_ENABLE_BUTTON, IDOK, 0);
hButton := 0;
EnumChildWindows(TaskDialog1.Handle, @FindDisabledDlgControl, LPARAM(@hButton));
SendMessage(TaskDialog1.Handle, TDM_ENABLE_BUTTON, IDOK, 1);
if hButton <> 0 then
begin
// use hButton as needed...
end;
// custom button
TaskDialog1.Buttons[0].Enabled := False;
hButton := 0;
EnumChildWindows(TaskDialog1.Handle, @FindDisabledDlgControl, LPARAM(@hButton));
TaskDialog1.Buttons[0].Enabled := True;
if hButton <> 0 then
begin
// use hButton as needed...
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With