2024-08-04 19:59:25 +02:00
unit Shared. TaskDialogFunc;
2018-12-03 17:58:37 +01:00
{
Inno Setup
2020-06-25 08:50:40 +02:00
Copyright ( C) 1 9 9 7 - 2 0 2 0 Jordan Russell
2018-12-03 17:58:37 +01:00
Portions by Martijn Laan
For conditions of distribution and use, see LICENSE. TXT.
TaskDialogMsgBox function integrating with CmnFunc' s MsgBox functions
}
interface
uses
2024-08-04 19:59:25 +02:00
Windows, Shared. CommonFunc. Vcl;
2018-12-03 17:58:37 +01:00
2020-06-18 08:37:45 +02:00
function TaskDialogMsgBox( const Icon, Instruction, Text , Caption: String ; const Typ: TMsgBoxType; const Buttons: Cardinal ; const ButtonLabels: array of String ; const ShieldButton: Integer ; const VerificationText: String = '' ; const pfVerificationFlagChecked: PBOOL = nil ) : Integer ;
2018-12-03 17:58:37 +01:00
implementation
uses
2024-04-02 16:35:06 +02:00
Classes, StrUtils, Math, Forms, Dialogs, SysUtils,
2024-08-06 19:12:28 +02:00
Commctrl, Shared. CommonFunc, {$IFDEF SETUPPROJ} Setup. InstFunc, {$ENDIF} PathFunc;
2018-12-03 17:58:37 +01:00
var
TaskDialogIndirectFunc: function( const pTaskConfig: TTaskDialogConfig;
pnButton: PInteger ; pnRadioButton: PInteger ;
pfVerificationFlagChecked: PBOOL) : HRESULT; stdcall ;
function ShieldButtonCallback( hwnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM; lpRefData: LONG_PTR) : HResult; stdcall ;
begin
if ( msg = TDN_CREATED) and ( lpRefData < > 0 ) then
SendMessage( hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, lpRefData, 1 ) ;
Result : = S_OK;
end ;
2020-06-18 08:37:45 +02:00
function DoTaskDialog( const hWnd: HWND; const Instruction, Text , Caption, Icon: PWideChar ; const CommonButtons: Cardinal ; const ButtonLabels: array of String ; const ButtonIDs: array of Integer ; const ShieldButton: Integer ; const RightToLeft: Boolean ; const TriggerMessageBoxCallbackFuncFlags: LongInt ; var ModalResult: Integer ; const VerificationText: PWideChar ; const pfVerificationFlagChecked: PBOOL) : Boolean ;
2018-12-03 17:58:37 +01:00
var
Config: TTaskDialogConfig;
2018-12-09 16:31:39 +01:00
NButtonLabelsAvailable: Integer ;
ButtonItems: TTaskDialogButtons;
ButtonItem: TTaskDialogButtonItem;
I: Integer ;
2018-12-09 16:54:22 +01:00
ActiveWindow: Windows. HWND;
WindowList: Pointer ;
2018-12-03 17:58:37 +01:00
begin
if Assigned( TaskDialogIndirectFunc) then begin
2019-01-21 19:19:43 +01:00
ZeroMemory( @ Config, Sizeof( Config) ) ;
Config. cbSize : = SizeOf( Config) ;
2025-06-08 10:24:21 +02:00
if ( StrPos( Text , ':\' ) < > nil ) or ( StrPos( Text , '\\' ) < > nil ) then
Config. dwFlags : = Config. dwFlags or TDF_SIZE_TO_CONTENT;
2019-01-21 19:19:43 +01:00
if RightToLeft then
Config. dwFlags : = Config. dwFlags or TDF_RTL_LAYOUT;
Config. hInstance : = HInstance;
2024-12-18 01:45:54 -06:00
Config. hwndParent : = hWnd;
2019-01-21 19:19:43 +01:00
Config. dwCommonButtons : = CommonButtons;
Config. pszWindowTitle : = Caption;
Config. pszMainIcon : = Icon;
Config. pszMainInstruction : = Instruction;
Config. pszContent : = Text ;
2020-06-18 08:37:45 +02:00
if VerificationText < > '' then
Config. pszVerificationText : = VerificationText;
2019-01-21 19:19:43 +01:00
if ShieldButton < > 0 then begin
Config. pfCallback : = ShieldButtonCallback;
Config. lpCallbackData : = ShieldButton;
end ;
ButtonItems : = nil ;
2018-12-03 17:58:37 +01:00
try
2019-01-21 19:19:43 +01:00
NButtonLabelsAvailable : = Length( ButtonLabels) ;
if NButtonLabelsAvailable < > 0 then begin
ButtonItems : = TTaskDialogButtons. Create( nil , TTaskDialogButtonItem) ;
Config. dwFlags : = Config. dwFlags or TDF_USE_COMMAND_LINKS;
for I : = 0 to NButtonLabelsAvailable- 1 do begin
ButtonItem : = TTaskDialogButtonItem( ButtonItems. Add) ;
ButtonItem. Caption : = ButtonLabels[ I] ;
ButtonItem. ModalResult : = ButtonIDs[ I] ;
end ;
Config. pButtons : = ButtonItems. Buttons;
Config. cButtons : = ButtonItems. Count;
2018-12-03 17:58:37 +01:00
end ;
2019-01-21 19:19:43 +01:00
TriggerMessageBoxCallbackFunc( TriggerMessageBoxCallbackFuncFlags, False ) ;
ActiveWindow : = GetActiveWindow;
2024-12-18 01:45:54 -06:00
WindowList : = DisableTaskWindows( Config. hwndParent) ;
2018-12-03 17:58:37 +01:00
try
2020-06-18 08:37:45 +02:00
Result : = TaskDialogIndirectFunc( Config, @ ModalResult, nil , pfVerificationFlagChecked) = S_OK;
2018-12-03 17:58:37 +01:00
finally
2019-01-21 19:19:43 +01:00
EnableTaskWindows( WindowList) ;
SetActiveWindow( ActiveWindow) ;
TriggerMessageBoxCallbackFunc( TriggerMessageBoxCallbackFuncFlags, True ) ;
2018-12-03 17:58:37 +01:00
end ;
2019-01-21 19:19:43 +01:00
finally
ButtonItems. Free;
2018-12-03 17:58:37 +01:00
end ;
end else
Result : = False ;
end ;
2024-04-02 16:35:06 +02:00
procedure DoInternalError( const Msg: String ) ;
begin
{$IFDEF SETUPPROJ}
InternalError( Msg) ;
{$ELSE}
raise Exception. Create( Msg) ;
{$ENDIF}
end ;
2020-06-18 08:37:45 +02:00
function TaskDialogMsgBox( const Icon, Instruction, Text , Caption: String ; const Typ: TMsgBoxType; const Buttons: Cardinal ; const ButtonLabels: array of String ; const ShieldButton: Integer ; const VerificationText: String = '' ; const pfVerificationFlagChecked: PBOOL = nil ) : Integer ;
2018-12-03 17:58:37 +01:00
var
2018-12-12 20:05:43 +01:00
IconP: PChar ;
2018-12-09 16:31:39 +01:00
TDCommonButtons: Cardinal ;
NButtonLabelsAvailable: Integer ;
ButtonIDs: array of Integer ;
2018-12-03 17:58:37 +01:00
begin
2024-12-16 02:00:00 -06:00
Application. Restore; { See comments in AppMessageBox }
2018-12-12 20:05:43 +01:00
if Icon < > '' then
IconP : = PChar( Icon)
else begin
case Typ of
mbInformation: IconP : = TD_INFORMATION_ICON;
mbError: IconP : = TD_WARNING_ICON;
mbCriticalError: IconP : = TD_ERROR_ICON;
else
IconP : = nil ; { No other TD_ constant available, MS recommends to use no icon for questions now and the old icon should only be used for help entries }
end ;
2018-12-03 17:58:37 +01:00
end ;
2018-12-09 16:31:39 +01:00
NButtonLabelsAvailable : = Length( ButtonLabels) ;
2018-12-03 17:58:37 +01:00
case Buttons of
2018-12-10 09:35:43 +01:00
MB_OK, MB_OKCANCEL:
2018-12-09 16:31:39 +01:00
begin
if NButtonLabelsAvailable = 0 then
2018-12-10 09:35:43 +01:00
TDCommonButtons : = TDCBF_OK_BUTTON
2018-12-09 16:31:39 +01:00
else begin
2018-12-10 09:35:43 +01:00
TDCommonButtons : = 0 ;
ButtonIDs : = [ IDOK] ;
end ;
if Buttons = MB_OKCANCEL then
TDCommonButtons : = TDCommonButtons or TDCBF_CANCEL_BUTTON;
end ;
MB_YESNO, MB_YESNOCANCEL:
begin
if NButtonLabelsAvailable = 0 then
TDCommonButtons : = TDCBF_YES_BUTTON or TDCBF_NO_BUTTON
else begin
TDCommonButtons : = 0 ;
2018-12-09 16:31:39 +01:00
ButtonIDs : = [ IDYES, IDNO] ;
end ;
2018-12-10 09:35:43 +01:00
if Buttons = MB_YESNOCANCEL then
TDCommonButtons : = TDCommonButtons or TDCBF_CANCEL_BUTTON;
end ;
MB_RETRYCANCEL:
begin
if NButtonLabelsAvailable = 0 then
TDCommonButtons : = TDCBF_RETRY_BUTTON
else begin
TDCommonButtons : = 0 ;
ButtonIDs : = [ IDRETRY] ;
end ;
TDCommonButtons : = TDCommonButtons or TDCBF_CANCEL_BUTTON;
2018-12-09 16:31:39 +01:00
end ;
2019-01-10 05:53:28 +01:00
MB_ABORTRETRYIGNORE:
begin
if NButtonLabelsAvailable = 0 then
2024-04-02 16:35:06 +02:00
DoInternalError( 'TaskDialogMsgBox: Invalid ButtonLabels' )
2019-01-10 05:53:28 +01:00
else
ButtonIDs : = [ IDRETRY, IDIGNORE, IDABORT] ; { Notice the order, abort label must be last }
TDCommonButtons : = 0 ;
end ;
2018-12-09 16:31:39 +01:00
else
begin
2024-04-02 16:35:06 +02:00
DoInternalError( 'TaskDialogMsgBox: Invalid Buttons' ) ;
2018-12-09 16:31:39 +01:00
TDCommonButtons : = 0 ; { Silence compiler }
end ;
2018-12-03 17:58:37 +01:00
end ;
2018-12-09 16:31:39 +01:00
if Length( ButtonIDs) < > NButtonLabelsAvailable then
2024-04-02 16:35:06 +02:00
DoInternalError( 'TaskDialogMsgBox: Invalid ButtonLabels' ) ;
2024-12-18 01:45:54 -06:00
if not DoTaskDialog( GetOwnerWndForMessageBox, PChar( Instruction) , PChar( Text ) ,
2018-12-12 20:05:43 +01:00
GetMessageBoxCaption( PChar( Caption) , Typ) , IconP, TDCommonButtons, ButtonLabels, ButtonIDs, ShieldButton,
2020-06-18 08:37:45 +02:00
GetMessageBoxRightToLeft, IfThen( Typ in [ mbError, mbCriticalError] , MB_ICONSTOP, 0 ) , Result , PChar( VerificationText) , pfVerificationFlagChecked) then //note that MB_ICONEXCLAMATION (used by mbError) includes MB_ICONSTOP (used by mbCriticalError)
2019-01-17 15:26:40 +01:00
Result : = 0 ;
2018-12-03 17:58:37 +01:00
end ;
procedure InitCommonControls; external comctl32 name 'InitCommonControls' ;
initialization
InitCommonControls;
TaskDialogIndirectFunc : = GetProcAddress( GetModuleHandle( comctl32) , 'TaskDialogIndirect' ) ;
end .