TFileOpenDialog 和 TFileSaveDialog 有不同的 GUID

Do TFileOpenDialog and TFileSaveDialog have different GUID

我已经创建了后代 TFileOpenDialog 和 TFileSaveDialog。 两者的 GUID 相同还是不同?我将其用于 TFileOpen 和 TFileSave 对话框:

FileDialog.QueryInterface(StringToGUID('{8016B7B3-3D49-4504-A0AA-2A37494E606F}'), FileDialogCustomize);

我创建了两个演示来测试该组件。一个 运行 时间和另一个设计时间。

我询问 GUID,因为当我在 运行 时创建 TFileOpenDialog 后代时,TFileOpenDialog 显示的标题为 'Open File' 并且预览显示在对话框的右侧.它是完美的,功能如您所料,但是当我安装对话框和 运行 设计时演示时,对话框出现时标题为 'Save File',并且没有显示预览。

我不明白为什么会发生这种情况。如有必要,我可以展示一些代码,但我不明白为什么设计时间和 运行 时间会因为对话框的创建方式不同而表现不同:

//TFileOpenDialog descendent
CoCreateInstance(CLSID_FileOpenDialog, nil, CLSCTX_INPROC_SERVER,
    IFileOpenDialog, FileDialog);
//TFileSaveDialog descendent
CoCreateInstance(CLSID_FileSaveDialog, nil, CLSCTX_INPROC_SERVER,
    IFileSaveDialog, FileDialog);

这是打开对话框的代码:

{ TIEWin7FileOpenDialog }

constructor TIEWin7FileOpenDialog.Create(AOwner: TComponent);
begin
  FillOpenFileTypesFilter;
  inherited Create(AOwner);
end;

destructor TIEWin7FileOpenDialog.Destroy;
begin
  inherited Destroy;
end;

