본문 바로가기

Library/Windows Programming

CShellFileOpenDialog / CShellFileSaveDialog 사용하기

WTL의 CShellFileOpenDialog / CShellFileSaveDialog는 비스타 이상에서 지원되는 대화상자 컨트롤이다. 이들은 전통적인 대화 상자와 달리, 탐색기과 같은 스타일을 가진다.




CShellFileOpenDialog / CShellFileSaveDialog를 사용하려면 WTL의 atldlgs.h를 먼저 포함해야 한다. 이 대화 상자들이 인스턴스화 될 때 플랫폼이 비스타 이상이 아니라면, 인스턴스의 m_spFileDlg는 널(null)이다. 플랫폼이 비스타가 아닐 수도 있다면, 윈도우 버전을 확인하는 절차가 필요할 것이다. 이들은 고전적인 대화 상자와 달리 CShellMultiFileOpenDialog와 같은 클래스가 존재하지 않으며, COM 인터페이스를 사용하여 대화 상자를 조정해주어야 한다. CShellFileOpenDialog / CShellFileSaveDialog는 CFileDialog와 비교해볼 때 더 풍부한 기능을 제공하지만, COM 인터페이스를 사용해야 한다. 여러 파일을 선택하려는 경우, 간단히 다음과 같은 코드가 필요하다.


CShellFileOpenDialog dlg;
FILEOPENDIALOGOPTIONS opt;
dlg.GetPtr()->GetOptions(&opt);
opt |= FOS_ALLOWMULTISELECT;
dlg.GetPtr()->SetOptions(opt);


만약 대화 상자에서 여러 파일을 선택했고, 그 파일의 이름을 얻어오고 싶다면 열거자(enumerator)를 얻어오고, 열거자를 사용하여 선택된 아이템을 차례로 돌아다니면서 원하는 값을 얻어오면 된다. 코드는 다음과 같다.


CComPtr< IShellItemArray > ar;
dlg.GetPtr()->GetResult(&ar);

CComPtr< IEnumShellItems > e;
ar->EnumItems(&e);
IShellItem *i;
while(e->Next(1, &i, 0) != S_FALSE) {
    LPWSTR filename;
    i->GetDisplayName(SIGDN_FILESYSPATH, &filename);

    // do something
    ....
}


filename은 이미 존재하는 열거자 속성에 대한 포인터이기 때문에 새로 버퍼를 할당받아 복사할 필요가 없다. 물론, 복사할 필요가 있을 때도 있겠지만 그럴 경우 완전히 문자열만 복사해야 하며, filename을 그대로 힙 해제 함수에 전달하면 당연히 정의되지 않은 동작을 하게 된다. while 루프 안에서 IShellItem 인터페이스를 어떻게 사용할지는 개인의 자유다.