win32: use TaskDialogIndirect for MessageDlg and ShowMessage on windows vista+

git-svn-id: trunk@28198 -
This commit is contained in:
paul 2010-11-13 07:42:13 +00:00
parent 13f15fb3ff
commit 8e99ab359b
6 changed files with 265 additions and 5 deletions

View File

@ -72,6 +72,146 @@ type
WINDOWINFO = tagWINDOWINFO;
PWINDOWINFO = ^tagWINDOWINFO;
// ===================== Task Dialog =========================
PFTASKDIALOGCALLBACK = function(hwnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM; lpRefData: LONG_PTR): HRESULT; stdcall;
// _TASKDIALOG_FLAGS enum
const
TDF_ENABLE_HYPERLINKS = $0001;
TDF_USE_HICON_MAIN = $0002;
TDF_USE_HICON_FOOTER = $0004;
TDF_ALLOW_DIALOG_CANCELLATION = $0008;
TDF_USE_COMMAND_LINKS = $0010;
TDF_USE_COMMAND_LINKS_NO_ICON = $0020;
TDF_EXPAND_FOOTER_AREA = $0040;
TDF_EXPANDED_BY_DEFAULT = $0080;
TDF_VERIFICATION_FLAG_CHECKED = $0100;
TDF_SHOW_PROGRESS_BAR = $0200;
TDF_SHOW_MARQUEE_PROGRESS_BAR = $0400;
TDF_CALLBACK_TIMER = $0800;
TDF_POSITION_RELATIVE_TO_WINDOW = $1000;
TDF_RTL_LAYOUT = $2000;
TDF_NO_DEFAULT_RADIO_BUTTON = $4000;
TDF_CAN_BE_MINIMIZED = $8000;
type
TASKDIALOG_FLAGS = Integer; // Note: _TASKDIALOG_FLAGS is an int
// _TASKDIALOG_MESSAGES enum
const
TDM_NAVIGATE_PAGE = WM_USER+101;
TDM_CLICK_BUTTON = WM_USER+102; // wParam = Button ID
TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER+103; // wParam = 0 (nonMarque) wParam != 0 (Marquee)
TDM_SET_PROGRESS_BAR_STATE = WM_USER+104; // wParam = new progress state
TDM_SET_PROGRESS_BAR_RANGE = WM_USER+105; // lParam = MAKELPARAM(nMinRange, nMaxRange)
TDM_SET_PROGRESS_BAR_POS = WM_USER+106; // wParam = new position
TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER+107; // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints)
TDM_SET_ELEMENT_TEXT = WM_USER+108; // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
TDM_CLICK_RADIO_BUTTON = WM_USER+110; // wParam = Radio Button ID
TDM_ENABLE_BUTTON = WM_USER+111; // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID
TDM_ENABLE_RADIO_BUTTON = WM_USER+112; // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID
TDM_CLICK_VERIFICATION = WM_USER+113; // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus)
TDM_UPDATE_ELEMENT_TEXT = WM_USER+114; // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER+115; // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required)
TDM_UPDATE_ICON = WM_USER+116; // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise)
// _TASKDIALOG_NOTIFICATIONS enum
const
TDN_CREATED = 0;
TDN_NAVIGATED = 1;
TDN_BUTTON_CLICKED = 2; // wParam = Button ID
TDN_HYPERLINK_CLICKED = 3; // lParam = (LPCWSTR)pszHREF
TDN_TIMER = 4; // wParam = Milliseconds since dialog created or timer reset
TDN_DESTROYED = 5;
TDN_RADIO_BUTTON_CLICKED = 6; // wParam = Radio Button ID
TDN_DIALOG_CONSTRUCTED = 7;
TDN_VERIFICATION_CLICKED = 8; // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0
TDN_HELP = 9;
TDN_EXPANDO_BUTTON_CLICKED = 10; // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded)
type
_TASKDIALOG_BUTTON = packed record
nButtonID: Integer;
pszButtonText: PCWSTR;
end;
TASKDIALOG_BUTTON = _TASKDIALOG_BUTTON;
TTASKDIALOG_BUTTON = TASKDIALOG_BUTTON;
PTASKDIALOG_BUTTON = ^TASKDIALOG_BUTTON;
// _TASKDIALOG_ELEMENTS enum
const
TDE_CONTENT = 0;
TDE_EXPANDED_INFORMATION = 1;
TDE_FOOTER = 2;
TDE_MAIN_INSTRUCTION = 3;
// _TASKDIALOG_ICON_ELEMENTS enum
TDIE_ICON_MAIN = 0;
TDIE_ICON_FOOTER = 1;
TD_WARNING_ICON = MAKEINTRESOURCEW(Word(-1));
TD_ERROR_ICON = MAKEINTRESOURCEW(Word(-2));
TD_INFORMATION_ICON = MAKEINTRESOURCEW(Word(-3));
TD_SHIELD_ICON = MAKEINTRESOURCEW(Word(-4));
TD_SHIELD_GRADIENT_ICON = MAKEINTRESOURCEW(Word(-5));
TD_SHIELD_WARNING_ICON = MAKEINTRESOURCEW(Word(-6));
TD_SHIELD_ERROR_ICON = MAKEINTRESOURCEW(Word(-7));
TD_SHIELD_OK_ICON = MAKEINTRESOURCEW(Word(-8));
TD_SHIELD_GRAY_ICON = MAKEINTRESOURCEW(Word(-9));
// _TASKDIALOG_COMMON_BUTTON_FLAGS enum
TDCBF_OK_BUTTON = $0001; // selected control return value IDOK
TDCBF_YES_BUTTON = $0002; // selected control return value IDYES
TDCBF_NO_BUTTON = $0004; // selected control return value IDNO
TDCBF_CANCEL_BUTTON = $0008; // selected control return value IDCANCEL
TDCBF_RETRY_BUTTON = $0010; // selected control return value IDRETRY
TDCBF_CLOSE_BUTTON = $0020; // selected control return value IDCLOSE
type
TASKDIALOG_COMMON_BUTTON_FLAGS = Integer; // Note: _TASKDIALOG_COMMON_BUTTON_FLAGS is an int
_TASKDIALOGCONFIG = packed record
cbSize: UINT;
hwndParent: HWND;
hInstance: HINST; // used for MAKEINTRESOURCE() strings
dwFlags: TASKDIALOG_FLAGS; // TASKDIALOG_FLAGS (TDF_XXX) flags
dwCommonButtons: TASKDIALOG_COMMON_BUTTON_FLAGS; // TASKDIALOG_COMMON_BUTTON (TDCBF_XXX) flags
pszWindowTitle: PCWSTR; // string or MAKEINTRESOURCE()
case PtrInt of
0: (hMainIcon: HICON);
1: (
pszMainIcon: PCWSTR;
pszMainInstruction: PCWSTR;
pszContent: PCWSTR;
cButtons: UINT;
pButtons: PTASKDIALOG_BUTTON;
nDefaultButton: Integer;
cRadioButtons: UINT;
pRadioButtons: PTASKDIALOG_BUTTON;
nDefaultRadioButton: Integer;
pszVerificationText: PCWSTR;
pszExpandedInformation: PCWSTR;
pszExpandedControlText: PCWSTR;
pszCollapsedControlText: PCWSTR;
case PtrInt of
0: (hFooterIcon: HICON);
1: (
pszFooterIcon: PCWSTR;
pszFooter: PCWSTR;
pfCallback: PFTASKDIALOGCALLBACK;
lpCallbackData: LONG_PTR;
cxWidth: UINT; // width of the Task Dialog's client area in DLU's. If 0, Task Dialog will calculate the ideal width.
);
);
end;
TASKDIALOGCONFIG = _TASKDIALOGCONFIG;
PTASKDIALOGCONFIG = ^TASKDIALOGCONFIG;
TTASKDIALOGCONFIG = TASKDIALOGCONFIG;
// ==================== End TaskDialog =======================
// AlphaBlend is only defined for win98&2k and up
// load dynamic and use ownfunction if not defined
var
@ -85,6 +225,9 @@ var
UpdateLayeredWindow: function(hWnd: HWND; hdcDst: HDC; pptDst: PPoint; psize: PSize;
hdcSrc: HDC; pptSrc: PPoint; crKey: COLORREF; pblend: PBlendFunction; dwFlags: DWORD): BOOL; stdcall;
IsProcessDPIAware: function: BOOL; stdcall;
TaskDialogIndirect: function(const pTaskConfig: PTASKDIALOGCONFIG; pnButton: PInteger; pnRadioButton: PInteger; pfVerificationFlagChecked: PBOOL): HRESULT; stdcall;
TaskDialog: function(hwndParent: HWND; hInstance: HINST; pszWindowTitle: PCWSTR; pszMainInstruction: PCWSTR; pszContent: PCWSTR;
dwCommonButtons: TASKDIALOG_COMMON_BUTTON_FLAGS; pszIcon: PCWSTR; pnButton: PInteger): HRESULT; stdcall;
const
// ComCtlVersions
@ -567,17 +710,30 @@ begin
Result := False;
end;
function _TaskDialogIndirect(const pTaskConfig: PTASKDIALOGCONFIG; pnButton: PInteger; pnRadioButton: PInteger; pfVerificationFlagChecked: PBOOL): HRESULT; stdcall;
begin
Result := E_NOTIMPL;
end;
function _TaskDialog(hwndParent: HWND; hInstance: HINST; pszWindowTitle: PCWSTR; pszMainInstruction: PCWSTR; pszContent: PCWSTR;
dwCommonButtons: TASKDIALOG_COMMON_BUTTON_FLAGS; pszIcon: PCWSTR; pnButton: PInteger): HRESULT; stdcall;
begin
Result := E_NOTIMPL;
end;
const
msimg32lib = 'msimg32.dll';
user32lib = 'user32.dll';
shell32lib = 'shell32.dll';
gdi32lib = 'gdi32.dll';
comctl32lib = 'comctl32.dll';
var
msimg32handle: THandle = 0;
user32handle: THandle = 0;
shell32handle: THandle = 0;
gdi32handle: THandle = 0;
comctl32handle: THandle = 0;
procedure Initialize;
var
@ -671,6 +827,21 @@ begin
then Pointer(SetLayout) := p;
end;
// Defaults
Pointer(TaskDialogIndirect) := @_TaskDialogIndirect;
Pointer(TaskDialog) := @_TaskDialog;
comctl32handle := LoadLibrary(comctl32lib);
if comctl32handle <> 0 then
begin
p := GetProcAddress(comctl32handle, 'TaskDialogIndirect');
if p <> nil
then Pointer(TaskDialogIndirect) := p;
p := GetProcAddress(comctl32handle, 'TaskDialog');
if p <> nil
then Pointer(TaskDialog) := p;
end;
end;
procedure Finalize;
@ -694,6 +865,10 @@ begin
if gdi32handle <> 0 then
FreeLibrary(gdi32handle);
gdi32handle := 0;
if comctl32handle <> 0 then
FreeLibrary(comctl32handle);
comctl32handle := 0;
end;
initialization

