http://msnmarketing.co.kr/msn_live/index.asp?authkey=MSN040913434112721175987512

iiasuraii.byus.net

Skip to content

Menu

Choice : Use stylesheet or not
This document use xhtml with css

Member menu


22. SHBrowseForFolder()로 사용자가 폴더를 검색하기


출처: 델파이코리아 인천 모임
원본글: http://sobakcc.com/bbs/view.php?id=tip&no=43
---------------------------------------------------------


- 제 목 : SHBrowseForFolder()로 사용자가 폴더를 검색하기
- 분 류 : Windows API
- 자료출처 : 하이텔 비주얼파워툴 동호회
- 등 록 일 : 2000년 4월 19일 수요일
- 작 성 자 : 배경환
--------------------------------------------------------------------------------
하이텔의 비주얼 파워툴 동호회의 델파이 Q&A 중에서
제 목:[질문] SHBrowseForFolder()
보낸이:김병희 (k8z7 ) 2000-03-08 01:15

다우에서 만든 델파이Q&A 218쪽에는 다음 예제가 나옵니다.


-------------------------------------------------------
218/Shell API 함수인 SHBrowseForFolder()를 써서 사용자가 폴더를 검색하도록 하
려면?


다음 예는 SHBrowseForFolder() 함수를 써서 사용자가 주어진 디렉토리 오브젝트를
선택할 수 있도록 한다.

uses ShellAPI, ShlObj;

procedure TForm1.changeDirClick(Sender: TObject);
var
TitleName: string;
lpItemID: PItemIDList;
BrowseInfo: TBrowseInfo;
DisplayName: Array[0..MAX_PATH] of Char;
TempPath: array[0..MAX_PATH] of Char;
Begin
FillChar(BrowseInfo, sizeof(TBrowseInfo), #0);
BrowseInfo.hwndOwner := Form1.Handle;
BrowseInfo.pszDisplayName := @DisplayName;
TitleName := 'Please specify a directory';
BrowseInfo.lpszTitle := PChar(TitleName);
BrowseInfo.ulFlags := BIF_RETURNONLYFSDIRS;
lpItemID := SHBrowseForFolder(BrowseInfo);

If lpItemID <> Nil Then Begin
SHGetPathFromIDList(lpItemID, TempPath);
Showmessage(TempPath);
GlobalFreePtr(lpItemID);
End;
End;

그런데, 항상 같은 위치에서 시작하는 것이 문제다.

1) 디폴트 폴더를 코드로 지정할 수 있었으면 좋겠다.

2) 일단 폴더를 선택하면 그것이 디폴트로 바뀌면 좋겠다.

누구 아는 사람 없나?
-------------------------------------------------------

이상 내용이 코드를 베끼고 테스트하면서 정리한 글입니다.

위 두 문제의 답을 가르쳐 주시면 고맙겠습니다.


lder라는 인터페이스는 Shell의 NameSpace Extension을 작성할 때

사용되는 인터페이스이며 특정 폴더에 대한 내용을 익스플로러가 요청할 때

호출됩니다. 그러므로 모든 폴더는 이 인터페이스를 별도로 구현하거나

이미 기본적으로 구현된 인터페이스를 가지게 되는데,

윈도우의 데스크탑 폴더는 이미 확실하게 이 인터페이스를 구현해 놓았다고

볼 수 있습니다.

그래서 SHGetDesktopFolder라는 API를 호출하면 (데스크탑 폴더를 위해 구현된)

IShellFolder 인터페이스를 가져올 수 있습니다. 우리가 원하는 것은

ParseDisplayName 메쏘드가 구현되어 있는 인터페이스이며 데스크탑 폴더의

이 인터페이스는 이 메쏘드를 확실히 구현해 놓았으므로(MSDN에 의해) 이

API를 사용해서 IShellFolder 인터페이스를 가져오면 됩니다.

그러면 이렇게 가져온 IShellFolder의 ParseDisplayName에 원하시는 폴더의

디스플레이명(일반 폴더는 디스플레이명이 풀패스입니다.)을 넣어 주시면

