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

时间:2015-12-17 20:17:05

标签: delphi themes delphi-xe6 visual-styles

我正在尝试在Delphi XE6中使用TSaveDialog

if not SaveDialog1.Execute(0) then
   Exit;

通话会立即返回 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;

CoCreateInstance的调用失败。我创建了最少的代码来重现这个问题:

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

抛出 EOleSysError 异常:

  

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

我的应用程序 使用通用控件库的第6版(6.0.7601.18837),但我意识到只有在用户为我的应用程序禁用了视觉样式时才会发生这种情况:

enter image description here

我们仍在使用公共控件库的第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     |

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

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

1 个答案:

答案 0 :(得分:5)

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

IsWindowsVistaOrGreater and Winapi.UxTheme.InitThemeLibrary and Winapi.UxTheme.UseThemes

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

UseLatestCommonDialogs := IsWindowsVistaOrGreater and Winapi.UxTheme.InitThemeLibrary 
  and Winapi.UxTheme.UseThemes;

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

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

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

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

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