2015-12-17 4 views
7

ich TSaveDialog in Delphi XE6 zu verwenden, versuchen:TSaveDialog nicht mit Client-visuellen Stilen deaktiviert

if not SaveDialog1.Execute(0) then 
    Exit; 

Der Aufruf sofort zurück falsch ohne Dialog angezeigt wird. Ich verfolgen es auf den Akt nach unten von dem Shell Speichern Dialog COM-Objekt erstellen:

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

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

Der Aufruf von CoCreateInstance versagt. Ich habe minimalen Code das Problem zu reproduzieren:

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

Es führt die EOleSysError Ausnahme:

0x80040111: Classfactory kann nicht angeforderte Klasse liefern, ClassID: {C0B4E2F3-BA21-4773-8DBA-335EC946EB8B }

Meine Anwendung Version 6 der Common Controls-Bibliothek ist (6.0.7601.18837), aber ich erkannte, dass es nur Happe ns, wenn der Benutzer visuelle Stile für meine Anwendung deaktiviert:

enter image description here

Wir sind immer noch Version mit 6 der gemeinsamen Kontrollen Bibliothek, nur dass IsAppThemed false zurück.

Hinweis: Ich weiß, dass viele Menschen fälschlicherweise glauben:

  • Visual Styles API funktioniert nur, wenn wir die Version 6 von Comctrl32.dll haben
  • Wenn Version 6 von Comctrl32 geladen. dLL geladen wird, dann Visual Styles API
  • funktionieren wenn wir nicht ComCtrl v6 verwenden, dann bedeutet das Visual Styles sind deaktiviert
  • Visual Styles deaktiviert sind, wenn wir mit sind die alte gemeinsame Kontrollen Bibliothek

Die Brute-Force-Lösung ist die globale UseLatestCommonDialogs auf false gesetzt.

Aber das ist ziemlich schlecht, da es nur für Menschen gilt, die behindert visuelle Stile in ihrer Anwendung hat:

  • der Dialog auf O ohne visuelle Stile weiter zu arbeiten (zB Windows Server 2008 R2)
  • (zB Windows 7 mit visuellen Stilen ausgeschaltet) ausgeschaltet, um der Dialog weiterhin mit visuellen Stilen arbeiten

das bedeutet, ich kann einfach nicht IsAppThemed verwenden, da dies auch falsch zurück, wenn IsThemeActive falsch ist.

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

Was ich denke, ich bin gefragt ist, wie der Status der Disble Visual Styles compat Flagge zu überprüfen.

Was ich wirklich frage ist, wie man die TSaveDialog korrekt in Delphi arbeiten lässt (ohne zu unterstellen, dass das Lesen des compat-Flags Teil der Lösung ist).

+0

Ich hoffe, das ist nicht zu stumpf eine Abfrage, aber warum "SaveDialog1.Execute (0)" und nicht die üblichere "SaveDialog1.Execute"? – MartynA

+0

@MartynA Nun, es gibt drei Gründe dafür i) '.Execute' erscheint nicht im Code-Einblick ii) Aufruf' 'Execute' bewirkt, dass das Fenster 'ApplicationMainHandle' gehört. Iii) In Wirklichkeit möchte ich den Dialog haben gehört zu dem Formular, das ich gerade betrachte (zB 'SaveDialog1.Execute (Self.Handle)'). Aber ich wollte nicht, dass Leute sich auf den Parameter konzentrieren, der an 'Execute' übergeben wird, also habe ich ihn zu' .Execute (0) 'vereinfacht. In Wirklichkeit ist Delphis Fensterbesitz gebrochen und ignoriert den Besitzer - stattdessen bringt er alles mit, was er will. –

+0

unter Berücksichtigung dieser akzeptierten Antwort: http://superuser.com/questions/694734/what-does-compatibility-option-disable-visual-themes-do ist es sinnvoll zu überprüfen ['IsCompositionActive'] (https: // msdn.microsoft.com/en-us/library/windows/desktop/bb759811(v=vs.85).aspx) auch? Nur eine Vermutung – fantaghirocco

Antwort

5

Sie wollen sicher nicht für die compat Flagge testen. Wenn Sie testen möchten, möchten Sie testen, was dieses Flag steuert. In diesem Fall, ob Themen verwendet werden oder nicht. Wenn Sie vorhaben, zu testen, wie das dann sollten Sie den Stil Dialoge Vista verwenden, wenn die folgende Bedingung erfüllt ist:

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

Andernfalls müssen Sie die alten XP-Stil Dialoge verwenden. Sie können dies mit dem folgenden Code geschehen:

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

Das Problem mit dieser ist aber, dass Sie neuen Stil Dialoge deaktivieren, wenn der Benutzer mit dem Thema Windows klassisch läuft. Was ich sicher nicht will.

So könnte man eine Funktionalität basierten Ansatz. Das ist der Versuch, die neuen Stildialoge und den Fallback auf den alten Stildialog zu verwenden, wenn der neue fehlschlägt. Versuchen Sie also, eine IFileSaveDialog zu erstellen. Weisen Sie UseLatestCommonDialogs zu, ob das erfolgreich ist oder nicht.


Auf der anderen Seite wird diese compat Einstellung soll auf Anwendungen verwendet werden, die Themen nicht korrekt funktionieren, wenn aktiviert sind. Ihre Anwendung funktioniert unter Themen korrekt und ich denke, es ist völlig gerechtfertigt, dass Sie sagen, dass Ihre Anwendung diesen bestimmten Kompatibilitätsmodus nicht unterstützt.

Sie sind nicht zu unterstützen Kompatibilitätsmodi erwartet. Wenn Sie zum Beispiel aufhören, XP zu unterstützen, dann wird nicht erwartet, dass Sie die XP-comp-Shims unterstützen.

Auf Reflexion, die mein Rat an Sie ist. Mach einfach nichts. Wenn Ihre Benutzer nach einem Fehler Ihrer App fragen, teilen Sie ihnen mit, dass Sie diesen Kompatibilitätsmodus nicht unterstützen. Es ist nicht Ihre Aufgabe, die Kompatibilitätsmodi Ihrer Anwendung zu unterstützen.

+0

Die Fremdheit ist, dass es Zeiten gibt, in denen "IsWindowsVistaOrGreater und InitThemeLibrary and UseThemes" false zurückgibt, aber es richtig und richtig ist, die neuen Dialoge zu verwenden. –

+1

Ich wünschte, Embarcadero würde aufhören, 'TOpenDialog' /' TSaveDialog' mit dem halben Dutzend nutzloser Prüfungen für verschiedene OS/Framework-Funktionalitäten zu überladen, bevor entschieden wird, ob 'IFileDialog' verwendet werden soll oder nicht. Jede Version scheint weitere Prüfungen hinzuzufügen.Entweder ist "IFileDialog" verfügbar oder nicht, das Betriebssystem entscheidet. Wenn 'UseLatestCommonDialogs' wahr ist, dann versuche,' IFileDialog' zu laden, und wenn es fehlschlägt, falle zum alten Dialog zurück. Erledigt. Aber das scheinen sie nicht zu wollen. –

+0

@Remy Ich habe diesen Aussichtspunkt ursprünglich geteilt. Aber jetzt frage ich mich, warum wir einen Kompat-Modus für Pre-XP-Apps unterstützen müssten. Ich halte es jetzt für vertretbar, dass wir uns in unseren modernen Apps nicht um solche Modi kümmern. –

Verwandte Themen