-1

TFileSaveDialog の子孫コンポーネントを構築しています。子孫には、イベントが処理される PushButton があります。

function TFileDialogEvent.OnButtonClicked(const pfdc: IFileDialogCustomize;
  dwIDCtl: DWORD): HResult; stdcall;
var
  iImageEnIO: TImageEnIO;
  iFilename: string;
  iName: PChar;
  pfd: IFileDialog;
begin
  if dwIDCtl = dwVisualGroup8ID then
  begin
    iImageEnIO := TImageEnIO.Create(nil);
    try
      FileDialog.QueryInterface(
    StringToGUID('{8016B7B3-3D49-4504-A0AA-2A37494E606F}'),
    pfd);
    // How to get correct valid handle to IFileDialog?
      pfd.GetFileName(iName);
      iFilename := string(iName);
      if FileExists(iFilename) then
      begin

このコンポーネントは、さまざまなコントロール ラベルの画像情報も正しく表示します。コンポーネントは選択されたファイル名を正常に返し、フォルダーの変更を許可しますが、OnButtonClicked イベントで pfd.GetFileName(iName) からファイル名を取得すると、無効なファイル名が返されます。問題は、pfd: IFileDialog の正しいハンドルを取得していないことが原因だと思います。

更新: FileDialog: IFileDialog をコンポーネント レベルで var として定義することでこれを解決し、次に呼び出しました

function TFileDialogEvent.OnButtonClicked(const pfdc: IFileDialogCustomize;
  dwIDCtl: DWORD): HResult; stdcall;
var
  iImageEnIO: TImageEnIO;
  iFilename: string;
  pFolder: PWideChar;
  iFolder: string;
  iName: PChar;
  pfd: IFileDialog;
  hr: HRESULT;
  aShellItem: IShellItem;
begin
  if dwIDCtl = dwVisualGroup8ID then
  begin
    iImageEnIO := TImageEnIO.Create(nil);
    try
      FileDialog.QueryInterface(IFileDialog, pfd);
      pfd.GetFileName(iName);
      // Get the ShellItem
      hr := SHCreateItemFromParsingName(iName, nil,
      StringToGUID(SID_IShellItem), aShellItem);
      // Get the folder
      pfd.GetFolder(aShellItem);
      // Get the folder displayname
      aShellItem.GetDisplayName(SIGDN_FILESYSPATH, pFolder);
      iFolder := string(pFolder);
      if DirectoryExists( iFolder) then
        iFilename := IncludeTrailingPathDelimiter( iFolder) + string(iName);
      if FileExists(iFilename) then
      begin

ありがとうございました... ありがとうロブ... あなたの投稿は役に立ちました。

4

2 に答える 2

4

GUID {8016B7B3-3D49-4504-A0AA-2A37494E606F} に一致するインターフェイスのオブジェクトをクエリし、結果をIFileDialog参照に格納しています。問題は、{8016B7B3-3D49-4504-A0AA-2A37494E606F} がIFileDialogCustomizeインターフェイスの GUID であり、IFileDialog. GetFileNameインターフェイスの 6 番目のメソッドであるを呼び出そうとしますIFileDialogが、変数は実際にはインターフェイスを保持しているため、代わりにそのインターフェイスIFileDialogCustomizeの 6 番目の関数に制御が渡されます。コンパイラは、型の不一致をキャッチできません。その理由の 1 つは、実行時に GUID を動的に構築している (コンパイル時に値がわからない) ことと、2 番目のパラメーターがQueryInterface型付けされていません (そのため、変数の型が最初のパラメーターと一致するはずであることを認識できません)。

実行時に GUID を計算するよりも簡単な方法があります。インターフェイスの種類は、関連付けられた GUID として自動的に使用可能になります (GUID がある場合)。インターフェイスをリクエストするにはIFileDialog、その識別子を に直接渡しますQueryInterface

FileDialog.QueryInterface(IFileDialog, pfd);

演算子QueryInterfaceを使用する場合は、呼び出す必要さえありません。as

pfd := FileDialog as IFileDialog;

直接呼び出す場合はQueryInterface、エラー コードの結果を確認する必要があります。演算子を使用するasと、サポートされていないインターフェイスで例外が発生します。あまり多くのエラー チェックを行わずに合格/不合格を確認したい場合は、Supports代わりに次の関数を使用します。

if Supports(FileDialog, IFileDialog, pfd) then ...
于 2012-06-11T19:16:44.863 に答える
0

TSaveFileDialogtypeのパブリックDialogプロパティがあるIFileDialogため、手動で探す必要はありません。すでに直接アクセスできます。たとえば、次のようになります。

function TFileDialogEvent.OnButtonClicked(const pfdc: IFileDialogCustomize;  dwIDCtl: DWORD): HResult; stdcall; 
var 
  iImageEnIO: TImageEnIO; 
  iFilename: string; 
  iName: PWideChar; 
begin 
  if dwIDCtl <> dwVisualGroup8ID then
    Result := E_NOTIMPL
  else
  begin
    Result := S_OK;
    if FAILED(Self.Dialog.GetFileName(iName)) then Exit;
    try 
      iFilename := string(iName); 
    finally
      CoTaskMemFree(iName);
    end;
    iImageEnIO := TImageEnIO.Create(nil); 
    try 
      if FileExists(iFilename) then 
      begin 
        ...
      end;
    finally
      iImageEnIO.Free;
    end; 
  end;
end;
于 2012-06-12T01:14:08.540 に答える