189 lines
7.2 KiB
ObjectPascal
189 lines
7.2 KiB
ObjectPascal
unit Shared.TaskDialogFunc;
|
|
|
|
{
|
|
Inno Setup
|
|
Copyright (C) 1997-2020 Jordan Russell
|
|
Portions by Martijn Laan
|
|
For conditions of distribution and use, see LICENSE.TXT.
|
|
|
|
TaskDialogMsgBox function integrating with CmnFunc's MsgBox functions
|
|
}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Shared.CommonFunc.Vcl;
|
|
|
|
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;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Classes, StrUtils, Math, Forms, Dialogs, SysUtils,
|
|
Commctrl, Shared.CommonFunc, {$IFDEF SETUPPROJ} Setup.InstFunc, {$ENDIF} PathFunc;
|
|
|
|
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;
|
|
|
|
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;
|
|
var
|
|
Config: TTaskDialogConfig;
|
|
NButtonLabelsAvailable: Integer;
|
|
ButtonItems: TTaskDialogButtons;
|
|
ButtonItem: TTaskDialogButtonItem;
|
|
I: Integer;
|
|
ActiveWindow: Windows.HWND;
|
|
WindowList: Pointer;
|
|
begin
|
|
if Assigned(TaskDialogIndirectFunc) then begin
|
|
ZeroMemory(@Config, Sizeof(Config));
|
|
Config.cbSize := SizeOf(Config);
|
|
if (StrPos(Text, ':\') <> nil) or (StrPos(Text, '\\') <> nil) then
|
|
Config.dwFlags := Config.dwFlags or TDF_SIZE_TO_CONTENT;
|
|
if RightToLeft then
|
|
Config.dwFlags := Config.dwFlags or TDF_RTL_LAYOUT;
|
|
Config.hInstance := HInstance;
|
|
Config.hwndParent := hWnd;
|
|
Config.dwCommonButtons := CommonButtons;
|
|
Config.pszWindowTitle := Caption;
|
|
Config.pszMainIcon := Icon;
|
|
Config.pszMainInstruction := Instruction;
|
|
Config.pszContent := Text;
|
|
if VerificationText <> '' then
|
|
Config.pszVerificationText := VerificationText;
|
|
if ShieldButton <> 0 then begin
|
|
Config.pfCallback := ShieldButtonCallback;
|
|
Config.lpCallbackData := ShieldButton;
|
|
end;
|
|
ButtonItems := nil;
|
|
try
|
|
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;
|
|
end;
|
|
TriggerMessageBoxCallbackFunc(TriggerMessageBoxCallbackFuncFlags, False);
|
|
ActiveWindow := GetActiveWindow;
|
|
WindowList := DisableTaskWindows(Config.hwndParent);
|
|
try
|
|
Result := TaskDialogIndirectFunc(Config, @ModalResult, nil, pfVerificationFlagChecked) = S_OK;
|
|
finally
|
|
EnableTaskWindows(WindowList);
|
|
SetActiveWindow(ActiveWindow);
|
|
TriggerMessageBoxCallbackFunc(TriggerMessageBoxCallbackFuncFlags, True);
|
|
end;
|
|
finally
|
|
ButtonItems.Free;
|
|
end;
|
|
end else
|
|
Result := False;
|
|
end;
|
|
|
|
procedure DoInternalError(const Msg: String);
|
|
begin
|
|
{$IFDEF SETUPPROJ}
|
|
InternalError(Msg);
|
|
{$ELSE}
|
|
raise Exception.Create(Msg);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
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;
|
|
var
|
|
IconP: PChar;
|
|
TDCommonButtons: Cardinal;
|
|
NButtonLabelsAvailable: Integer;
|
|
ButtonIDs: array of Integer;
|
|
begin
|
|
Application.Restore; { See comments in AppMessageBox }
|
|
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;
|
|
end;
|
|
NButtonLabelsAvailable := Length(ButtonLabels);
|
|
case Buttons of
|
|
MB_OK, MB_OKCANCEL:
|
|
begin
|
|
if NButtonLabelsAvailable = 0 then
|
|
TDCommonButtons := TDCBF_OK_BUTTON
|
|
else begin
|
|
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;
|
|
ButtonIDs := [IDYES, IDNO];
|
|
end;
|
|
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;
|
|
end;
|
|
MB_ABORTRETRYIGNORE:
|
|
begin
|
|
if NButtonLabelsAvailable = 0 then
|
|
DoInternalError('TaskDialogMsgBox: Invalid ButtonLabels')
|
|
else
|
|
ButtonIDs := [IDRETRY, IDIGNORE, IDABORT]; { Notice the order, abort label must be last }
|
|
TDCommonButtons := 0;
|
|
end;
|
|
else
|
|
begin
|
|
DoInternalError('TaskDialogMsgBox: Invalid Buttons');
|
|
TDCommonButtons := 0; { Silence compiler }
|
|
end;
|
|
end;
|
|
if Length(ButtonIDs) <> NButtonLabelsAvailable then
|
|
DoInternalError('TaskDialogMsgBox: Invalid ButtonLabels');
|
|
if not DoTaskDialog(GetOwnerWndForMessageBox, PChar(Instruction), PChar(Text),
|
|
GetMessageBoxCaption(PChar(Caption), Typ), IconP, TDCommonButtons, ButtonLabels, ButtonIDs, ShieldButton,
|
|
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)
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure InitCommonControls; external comctl32 name 'InitCommonControls';
|
|
|
|
initialization
|
|
InitCommonControls;
|
|
TaskDialogIndirectFunc := GetProcAddress(GetModuleHandle(comctl32), 'TaskDialogIndirect');
|
|
|
|
end.
|