그 풀패스에 해당하는 PIDL을 만들어서 리턴합니다.

이 리턴된 PIDL을 TBrowseInfo 레코드의 pidlRoot로 지정해 주시면 원하시는

결과를 얻으실 수 있는 것입니다.

단, ParseDisplayName은 그 인자로 UniCode를 받으므로 풀패스를 유니코드로

변환시켜 주어야 합니다. 일반적으로 API를 이용한다면 MultiByteToWideChar같은

API를 이용해야 하지만 델파이는 단순히 타입 캐스트만으로도 유니코드로

변환시켜 주므로 병규님의 소스에서는 pOleStr로 캐스트하신 겁니다.

또, 다행히 (어쩌면 당연히) 델파이에서는 PIDL을 위한 프로토타입을

ShlObj.pas에 모두 import해 놓았으므로 단순히 uses구문에 ShlObj만 넣어

주시면 PIDL에 관련된 모든 자료형을 델파이 형태로 사용하실 수 있습니다.

그리고 참고사항이지만 보통 C++등으로 위의 내용을 구현한다고 하면

마지막에 IShellFolder 인터페이스의 인스턴스를 해제하기 위해

IShellFolder.Release를 호출해 주어야 정상이지만 델파이는 인터페이스가

그 통용범위를 벗어나면 자동으로 릴리즈를 수행하므로 필요없는 작업이

됩니다. 아니, 오히려 Release(델파이에서는 _Release)를 호출해 주면

중복 해제작업이 되어 버리므로 익셉션이 발생할 수 있습니다.

이상입니다. 위의 설명과 병규님의 소스를 같이 보시면 이해가

쉬우실 겁니다.

그럼 이만...


------------------------------------------------------------
아래에는 위의 글에 대한 참고를 위하여 배경환이가 정리하여 보았습니다.

BROWSEINFO

SHBrowseForFolder 함수(참조1)에 대한 파라메터를 포함하고 사용자에 의해 선택된
폴더에 관하여 정보를 받는다.

아래에는 BROWSEINFO의 구조에 대하여 나타내었다.

typedef struct _browseinfo {
HWND hwndOwner; // see below
LPCITEMIDLIST pidlRoot; // see below
LPSTR pszDisplayName; // see below
LPCSTR lpszTitle; // see below
UINT ulFlags; // see below
BFFCALLBACK lpfn; // see below
LPARAM lParam; // see below
int iImage; // see below
} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO;

그럼 구조체 멤버에 대하여 알아보도록 하자.

- hwndOwner

Dialog Box에 대한 Owner 윈도우의 Handle.

- pidlRoot

어디서부터 검색을 시작할 지, "root" 폴더의 위치를 지정하는 아이템 식별자
리스트(ITEMIDLIST 구조체: 참조2)에 대한 포인터. 단지 지정된 폴더와 서브
폴더들만이 Dialog Box에 나타난다. 이 멤버 변수는 Null 값을 가질 수 있고
이 경우에 Name Space root(Desktop Folder)가 사용된다.

- pszDisplayName

사용자에 의하여 지정된 폴더의 Display Name을 받는 버퍼의 포인터. 이 버퍼의
크기는 MAX_PATH 바이트로 가정한다.

- lpszTitle

Dialog Box에서 트리뷰 상단에 출력되는 null-terminated 문자열에 대한 포인터.
이 문자열은 사용자에게 명령을 하기 위하여 사용될 수 있다.

- ulFlags

다른 옵션뿐만 아니라 Dialog box에서 리스트된 폴더의 타입을 결정하는 값.
이 멤버 변수는 다음과 같은 값이나 zero값을 포함할 수 있다.

BIF_BROWSEFORCOMPUTER
Only returns computers. If the user selects anything other than a computer,
the OK button is grayed.

BIF_BROWSEFORPRINTER Only returns printers. If the user selects anything
other than a printer, the OK button is grayed.

BIF_DONTGOBELOWDOMAIN Does not include network folders below the domain level
in the tree view control.