View File

@ -35,7 +35,7 @@ interface
}
uses
Windows, ActiveX, Classes, Translations, ComCtrls, Controls, Buttons,
ExtCtrls, Forms, GraphMath, GraphType, InterfaceBase, LCLIntf,
ExtCtrls, Forms, Dialogs, GraphMath, GraphType, InterfaceBase, LCLIntf,
LCLType, LMessages, StdCtrls, SysUtils, Win32Def, Graphics, Menus, CommCtrl,
MultiMon, Themes{, Win32Debug};
@ -249,6 +249,7 @@ uses
Win32WSMenus,
Win32WSSpin,
Win32WSStdCtrls,
Win32WSDialogs,
Win32Themes,
////////////////////////////////////////////////////
Win32Extra, LclProc, LCLMessageGlue;

View File

@ -590,6 +590,86 @@ begin
Result := False;
end;
function TWin32WidgetSet.PromptUser(const DialogCaption, DialogMessage: String;
DialogType: longint; Buttons: PLongint; ButtonCount, DefaultIndex,
EscapeResult: Longint): Longint;
var
i: Integer;
Caption: String;
TaskConfig: TTASKDIALOGCONFIG;
DialogButtons: PTASKDIALOG_BUTTON;
State: TApplicationState;
begin
if (WindowsVersion >= wvVista) and ThemeServices.ThemesEnabled then
begin
FillChar(TaskConfig, SizeOf(TaskConfig), 0);
TaskConfig.cbSize := SizeOf(TaskConfig);
// if we skip hwndParent our form will be a root window - with the taskbar item and icon
// this is unwanted
if Assigned(Screen.ActiveCustomForm) then
TaskConfig.hwndParent := Screen.ActiveCustomForm.Handle
else
if Assigned(Application.MainForm) then
TaskConfig.hwndParent := Application.MainForm.Handle
else
TaskConfig.hwndParent := AppHandle;
TaskConfig.hInstance := HInstance;
TaskConfig.dwFlags := TDF_ALLOW_DIALOG_CANCELLATION;
if DialogCaption <> '' then
Caption := DialogCaption
else
case DialogType of
idDialogConfirm,
idDialogInfo,
idDialogWarning,
idDialogError: Caption := GetDialogCaption(DialogType);
else
Caption := Application.Title;
end;
TaskConfig.pszWindowTitle := PWideChar(UTF8ToUTF16(Caption));
case DialogType of
idDialogConfirm:
begin
TaskConfig.hMainIcon := LoadIcon(0, IDI_QUESTION);
TaskConfig.dwFlags := TaskConfig.dwFlags or TDF_USE_HICON_MAIN;
end;
idDialogInfo: TaskConfig.pszMainIcon := TD_INFORMATION_ICON;
idDialogWarning: TaskConfig.pszMainIcon := TD_WARNING_ICON;
idDialogError: TaskConfig.pszMainIcon := TD_ERROR_ICON;
idDialogShield: TaskConfig.pszMainIcon := TD_SHIELD_ICON;
else
TaskConfig.dwFlags := TaskConfig.dwFlags or TDF_USE_HICON_MAIN;
end;
TaskConfig.pszMainInstruction := PWideChar(UTF8ToUTF16(DialogMessage));
TaskConfig.cButtons := ButtonCount;
GetMem(DialogButtons, SizeOf(TTASKDIALOG_BUTTON) * ButtonCount);
for i := 0 to ButtonCount - 1 do
begin
DialogButtons[i].nButtonID := Buttons[i];
DialogButtons[i].pszButtonText := UTF8StringToPWideChar(GetButtonCaption(Buttons[i]));
end;
TaskConfig.pButtons := DialogButtons;
TaskConfig.nDefaultButton := DefaultIndex;
State := SaveApplicationState;
try
if TaskDialogIndirect(@TaskConfig, @Result, nil, nil) <> S_OK then
Result := EscapeResult;
finally
RestoreApplicationState(State);
for i := 0 to ButtonCount - 1 do
FreeMem(DialogButtons[i].pszButtonText);
FreeMem(DialogButtons);
end;
end
else
Result := inherited PromptUser(DialogCaption, DialogMessage, DialogType,
Buttons, ButtonCount, DefaultIndex, EscapeResult);
end;
{------------------------------------------------------------------------------
Function: RawImage_CreateBitmaps
Params: ARawImage:

View File

@ -57,6 +57,8 @@ function GetDesignerDC(WindowHandle: HWND): HDC; override;
function IntfSendsUTF8KeyPress: boolean; override;
function IsDesignerDC(WindowHandle: HWND; DC: HDC): Boolean; override;
function PromptUser(const DialogCaption, DialogMessage : String; DialogType : longint; Buttons : PLongint; ButtonCount, DefaultIndex, EscapeResult : Longint) : Longint; override;
function RawImage_CreateBitmaps(const ARawImage: TRawImage; out ABitmap, AMask: HBitmap; ASkipMask: Boolean = False): Boolean; override;
function RawImage_DescriptionFromBitmap(ABitmap: HBITMAP; out ADesc: TRawImageDescription): Boolean; override;
function RawImage_DescriptionFromDevice(ADC: HDC; out ADesc: TRawImageDescription): Boolean; override;

View File

@ -254,13 +254,13 @@ begin
if UnicodeEnabledOS then
PreferredSizeStatusBar := CreateWindowExW(0, STATUSCLASSNAMEW,
nil, Flags,
0, 0, 0, 0, Parent, 0, HInstance, Nil)
0, 0, 0, 0, Parent, 0, HInstance, nil)
else
PreferredSizeStatusBar := CreateWindowEx(0, STATUSCLASSNAME, nil,
Flags, 0, 0, 0, 0, Parent,0 , HInstance, Nil);
Flags, 0, 0, 0, 0, Parent,0 , HInstance, nil);
{$else}
PreferredSizeStatusBar := CreateWindowEx(0, STATUSCLASSNAME, nil,
Flags, 0, 0, 0, 0, Parent, 0, HInstance, Nil);
Flags, 0, 0, 0, 0, Parent, 0, HInstance, nil);
{$endif}
GetWindowRect(PreferredSizeStatusBar, R);
PreferredStatusBarHeight := R.Bottom - R.Top;
@ -464,7 +464,7 @@ end;
class procedure TWin32WSStatusBar.GetPreferredSize(const AWinControl: TWinControl;
var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean);
begin
if (PreferredStatusBarHeight=0) then
if (PreferredStatusBarHeight = 0) then
InitializePreferredStatusBarHeight;
PreferredHeight := PreferredStatusBarHeight;

View File

@ -122,6 +122,8 @@ function OpenFileDialogCallBack(Wnd: HWND; uMsg: UINT; wParam: WPARAM;
function SaveApplicationState: TApplicationState;
procedure RestoreApplicationState(AState: TApplicationState);
function UTF8StringToPWideChar(const s: string) : PWideChar;
function UTF8StringToPAnsiChar(const s: string) : PAnsiChar;
implementation