When I repeat controls on a form, how can I identify specific buttons?

I need to make some changes to TaskDialog before it is shown to the user. Simply use the Windows API calls to work with each of the controls in the dialog box. I need to be sure which button I found. I would expect to find a place where I could read the result that the button will give when clicked.

In other words, if I clicked on a button that would call a return value (in Delphi, it is called a modal result) at 100, I would expect that there would be an API call that I could call to find out that the "return value" button will be. I have not found such a call.

I do not want to rely on the button text.

Here is what I still have.

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 that it is not entirely β€œrespectable” to do such things with dialogue.

This is a Delphi 10 Win32 application using the Delphi VCL component TTaskDialog, which is a wrapper around the Windows task dialog. before it is shown, the OnConstructed event is fired, executing this code.

Thank you for your help!

+5
source share
1 answer

Win32 buttons do not have "return values", so the API cannot extract such a value from them. What you are thinking is strictly a function of VCL.

In terms of the Win32 API, a button can have a control identifier, and in the case of MessageBox() , for example, standard identification values ​​are assigned to dialog buttons, such as IDOK , IDCANCEL , etc. When the button is pressed and the dialog is closed, the control identifier is used as the return value of the function.

But task dialogs do not use control identifiers, so you do not see any dialog buttons assigned to buttons.

To define a specific task dialog button, I can present two ways:

  • while listing children, get the text of each button ( GetWindowText() ) and compare this with the headings that interest you. Just be aware that the button standard (from the TTaskDialog.CommonButtons property) uses localized text, which does not make it a suitable option to search for standard buttons if you do not control the application locale settings.

  • send the TDM_ENABLE_BUTTON dialog box to temporarily disable the desired button with the given identifier, then list the dialog box controls until you find the disabled one (using IsWindowEnabled() ), and then turn on the control again. Then you can manipulate the found window.

    For task dialog messages and task dialog notifications that work with buttons (for example, TDN_BUTTON_CLICKED , which fires the TTaskDialog.OnButtonClicked event), standard buttons use identifiers like IDOK , IDCANCEL , etc., while custom buttons (from properties of TTaskDialog.Buttons ) use their ModalResult as an identifier.

    You can send TDM_ENABLE_BUTTON directly through SendMessage() for standard buttons or through the TTaskDialogBaseButtonItem.Enabled property for custom buttons.

For # 2, this works when I try:

 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; 
+9
source

All Articles