BIF_RETURNFSANCESTORS Only returns file system ancestors. If the user selects
anything other than a file system ancestor, the OK button is grayed.

BIF_RETURNONLYFSDIRS Only returns file system directories. If the user selects
folders that are not part of the file system, the OK button is grayed.

BIF_STATUSTEXT Includes a status area in the dialog box. The callback function
can set the status text by sending messages to the dialog box.


- lpfn

이벤트가 발생할 때 dialog box가 호출하는 Application-defined Function의 주소.
더 많은 정보는 BrowseCallbackProc(참조3)를 참고하자. 이 멤버 변수는 Null값을
가질 수 있다.

- lParam

Dialog Box는 callback function 패스하는 Application-defined value이다.
(if one is specified).

- iImage

지정된 폴더와 연관도니 이미지를 받는 변수. 이미지는 시스템 이미지 리스트의
인덱스로서 정의된다.

=================================================
여기서부터는 배경환이 덧붙여 쓴 글 입니다.
-----------------------------------------
참조 1

SHBrowseForFolder

[이제는 Windows NT에서도 지원한다.]

사용자가 shell 폴더를 선택하도록 Dialog box를 디스플레이한다.

WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(

LPBROWSEINFO lpbi
);


Parameters

- lpbi

Dialog box를 보여주는데 사용된 정보를 포함하는 BROWSEINFO 구조체의 포인터.

Return Values

name space의 root와 연관된 선택된 폴더의 location을 지정하는 item 식별자
리스트에 대한 포인터를 리턴. 만약 사용자가 Dialog box에서 Cancel 버튼을
클릭한다면, 리턴 값은 Null이 된다.
호출하는 어플리케이션은 shell의 태스크 allocator를 사용해서 리턴된 Item 식별자
리스트를 제거하는 데에 응답한다.


--------------------------------------
참조 2

ITEMIDLIST

Item 식별자들의 리스트를 포함한다.

typedef struct _ITEMIDLIST { // idl
SHITEMID mkid; // list of item identifers
} ITEMIDLIST, * LPITEMIDLIST;
typedef const ITEMIDLIST * LPCITEMIDLIST;


-------------------------------------
참조 3

BrowseCallbackProc

[이제는 Windows NT에서도 지원한다.]

SHBrowseForFolder 함수와 함께 사용된 application-defined callback function을
지정한다. Browse Dialog box는 이벤트에 이를 알려주는 함수를 호출한다.
BFFCALLBACK type은 callback 함수에 대한 포인터를 정의한다.

int BrowseCallbackProc(

HWND hwnd,
UINT uMsg,
LPARAM lParam,
LPARAM lpData
);


Parameters

- hwnd

Browse Dialog box의 Handle. callback function은 윈도우에서 다음과 같은
메세지를 전송할 수 있다.

BFFM_ENABLEOK Enables the OK button if the wParam parameter is nonzero or
disables it if wParam is zero.

BFFM_SETSELECTION Selects the specified folder. The lParam parameter is
the PIDL of the folder to select if wParam is FALSE, or it is the path
of the folder otherwise.

BFFM_SETSTATUSTEXT Sets the status text to the null-terminated string
specified by the lParam parameter.

- uMsg

이벤트를 식별하는 값. 이 파라메터는 다음 값들중 하나이다.

BFFM_INITIALIZED The browse dialog box has finished initializing.
lpData is NULL.

BFFM_SELCHANGED The selection has changed. lpData is a pointer to the item
identifier list for the newly selected folder.

- lParam

Message-specific value. uMsg를 참고하라..

- lpData

BROWSEINFO 구조체의 lParam 멤버 변수에서 지정된 Application-defined value.


Return Values

zero를 리턴한다.
-------------------------------

또, 위의 browse folder는 델파이에서 selectdirectory라는 메소드로 지원하고
있습니다. 이를 사용하면 위의 기능을 100%는 아니겠지만... 편하게 사용할 수
있습니다.

Comment

선택

늘리기 줄이기


[1] [2]