procedure TIEWin7FileOpenDialog.FillOpenFileTypesFilter;
{ Fill the TIEWin7FileOpenDialog FFilterArray with FileTypes }
begin
  CoCreateInstance(CLSID_FileOpenDialog, nil, CLSCTX_INPROC_SERVER,
    IFileOpenDialog, FileDialog);
  { Create an array of file types for OpenDialog }
  SetLength(FFilterArray, 26);
  FFilterArray[0].pszName := PWideChar(Widestring('Common Graphic Files'));
  FFilterArray[0].pszSpec :=
    PWideChar(Widestring
    ('*.tif;*.tiff;*.gif;*.png;*.apf;*.cur;*.pcx;*.ani;*.jpg;*.jpeg;*.jp2;*.j2k*;*.bmp;*.ico;*.emf;*.wmf;*.tga;*.wdp;*.hdp;*.avi')
    );
  FFilterArray[1].pszName := PWideChar(Widestring('JPEG Bitmap'));
  FFilterArray[1].pszSpec := PWideChar(Widestring('*.jpg;*.jpeg;*.jpe;*.jif'));
  FFilterArray[2].pszName := PWideChar(Widestring('TIFF Bitmap'));
  FFilterArray[2].pszSpec :=
    PWideChar(Widestring('*.tif;*.tiff;*.fax;*.g3n;*.g3f;*.xif'));
  FFilterArray[3].pszName := PWideChar(Widestring('CompuServe Bitmap'));
  FFilterArray[3].pszSpec := PWideChar(Widestring('*.gif'));
  FFilterArray[4].pszName := PWideChar(Widestring('PaintBrush'));
  FFilterArray[4].pszSpec := PWideChar(Widestring('*.pcx'));
  FFilterArray[5].pszName := PWideChar(Widestring('Windows Bitmap'));
  FFilterArray[5].pszSpec := PWideChar(Widestring('*.bmp;*.dib;*.rle'));
  FFilterArray[6].pszName := PWideChar(Widestring('Windows Icon'));
  FFilterArray[6].pszSpec := PWideChar(Widestring('*.ico'));
  FFilterArray[7].pszName := PWideChar(Widestring('Windows Cursor'));
  FFilterArray[7].pszSpec := PWideChar(Widestring('*.cur'));
  FFilterArray[8].pszName := PWideChar(Widestring('Portable Network Graphics'));
  FFilterArray[8].pszSpec := PWideChar(Widestring('*.png'));
  FFilterArray[9].pszName := PWideChar(Widestring('DICOM Bitmap'));
  FFilterArray[9].pszSpec := PWideChar(Widestring('*.dcm;*.dic;*.dicom;*.v2'));
  FFilterArray[10].pszName := PWideChar(Widestring('Windows Metafile'));
  FFilterArray[10].pszSpec := PWideChar(Widestring('*.wmf'));
  FFilterArray[11].pszName := PWideChar(Widestring('Targa Bitmap'));
  FFilterArray[11].pszSpec :=
    PWideChar(Widestring('*.tga;*.targa;*.vda;*.icb;*.vst;*.pix'));
  FFilterArray[12].pszName :=
    PWideChar(Widestring('Portable Pixmap, GrayMap, BitMap'));
  FFilterArray[12].pszSpec := PWideChar(Widestring('*.pxm;*.ppm;*.pgm;*.pbm'));
  FFilterArray[13].pszName := PWideChar(Widestring('Wireless Bitmap'));
  FFilterArray[13].pszSpec := PWideChar(Widestring('*.wbmp'));
  FFilterArray[14].pszName := PWideChar(Widestring('JPEG2000'));
  FFilterArray[14].pszSpec := PWideChar(Widestring('*.jp2'));
  FFilterArray[15].pszName := PWideChar(Widestring('JPEG2000 Code Stream'));
  FFilterArray[15].pszSpec := PWideChar(Widestring('*.j2k;*.jpc;*.j2c'));
  FFilterArray[16].pszName := PWideChar(Widestring('Multipage PCX'));
  FFilterArray[16].pszSpec := PWideChar(Widestring('*.dcx'));
  FFilterArray[17].pszName := PWideChar(Widestring('Camera RAW'));
  FFilterArray[17].pszSpec :=
    PWideChar(Widestring
    ('*.crw;*.cr2;*.nef;*.raw;*.pef;*.raf;*.x3f;*.bay;*.orf;*.srf;*.mrw;*.dcr;*.sr2')
    );
  FFilterArray[18].pszName := PWideChar(Widestring('Photoshop PSD'));
  FFilterArray[18].pszSpec := PWideChar(Widestring('*.psd'));
  FFilterArray[19].pszName :=
    PWideChar(Widestring('ImageEn Vectorial Objects'));
  FFilterArray[19].pszSpec := PWideChar(Widestring('*.iev'));
  FFilterArray[20].pszName := PWideChar(Widestring('ImageEn Layers'));
  FFilterArray[20].pszSpec := PWideChar(Widestring('*.lyr'));
  FFilterArray[21].pszName :=
    PWideChar(Widestring('ImageEn Layers and Objects'));
  FFilterArray[21].pszSpec := PWideChar(Widestring('*.all'));
  FFilterArray[22].pszName := PWideChar(Widestring('Microsoft HD Photo'));
  FFilterArray[22].pszSpec := PWideChar(Widestring('*.wdp;*.hdp'));
  FFilterArray[23].pszName := PWideChar(Widestring('Video For Windows'));
  FFilterArray[23].pszSpec := PWideChar(Widestring('*.avi'));
  FFilterArray[24].pszName := PWideChar(Widestring('Mpeg'));
  FFilterArray[24].pszSpec := PWideChar(Widestring('*.mpeg;*.mpg'));
  FFilterArray[25].pszName := PWideChar(Widestring('Windows Media Video'));
  FFilterArray[25].pszSpec := PWideChar(Widestring('*.wmv'));
  { Set the FileTypes Filter Array }
  FilterArray := FFilterArray;
end;

function TIEWin7FileOpenDialog.DoExecute: BOOL;
{ Create the dialogs and add control items }
const
  dwVisualGroup1ID: DWORD = 1200;
  dwVisualGroup2ID: DWORD = 1300;
  dwVisualGroup3ID: DWORD = 1400;
  dwVisualGroup4ID: DWORD = 1500;
  dwVisualGroup5ID: DWORD = 1600;
  dwVisualGroup6ID: DWORD = 1700;
  dwVisualGroup7ID: DWORD = 1800;
