I am trying to use a TSaveDialog
in Delphi XE6:
if not SaveDialog1.Execute(0) then
Exit;
The call immediately returns false, without displaying any dialog. I traced it down to the act of creating the shell Save Dialog COM object:
function TCustomFileSaveDialog.CreateFileDialog: IFileDialog;
var
LGuid: TGUID;
begin
LGuid := CLSID_FileSaveDialog;
CoCreateInstance(LGuid, nil, CLSCTX_INPROC_SERVER,
StringToGUID(SID_IFileSaveDialog), Result);
end;
The call to CoCreateInstance
is failing. I created minimal code to reproduce the issue:
procedure TForm1.Button1Click(Sender: TObject);
const
CLSID_FileSaveDialog: TGUID = '{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}';
begin
CreateComObject(CLSID_FileSaveDialog);
end;
It throws the EOleSysError exception:
0x80040111: ClassFactory cannot supply requested class, ClassID: {C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}
My application is using Version 6 of the Common Controls library (6.0.7601.18837), but i realized it only happens if the user has disabled visual styles for my application:
We're still using version 6 of the common controls library, just that IsAppThemed
returns false.
Note: I know a lot of people mistakenly believe that:
- Visual Styles API only works if we have version 6 of Comctrl32.dll loaded
- If version 6 of Comctrl32.dll is loaded, then Visual Styles API will work
- If we're not using ComCtrl v6 then that means Visual Styles are disabled
- Visual Styles are disabled if we're using the old common controls library
The brute-force solution is to set the global UseLatestCommonDialogs to false.
But that's pretty bad, as it only applies to people who have disabled visual styles in their application:
- the dialog continues to work on OS without visual styles (e.g. Windows Server 2008 R2)
- the dialog continues to work with visual styles turned off (e.g. Windows 7 with visual styles turned off)
This means i cannot simply use IsAppThemed
, as that also returns false if IsThemeActive
is false.
| IsThemeActive | IsAppThemed | Disable visual styles | Result |
|---------------|-------------|-----------------------|-----------|
| True | True | Unchecked | Works |
| True | False | Checked | Fails |
| False | False | Unchecked | Works |
| False | False | Checked | Fails |
What i guess i'm asking is how to check the status of the Disble Visual Styles compat flag.
What i'm really asking is how to make the TSaveDialog
work correctly in Delphi (without implying that reading the compat flag is part of the solution).
.Execute
doesn't show up in code insight ii) Calling.Execute
causes the window to be owned byApplicationMainHandle
iii) In reality i want the dialog to be owned to the form i'm looking at (e.g.SaveDialog1.Execute(Self.Handle)
). But i didn't want people focusing on the parameter passed toExecute
, so i simplified it to.Execute(0)
. In reality, Delphi's window ownership is broken, and it ignored the owner - instead bringing whatever it wants forward. – SoberIsCompositionActive
also? Just a guess – Newland