2015-12-17 4 views
7

Я пытаюсь использовать в Delphi XE6 в TSaveDialog:TSaveDialog терпит неудачу с клиентами визуальных стилей отключенными

if not SaveDialog1.Execute(0) then 
    Exit; 

вызов немедленно возвращает ложные, без отображения диалогового окна. Я проследил его до акта создания оболочки Диалог сохранения 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 общей библиотеки Controls (6.0.7601.18837), но я понял, что это только Happe нс, если пользователь отключил визуальные стили для моего приложения:

enter image description here

Мы до сих пор используют версию 6 из общей библиотеки элементов управления, так что IsAppThemed возвращает ложь.

Примечание: Я знаю, что многие люди ошибочно полагают, что:

  • Visual Styles API работает только если у нас есть версия 6 из Comctrl32.dll загруженную
  • Если версия 6 из Comctrl32. dll будет загружен, тогда API визуальных стилей будет работать
  • Если мы не используем ComCtrl v6, значит, визуальные стили отключены
  • Визуальные стили отключены, если мы используем старый общий контроль библиотека

Решение перебором является создание глобальной UseLatestCommonDialogs к ложным.

Но это очень плохо, так как это относится только к людям, которые имеют инвалидов визуальные стили в их применении:

  • диалог продолжает работать на ОС без визуальных стилей (например, 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 Compat флаг.

Что я действительно спрашиваю, как правильно сделать работу TSaveDialog в Delphi (не подразумевая, что чтение флага совместимости является частью решения).

+0

Надеюсь, это не слишком тупой запрос, но почему «SaveDialog1.Execute (0)», а не более обычный «SaveDialog1.Execute»? – MartynA

+0

@MartynA Ну, есть три причины для этого: i) '.Execute' не отображается в представлении кода ii) Вызов' .Execute' заставляет окно принадлежать 'ApplicationMainHandle' iii) На самом деле я хочу, чтобы диалог был (например, 'SaveDialog1.Execute (Self.Handle)'). Но я не хотел, чтобы люди фокусировались на параметре, переданном 'Execute', поэтому я упростил его для' .Execute (0) '. На самом деле, владельцы окон Delphi сломаны, и он игнорировал владельца - вместо этого он делал все, что захочет. –

+0

с учетом этого принятого ответа: http://superuser.com/questions/694734/what-does-compatibility-option-disable-visual-themes-do разумно проверить ['IsCompositionActive'] (https: // msdn.microsoft.com/en-us/library/windows/desktop/bb759811(v=vs.85).aspx) также? Просто гадать – fantaghirocco

ответ

5

Вы, конечно же, не хотите проверять флаг совместимости. Если вы собираетесь тестировать, вы хотите проверить, что этот флаг контролирует. В этом случае используются темы или нет. Если вы собираетесь испытать подобное, то вы должны использовать диалоговые окна в стиле Vista, когда выполняется следующее условие:

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

В противном случае вы должны использовать старые XP диалоговые окна стиля. Вы можете сделать это произойдет со следующим кодом:

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

Проблема с этим, хотя в том, что вы будете отключать новые диалоги в стиле, когда пользователь работает с темой Windows Classic. Который я уверен, что вы не хотите.

Таким образом, вы можете использовать подход, основанный на функциональности. Это попытка использовать диалоговые окна нового стиля и откат в диалоговом окне старого стиля, если новый сбой. Итак, попытайтесь создать IFileSaveDialog. Назначьте UseLatestCommonDialogs на основе того, удастся ли это выполнить.


С другой стороны, эта настройка сопоставления предназначена для использования в приложениях, которые работают неправильно, когда темы включены. Ваше приложение работает правильно по темам, и я думаю, что для вас вполне оправданно утверждать, что ваше приложение не поддерживает этот режим совместимости.

Ожидается, что вы не будете поддерживать режимы совместимости. Например, если вы перестанете поддерживать XP, тогда вам не следует поддерживать поддерживающие XP совместимые прокладки.

Об отражении, это мой совет вам. Просто ничего не делайте. Если ваши пользователи спрашивают о том, что ваше приложение не работает таким образом, сообщите им, что вы не поддерживаете этот режим сопоставления. Это не ваша работа, чтобы ваше приложение поддерживало режимы совместимости.

+0

Странность в том, что бывают случаи, когда 'IsWindowsVistaOrGreater и InitThemeLibrary и UseThemes' вернут false, но правильно и правильно использовать новые диалоги. –

+1

Я хочу, чтобы Embarcadero прекратил загромождать 'TOpenDialog' /' TSaveDialog' полдюжины бесполезных проверок для различных функциональных возможностей OS/framework, прежде чем решать, использовать ли 'IFileDialog' или нет. Кажется, что в каждом выпуске больше проверок.Либо «IFileDialog» доступен, либо нет, пусть ОС решит. Если 'UseLatestCommonDialogs' истинно, тогда попытайтесь загрузить' IFileDialog', и если он не сработает, вернитесь к старому диалоговому окну. Готово. Но они, похоже, не хотят этого делать. –

+0

@Remy Я изначально поделился этой точкой зрения. Но теперь мне интересно, почему нам нужно поддерживать режим совместимости, предназначенный для приложений до XP. Теперь я считаю, что нам не нужно беспокоиться о таких режимах в наших современных приложениях. –