var
  iFileDialogEvent: TFileDialogEvent;
  iCookie: cardinal;
  iWideString: Widestring;
  iFilename: PWideChar;
  iFileTypeIndex: Integer;
  hr: HResult;
  ShellItem: IShellItem;
  iOptionsSet: cardinal;
begin
  { Add labels }
  FileDialog.QueryInterface(IFileDialogCustomize, FileDialogCustomize);
  FileDialogCustomize.StartVisualGroup(dwVisualGroup1ID, 'Frames');
  FileDialogCustomize.AddControlItem(1, 0, 'Frames: ');
  FileDialogCustomize.AddText(1, '');
  FileDialogCustomize.EndVisualGroup;
  { Add a visual group for BitDepth }
  FileDialogCustomize.StartVisualGroup(dwVisualGroup2ID, 'BitDepth');
  FileDialogCustomize.AddControlItem(2, 1, 'BitDepth: ');
  FileDialogCustomize.AddText(2, '');
  FileDialogCustomize.EndVisualGroup;
  { Add a visual group for Dimensions }
  FileDialogCustomize.StartVisualGroup(dwVisualGroup3ID, 'Dimensions');
  FileDialogCustomize.AddControlItem(3, 2, 'Dimensions:');
  FileDialogCustomize.AddText(3, '');
  FileDialogCustomize.EndVisualGroup;
  { Add a visual group for DPI }
  FileDialogCustomize.StartVisualGroup(dwVisualGroup4ID, 'DPI');
  FileDialogCustomize.AddControlItem(4, 3, 'DPI:');
  FileDialogCustomize.AddText(4, '');
  FileDialogCustomize.EndVisualGroup;
  { Add a visual group for FileType }
  FileDialogCustomize.StartVisualGroup(dwVisualGroup5ID, 'File Type');
  FileDialogCustomize.AddControlItem(5, 4, 'File Type:');
  FileDialogCustomize.AddText(5, '');
  FileDialogCustomize.EndVisualGroup;
  { Add a visual group for FileSize }
  FileDialogCustomize.StartVisualGroup(dwVisualGroup6ID, 'File Size');
  FileDialogCustomize.AddControlItem(6, 5, 'File Type:');
  FileDialogCustomize.AddText(6, '');
  FileDialogCustomize.EndVisualGroup;
  { Add a visual group for MemorySize }
  FileDialogCustomize.StartVisualGroup(dwVisualGroup7ID, 'Memory Size');
  FileDialogCustomize.AddControlItem(7, 6, 'Memory:');
  FileDialogCustomize.AddText(7, '');
  FileDialogCustomize.EndVisualGroup;
  { Set Default Extension }
  iWideString := self.DefaultExtension;
  FileDialog.SetDefaultExtension(PWideChar(iWideString));
  { Set Default Filename }
  iWideString := FileName;
  iFilename := PWideChar(FileName);
  FileDialog.SetFilename(iFilename);
  { Set FileType (filter) index }
  iFileTypeIndex := 1;
  FileDialog.SetFileTypeIndex(iFileTypeIndex);
  self.FileTypeIndex := iFileTypeIndex;
  { Set Options }
  iOptionsSet := 0;
  if fdoOverwritePrompt in Options then
    iOptionsSet := iOptionsSet + FOS_OVERWRITEPROMPT;
  if fdoStrictFileTypes in Options then
    iOptionsSet := iOptionsSet + FOS_STRICTFILETYPES;
  if fdoNoChangeDir in Options then
    iOptionsSet := iOptionsSet + FOS_NOCHANGEDIR;
  if fdoPickFolders in Options then
    iOptionsSet := iOptionsSet + FOS_PICKFOLDERS;
  if fdoForceFileSystem in Options then
    iOptionsSet := iOptionsSet + FOS_FORCEFILESYSTEM;
  if fdoAllNonStorageItems in Options then
    iOptionsSet := iOptionsSet + FOS_ALLNONSTORAGEITEMS;
  if fdoNoValidate in Options then
    iOptionsSet := iOptionsSet + FOS_NOVALIDATE;
  if fdoAllowMultiSelect in Options then
    iOptionsSet := iOptionsSet + FOS_ALLOWMULTISELECT;
  if fdoPathMustExist in Options then
    iOptionsSet := iOptionsSet + FOS_PATHMUSTEXIST;
  if fdoFileMustExist in Options then
    iOptionsSet := iOptionsSet + FOS_FILEMUSTEXIST;
  if fdoCreatePrompt in Options then
    iOptionsSet := iOptionsSet + FOS_CREATEPROMPT;
  if fdoShareAware in Options then
    iOptionsSet := iOptionsSet + FOS_SHAREAWARE;
  if fdoNoReadOnlyReturn in Options then
    iOptionsSet := iOptionsSet + FOS_NOREADONLYRETURN;
  if fdoNoTestFileCreate in Options then
    iOptionsSet := iOptionsSet + FOS_NOTESTFILECREATE;
  if fdoHideMRUPlaces in Options then
    iOptionsSet := iOptionsSet + FOS_HIDEMRUPLACES;
  if fdoHidePinnedPlaces in Options then
    iOptionsSet := iOptionsSet + FOS_HIDEPINNEDPLACES;
  if fdoNoDereferenceLinks in Options then
  iOptionsSet := iOptionsSet + FOS_NODEREFERENCELINKS;
  if fdoDontAddToRecent in Options then
    iOptionsSet := iOptionsSet + FOS_DONTADDTORECENT;
  if fdoForceShowHidden in Options then
    iOptionsSet := iOptionsSet + FOS_FORCESHOWHIDDEN;
  if fdoDefaultNoMiniMode in Options then
    iOptionsSet := iOptionsSet + FOS_DEFAULTNOMINIMODE;
  if fdoForcePreviewPaneOn in Options then
    iOptionsSet := iOptionsSet + FOS_FORCEPREVIEWPANEON;
  FileDialog.SetOptions(iOptionsSet);
  { The array of file types for OpenDialog is initialized in OnCreate }
  { Set the FileTypes }
  FileDialog.SetFileTypes(26, FFilterArray);
  { Setup the TFileDialogEvents }
  iFileDialogEvent := TFileDialogEvent.Create;
  iFileDialogEvent.FType := 'Open';
  iFileDialogEvent.QueryInterface(IFileDialogEvents, FileDialogEvents);
  FileDialog.Advise(iFileDialogEvent, iCookie);
  { Show the dialog }
  hr := FileDialog.Show(Application.Handle);
  if hr = 0 then
  begin
    ShellItem := nil;
    hr := FileDialog.GetResult(ShellItem);
    if hr = 0 then
    begin
      hr := ShellItem.GetDisplayName(SIGDN_FILESYSPATH, iFilename);
      if hr = 0 then
        FileName := iFilename;
    end;
    Result := true;
  end
  else
  begin
    Result := False;
  end;
  FileDialog.Unadvise(iCookie);
