2012-06-11 3 views
-1

TFileSaveDialog 자손 구성 요소를 구축 중입니다. 자손은 이벤트가 다음에 의해 처리되는 푸시 버튼을가집니다.TFileDialogEvent에서 IFileDialog에 대한 핸들을 가져 와서 파일 이름을 얻습니다.

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 정의하여이 문제를 해결 : 구성 요소 수준에서 var과 같은 IFileDialog이 그때라고

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 

감사의 모든 ... 롭 당신에게 감사합니다 ... 당신의 게시물이 도움이되었습니다.

+0

을; with pfd : = FileDialog as IFileDialog; –

+0

업데이트 된 질문의 코드는 무의미합니다. FileDialog는 이미 IFileDialog입니다. 그리고 Rob의 솔루션은 어쨌든 여분의 필드가 필요 없게 작동합니다. –

답변

4

개체에 GUID {8016B7B3-3D49-4504-A0AA-2A37494E606F}와 일치하는 인터페이스를 쿼리하고 결과를 IFileDialog 참조에 저장합니다. 문제는 {0126B7B3-3D49-4504-A0AA-2A37494E606F}가 IFileDialogCustomize 인터페이스의 GUID이며 IFileDialog이 아니라는 것입니다. IFileDialog 인터페이스의 여섯 번째 방법 인 GetFileName을 호출하려고 시도하지만 변수가 실제로 IFileDialogCustomize 인터페이스를 보유하고 있기 때문에 제어가 인터페이스의 여섯 번째 함수로 전송됩니다. 컴파일러는 유형 불일치를 catch 할 수 없습니다. 런타임시 GUID를 동적으로 구성하기 때문에 (컴파일 타임에 값을 알 수 없으므로) 부분적으로 QueryInterface의 두 번째 매개 변수가 형식이 지정되지 않았기 때문입니다. 변수의 유형이 첫 번째 매개 변수와 일치한다고 가정).

런타임에 GUID를 계산하는 것보다 쉬운 방법이 있습니다. 인터페이스 유형은 이며 자동으로과 관련 GUID (GUID가있는 경우)로 사용할 수 있습니다. IFileDialog 인터페이스를 요청하려면, 단지 QueryInterface에 직접 그 식별자를 전달합니다

FileDialog.QueryInterface(IFileDialog, pfd); 

당신이 as 연산자를 사용하는 경우도 QueryInterface를 호출 할 필요가 없습니다 : 직접 QueryInterface를 호출 할 때

pfd := FileDialog as IFileDialog; 

을, 오류 코드에 대한 결과를 확인해야합니다. as 연산자를 사용하면 지원되지 않는 인터페이스에서 예외가 발생합니다. 이미 당신을 당신이 수동으로 사냥 할 필요가 없습니다

if Supports(FileDialog, IFileDialog, pfd) then ... 
+0

죄송합니다 ...FileDialog가 TFileDialogEvent.OnButtonClicked 이벤트 함수에 정의되어 있지 않습니다. 여기에 어떻게 정의되어 있습니까? – Bill

+0

저에게 묻지 마십시오. * 당신은 당신의 질문에 그것을 붙여 넣은 사람입니다. –

+0

나는 그것이 나를 위해 작동하지 않는 이유의 FileDialog는 여전히 가능하다 함수 TFileDialogEvent에 정의되어 있지 않은 경우 즉 ... 추측? – Bill

0

TSaveFileDialog가 입력 IFileDialog의 공개 Dialog 속성이 있습니다 : 당신은 너무 많은 오류 검사없이-실패 패스하려면, 대신 Supports 기능을 사용 예를 들어, 그것에 직접 액세스가 : 당신이 FileDialog.QueryInterface (IFileDialog, PFD)를 교체해야

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; 
+0

TFileDialogEvent는 대화 상자를 구현하는 클래스가 아니라 권고 이벤트를 구현하는 클래스입니다. –

관련 문제