2015-12-17 15 views
7

Próbuję użyć TSaveDialog w Delphi XE6:TSaveDialog nie z klientem wizualnych stylów wyłączone

if not SaveDialog1.Execute(0) then 
    Exit; 

Wezwanie natychmiast powraca fałszywy, bez wyświetlania okna dialogowego. I prześledzić go do aktu tworzenia powłoki obiektu Zapisz Dialog COM:

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

    CoCreateInstance(LGuid, nil, CLSCTX_INPROC_SERVER, 
    StringToGUID(SID_IFileSaveDialog), Result); 
end; 

Wezwanie do CoCreateInstance zawodzi. Stworzyłem minimalny kod do odtworzenia problemu:

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

To rzuca EOleSysError wyjątek:

0x80040111: ClassFactory nie może dostarczyć żądanej klasy, CLASSID: {C0B4E2F3-BA21-4773-8DBA-335EC946EB8B }

Moja aplikacja jest używając wersji 6 wspólnej biblioteki kontrolnej (6.0.7601.18837), ale uświadomiłem sobie, że tylko Happe ns, jeśli użytkownik wyłączył style wizualne dla mojej aplikacji:

enter image description here

Ciągle używając wersji 6 wspólnej biblioteki Controls, tylko że IsAppThemed zwraca false.

Uwaga: Znam wiele osób błędnie uważa, że:

  • Style wizualne API działa tylko wtedy, gdy mamy Wersja 6 Comctrl32.dll załadowany
  • Jeśli wersja 6 Comctrl32. dll jest ładowany, a następnie Visual Styles API zadziała
  • Jeśli nie używamy ComCtrl v6, oznacza to, że Style wizualne są wyłączone
  • Style wizualne są wyłączone, jeśli używamy stary wspólna biblioteka kontrole

Rozwiązanie brute-force jest stworzenie globalnego UseLatestCommonDialogs false.

Ale to jest bardzo złe, ponieważ odnosi się tylko do ludzi, którzy mają niepełnosprawne stylów wizualnych we wniosku:

  • okno kontynuuje prace nad OS bez stylów wizualnych (np Windows Server 2008 R2)
  • okno kontynuuje współpracę z style wizualne wyłączony (np Windows 7 z style wizualne wyłączony)

oznacza to, że nie można po prostu użyć IsAppThemed, jak również zwraca wartość false, jeśli IsThemeActive jest fałszywe.

| IsThemeActive | IsAppThemed | Disable visual styles | Result | 
|---------------|-------------|-----------------------|-----------| 
| True   | True  | Unchecked    | Works  | 
| True   | False  | Checked    | Fails  | 
| False   | False  | Unchecked    | Works  | 
| False   | False  | Checked    | Fails  | 

Co Chyba jestem pytaniem jest, jak sprawdzić stan Disble style wizualne compat flagi.

Naprawdę pytam, jak sprawić, aby TSaveDialog działał poprawnie w Delphi (bez sugerowania, że ​​czytanie flagi compat jest częścią rozwiązania).

+0

Mam nadzieję, że to nie jest zbyt rozwlekłe zapytanie, ale dlaczego "SaveDialog1.Execute (0)", a nie bardziej "SaveDialog1.Execute"? – MartynA

+0

@MartynA Cóż, istnieją trzy powody, dla których i) '.Execute' nie pojawia się wglądu w kod ii) Wywołanie' .Execute' powoduje, że okno jest własnością 'ApplicationMainHandle' iii) W rzeczywistości chcę, aby okno dialogowe było własnością formularza, na który patrzę (np. 'SaveDialog1.Execute (Self.Handle)'). Ale nie chciałem, aby ludzie koncentrowali się na parametrze przekazanym do 'Execute', więc uprościłem go do' .Execute (0) '. W rzeczywistości własność okna Delphi jest zerwana i zignorowała właściciela - zamiast tego przynosi to, co chce. –

+0

biorąc pod uwagę tę zaakceptowaną odpowiedź: http://superuser.com/questions/694734/what-does-compatibility-option-disable-visual-themes-do sensownym jest sprawdzenie ['IsCompositionActive'] (https: // msdn.microsoft.com/en-us/library/windows/desktop/bb759811(v=vs.85).aspx) również? Tylko zgadywanie – fantaghirocco

Odpowiedz

5

Na pewno nie chcesz testować flagi zgodności. Jeśli zamierzasz przetestować, chcesz przetestować, co ta flaga kontroluje. W tym przypadku czy motywy są w użyciu. Jeśli masz zamiar przetestować jak to wtedy należy użyć stylu okien dialogowych Vista, gdy następujący warunek:

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

W przeciwnym razie trzeba używać starych okien dialogowych stylu XP. Można tego dokonać za pomocą następującego kodu:

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

Problem z tym jest jednak, że można wyłączyć nowe dialogi w stylu, gdy użytkownik pracuje z tematem Klasyczny Windows. Które jestem pewien, że nie chcesz.

Dzięki temu można zastosować podejście oparte na funkcjonalności. Jest to próba użycia okien dialogowych nowego stylu i powrotu do poprzedniego okna dialogowego, jeśli nowa się nie powiedzie. Tak więc spróbuj utworzyć IFileSaveDialog. Przypisz UseLatestCommonDialogs w zależności od tego, czy się to uda, czy też nie.


Z drugiej strony, to compat ustawienie jest przeznaczone do stosowania w aplikacjach, które nie działają poprawnie, gdy są włączone motywy. Twoja aplikacja działa poprawnie w ramach motywów i myślę, że uzasadnione jest twierdzenie, że twoja aplikacja nie obsługuje tego konkretnego trybu kompatybilnego.

Nie przewiduje się obsługiwania trybów zgodności. Na przykład, jeśli przestaniesz wspierać obsługę XP, nie będziesz oczekiwać obsługi podkładek XP compat.

Odbicie to moja rada dla ciebie. Po prostu nie rób nic. Jeśli użytkownicy pytają o awarię aplikacji w ten sposób, powiedz im, że nie obsługujesz tego trybu zgodności. Nie jest Twoim zadaniem tworzenie trybów zgodności aplikacji.

+0

Dziwność polega na tym, że zdarzają się sytuacje, w których 'IsWindowsVistaOrGreater i InitThemeLibrary i UseThemes' zwrócą fałsz, ale jest poprawne i właściwe korzystanie z nowych okien dialogowych. –

+1

Chciałabym, aby Embarcadero przestał wywoływać 'TOpenDialog' /' TSaveDialog' z kilkoma bezużytecznymi sprawdzeniami dla różnych funkcjonalności OS/framework przed podjęciem decyzji, czy użyć 'IFileDialog' czy nie. Każda wersja wydaje się dodawać więcej kontroli.Albo 'IFileDialog' jest dostępny, albo nie jest, niech OS decyduje. Jeśli "UseLatestCommonDialogs" jest prawdziwe, spróbuj załadować 'IFileDialog', a jeśli się nie powiedzie, powróć do starego okna dialogowego. Gotowe. Ale wydaje się, że nie chcą tego robić. –

+0

@Remy Początkowo udostępniłem ten punkt widokowy. Ale teraz zastanawiam się, dlaczego potrzebowalibyśmy obsługi trybu zgodności z przeznaczeniem dla wcześniejszych aplikacji XP. Teraz uważam, że uzasadnione jest dla nas, aby nie martwić się o takie tryby w naszych nowoczesnych aplikacjach. –

Powiązane problemy