end;

function TIEWin7FileOpenDialog.Execute: Boolean;
{ Handle Execute which calls DoExecute before the dialog is visible }
begin
  Result := DoExecute;
end;

procedure TIEWin7FileOpenDialog.OnExecute;
{ Handle Execute which calls DoExecute before the dialog is visible }
begin
  DoExecute;
end;

我建议另一种方法 - 从 Delphi 现有的 Vcl.Dialogs.TFileOpenDialog 组件派生 TIEWin7FileOpenDialog,它为您包装 IFileOpenDialog 接口。

让构造函数填充继承的 TFileOpenDialog.FileTypes collection as needed, and override the virtual TFileOpenDialog.DoOnExecute() method to add your visual groups and hook up your IFileDialogControlEvents handler. DoOnExecute() is called after the IFileDialog is created and before its Show() method is called. The IFileDialog interface will be available in the TFileOpenDialog.Dialog 属性.

您的代码手动执行的所有其他操作都已由 TFileOpenDialog 为您处理。

试试这个:

uses
  ..., Vcl.Dialogs, Winapi.ShlObj;

type
  TIEWin7FileOpenDialog = class(TFileOpenDialog)
  protected
    procedure DoOnExecute; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TIEWin7FileOpenDialogControlEvents = class(TInterfacedObject, IFileDialogEvents, IFileDialogControlEvents)
  public
    // implement IFileDialogControlEvents as needed.
    // TFileOpenDialog already has an IFileDialogEvents
    // implementation so just ignore those methods, though
    // you still have to implement them here...
  end;

