7

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

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}

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

在此处输入图像描述

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

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

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

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

但这很糟糕,因为它只适用于在他们的应用程序中禁用了视觉样式的人:

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

这意味着我不能简单地使用IsAppThemed,因为如果IsThemeActive为假,它也会返回假。

| 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兼容标志的状态。

我真正要问的是如何TSaveDialog在 Delphi 中正确地工作(并不暗示读取 compat 标志是解决方案的一部分)。

4

1 回答 1

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根据是否成功分配。


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

您不应该支持兼容模式。例如,如果您停止支持 XP,那么您将不会支持 XP 兼容 shim。

经过反思,这是我对你的建议。干脆什么都不做。如果您的用户询问您的应用程序以这种方式失败,请告诉他们您不支持该兼容模式。让您的应用程序支持兼容模式不是您的工作。

于 2015-12-17T21:13:48.130 回答