TSaveDialog失败,客户端视觉样式被禁用

Ian*_*oyd 7 delphi themes visual-styles delphi-xe6

我想TSaveDialog在Delphi XE6中使用a :

if not SaveDialog1.Execute(0) then
   Exit;
Run Code Online (Sandbox Code Playgroud)

该调用立即返回false,而不显示任何对话框.我将其追溯到创建shell Save Dialog COM对象的行为:

function TCustomFileSaveDialog.CreateFileDialog: IFileDialog;
var
       LGuid: TGUID;
begin
  LGuid := CLSID_FileSaveDialog;

  CoCreateInstance(LGuid, nil, CLSCTX_INPROC_SERVER,
    StringToGUID(SID_IFileSaveDialog), Result);
end;
Run Code Online (Sandbox Code Playgroud)

呼叫CoCreateInstance失败了.我创建了最少的代码来重现问题:

procedure TForm1.Button1Click(Sender: TObject);
const
   CLSID_FileSaveDialog: TGUID = '{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}';
begin
   CreateComObject(CLSID_FileSaveDialog);
end;
Run Code Online (Sandbox Code Playgroud)

它抛出EOleSysError异常:

0x80040111:ClassFactory无法提供请求的类,ClassID:{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}

我的应用程序使用公共控件库(6.0.7601.18837)的第6版,但我意识到,如果用户已禁用我的应用程序的视觉样式时才会发生:

在此输入图像描述

我们仍在使用公共控件库的第6版,只IsAppThemed返回false.

注意:我知道很多人错误地认为:

  • Visual Styles API仅在我们加载了Comctrl32.dll版本6时才有效
  • 如果加载了Comctrl32.dll的版本6,则Visual Styles API将起作用
  • 如果我们不使用ComCtrl v6那么这意味着视觉样式被禁用
  • 如果我们使用旧的公共控件库,则禁用视觉样式

蛮力解决方案是将全局UseLatestCommonDialogs设置为false.

但这非常糟糕,因为它仅适用于在应用程序中禁用视觉样式的人:

  • 对话框继续在没有视觉样式的操作系统上工作(例如Windows Server 2008 R2)
  • 关闭视觉样式后对话框继续工作(例如关闭视觉样式的Windows 7)

这意味着我不能简单地使用IsAppThemed,因为如果IsThemeActive为false 则返回false.

| IsThemeActive | IsAppThemed | Disable visual styles | Result    |
|---------------|-------------|-----------------------|-----------|
| True          | True        | Unchecked             | Works     |
| True          | False       | Checked               | Fails     |
| False         | False       | Unchecked             | Works     |
| False         | False       | Checked               | Fails     |
Run Code Online (Sandbox Code Playgroud)

我想我要问的是如何检查Disble Visual Styles compat标志的状态.

我真正想问的是如何TSaveDialog在Delphi中正确地工作(并不意味着读取compat标志是解决方案的一部分).

Dav*_*nan 5

你肯定不想测试compat标志.如果要进行测试,则需要测试该标志控制的内容.在这种情况下,是否使用主题.如果您要进行类似测试,则在满足以下条件时应使用Vista样式对话框:

IsWindowsVistaOrGreater and Winapi.UxTheme.InitThemeLibrary and Winapi.UxTheme.UseThemes
Run Code Online (Sandbox Code Playgroud)

否则,您需要使用旧的XP样式对话框.您可以使用以下代码实现此目的:

UseLatestCommonDialogs := IsWindowsVistaOrGreater and Winapi.UxTheme.InitThemeLibrary 
  and Winapi.UxTheme.UseThemes;
Run Code Online (Sandbox Code Playgroud)

但问题是,当用户使用Windows经典主题运行时,您将禁用新样式对话框.我确信你不想要.

所以你可以采用基于功能的方法.如果新的失败,那就是尝试在旧样式对话框中使用新样式对话框和回退.所以,尝试创建一个IFileSaveDialog.UseLatestCommonDialogs根据是否成功进行分配.


另一方面,此compat设置旨在用于启用主题时无法正常工作的应用程序.您的应用程序在主题下可以正常工作,我认为您的应用程序不支持该特定的compat模式是完全合理的.

您不应该支持兼容模式.例如,如果你停止支持XP,那么你不会期望支持XP compat垫片.

经过反思,这是我对你的建议.什么都不做.如果您的用户以这种方式询问您的应用是否失败,请告诉他们您不支持该compat模式.使您的应用程序支持兼容模式不是您的职责.