constructor TIEWin7FileOpenDialog.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  { Fill the FileTypes collection }
  with FileTypes.Add do
  begin
    DisplayName := 'Common Graphic Files';
    FileMask := '*.tif;*.tiff;*.gif;*.png;*.apf;*.cur;*.pcx;*.ani;*.jpg;*.jpeg;*.jp2;*.j2k*;*.bmp;*.ico;*.emf;*.wmf;*.tga;*.wdp;*.hdp;*.avi';
  end;
  with FileTypes.Add do
  begin
    DisplayName := 'JPEG Bitmap';
    FileMask := '*.jpg;*.jpeg;*.jpe;*.jif';
  end;
  // and so on...

  { Set FileType (filter) index }
  FileTypeIndex := 1;
end;

procedure TIEWin7FileOpenDialog.DoOnExecute;
const
  dwVisualGroup1ID: DWORD = 1200;
  dwVisualGroup2ID: DWORD = 1300;
  dwVisualGroup3ID: DWORD = 1400;
  dwVisualGroup4ID: DWORD = 1500;
  dwVisualGroup5ID: DWORD = 1600;
  dwVisualGroup6ID: DWORD = 1700;
  dwVisualGroup7ID: DWORD = 1800;
var
  DialogCustomize: IFileDialogCustomize;
  DialogEvents: TIEWin7FileOpenDialogControlEvents;
  Cookie: Cardinal;
begin
  DialogCustomize := Self.Dialog as IFileDialogCustomize;

  { Add labels }
  DialogCustomize.StartVisualGroup(dwVisualGroup1ID, 'Frames');
  DialogCustomize.AddControlItem(1, 0, 'Frames: ');
  DialogCustomize.AddText(1, '');
  DialogCustomize.EndVisualGroup;
  { Add a visual group for BitDepth }
  DialogCustomize.StartVisualGroup(dwVisualGroup2ID, 'BitDepth');
  DialogCustomize.AddControlItem(2, 1, 'BitDepth: ');
  DialogCustomize.AddText(2, '');
  DialogCustomize.EndVisualGroup;
  { Add a visual group for Dimensions }
  DialogCustomize.StartVisualGroup(dwVisualGroup3ID, 'Dimensions');
  DialogCustomize.AddControlItem(3, 2, 'Dimensions:');
  DialogCustomize.AddText(3, '');
  DialogCustomize.EndVisualGroup;
  { Add a visual group for DPI }
  DialogCustomize.StartVisualGroup(dwVisualGroup4ID, 'DPI');
  DialogCustomize.AddControlItem(4, 3, 'DPI:');
  DialogCustomize.AddText(4, '');
  DialogCustomize.EndVisualGroup;
  { Add a visual group for FileType }
  DialogCustomize.StartVisualGroup(dwVisualGroup5ID, 'File Type');
  DialogCustomize.AddControlItem(5, 4, 'File Type:');
  DialogCustomize.AddText(5, '');
  DialogCustomize.EndVisualGroup;
  { Add a visual group for FileSize }
  DialogCustomize.StartVisualGroup(dwVisualGroup6ID, 'File Size');
  DialogCustomize.AddControlItem(6, 5, 'File Type:');
  DialogCustomize.AddText(6, '');
  DialogCustomize.EndVisualGroup;
  { Add a visual group for MemorySize }
  DialogCustomize.StartVisualGroup(dwVisualGroup7ID, 'Memory Size');
  DialogCustomize.AddControlItem(7, 6, 'Memory:');
  DialogCustomize.AddText(7, '');
  DialogCustomize.EndVisualGroup;

  { Setup the TFileDialogEvents }
  DialogEvents := TIEWin7FileOpenDialogControlEvents.Create;
  DialogEvents.FType := 'Open';
  Self.Dialog.Advise(DialogEvents, Cookie);

  { trigger OnExecute event handler }
  inherited;
end;