기본 폴더 개체 인터페이스 구현

네임스페이스 확장을 구현하는 절차는 다른 COM(In-process Component Object Model) 개체의 경우와 비슷합니다. 모든 확장은 트리 보기에 확장의 폴더를 표시하는 데 필요한 기본 정보를 Windows 탐색기에 제공하는 세 가지 기본 인터페이스를 지원해야 합니다. 그러나 Windows 탐색기의 기능을 최대한 활용하려면 확장에서 바로 가기 메뉴 또는 끌어서 놓기와 같은 보다 정교한 기능을 지원하는 하나 이상의 선택적 인터페이스를 노출하고 폴더 보기를 제공해야 합니다.

이 문서에서는 Windows 탐색기에서 확장 내용에 대한 정보를 요구하는 기본 및 선택적 인터페이스를 구현하는 방법을 설명합니다. 폴더 보기를 구현하는 방법 및 Windows 탐색기를 사용자 지정하는 방법에 대한 자세한 내용은 폴더 보기 구현을 참조 하세요.

기본 구현 및 등록

In-process COM 서버인 DLL은 다음과 같은 몇 가지 표준 함수 및 인터페이스를 노출해야 합니다.

이러한 함수 및 인터페이스는 대부분의 다른 COM 개체와 동일한 방식으로 구현됩니다. 자세한 내용은 COM 설명서를 참조 하세요.

확장 등록

모든 COM 개체와 마찬가지로 확장에 대한 CLSID(클래스 식별자) GUID를 만들어야 합니다. 확장의 CLSID에 이름이 지정된 HKEY_CLASSES_ROOT\CLSID하위 키를 만들어 개체를 등록합니다. DLL은 In-process 서버로 등록되어야 하며 아파트 스레딩 모델을 지정해야 합니다. 확장의 CLSID 키에 다양한 하위 키와 값을 추가하여 확장의 루트 폴더 동작을 사용자 지정할 수 있습니다.

이러한 값 중 일부는 가상 접합점이 있는 확장에만 적용됩니다. 이러한 값은 연결점이 파일 시스템 폴더인 확장에 적용되지 않습니다. 자세한 내용은 네임스페이스 확장의 위치 지정을 참조 하세요. 가상 접합점을 사용하여 확장의 동작을 수정하려면 확장의 CLSID 키에 다음 값 중 하나 이상을 추가합니다.

  • 원스포파싱. 가상 접합점이 있는 확장의 구문 분석 이름은 일반적으로 다음과 같은 형식:{GUID}입니다. 이 형식의 확장에는 일반적으로 가상 항목이 포함됩니다. 그러나 내 문서와 같은 일부 확장은 가상 접합 지점이 있더라도 파일 시스템 폴더에 실제로 해당합니다. 확장이 이러한 방식으로 파일 시스템 개체를 나타내는 경우 WantsFORPARSING 값을 설정할 수 있습니다. 그런 다음 Windows 탐색기는 uFlags가 SHGDN_FORPARSING 설정되고 pidl이 PIDL(항목 식별자 목록)에 대한 단일 빈 포인터로 설정된 폴더 개체의 IShellFolder::GetDisplayNameOf 메서드를 호출하여 루트 폴더의 구문 분석 이름을 요청합니다. 빈 PIDL에는 종결자만 포함됩니다. 그러면 메서드가 루트 폴더의 ::{GUID} 구문 분석 이름을 반환해야 합니다.
  • HideFolderVerbs. HKEY_CLASSES_ROOT\폴더등록된 동사는 일반적으로 모든 확장과 연결됩니다. 확장의 바로 가기 메뉴에 표시되며 ShellExecute에서 호출할 수 있습니다. 이러한 동사가 확장과 연결되지 않도록 하려면 HideFolderVerbs 값을 설정합니다.
  • HideAsDelete. 사용자가 확장을 삭제하려고 하면 Windows 탐색기에서 확장을 숨깁니다.
  • HideAsDeletePerUser. 이 값은 HideAsDelete와 동일하지만 사용자 단위로 적용됩니다. 확장을 삭제하려고 시도한 사용자에 대해서만 확장이 숨겨집니다. 확장은 다른 모든 사용자에게 표시됩니다.
  • QueryForOverlay. 이 값을 설정하여 루트 폴더의 아이콘에 아이콘 오버레이가 있을 수 있음을 나타냅니다. 폴더 개체는 IShellIconOverlay 인터페이스를 지원해야 합니다. Windows 탐색기에서 루트 폴더의 아이콘을 표시하기 전에 pidlItem이 빈 PIDL로 설정된 두 IShellIconOverlay 메서드 중 하나를 호출하여 오버레이 아이콘을 요청합니다.

나머지 값과 하위 키는 모든 확장에 적용됩니다.

  • 확장의 접합점 폴더의 표시 이름을 지정하려면 확장의 CLSID 하위 키의 기본값을 적절한 문자열로 설정합니다.
  • 커서가 폴더 위로 마우스를 가져가면 일반적으로 폴더의 내용을 설명하는 정보 설명이 표시됩니다. 확장의 루트 폴더에 대한 정보 설명을 제공하려면 확장의 CLSID 키에 대한 InfoTip REG_SZ 값을 만들고 적절한 문자열로 설정합니다.
  • 확장의 루트 폴더에 대한 사용자 지정 아이콘을 지정하려면 DefaultIcon이라는 확장의 CLSID 하위 키 하위 키를 만듭니다. DefaultIcon 기본값을 아이콘이 포함된 파일의 이름, 쉼표, 빼기 기호, 해당 파일의 아이콘 인덱스가 포함된 REG_SZ 값으로 설정합니다.
  • 기본적으로 확장 루트 폴더의 바로 가기 메뉴에는 HKEY_CLASSES_ROOT\Folder 아래에 정의된 항목이 포함됩니다. 적절한 SFGAO_XXX 플래그를 설정한 경우 Delete, RenameProperties 항목이 추가됩니다. 파일 형식과 마찬가지로 루트 폴더의 바로 가기 메뉴에 다른 항목을 추가하거나 기존 항목을 재정의할 수 있습니다. 확장의 CLSID 키 아래에 셸 하위 키를 만들고 바로 가기 메뉴 확장에 설명된 대로 명령을 정의합니다.
  • 루트 폴더의 바로 가기 메뉴를 처리하는 보다 유연한 방법이 필요한 경우 바로 가기 메뉴 처리기를 구현할 수 있습니다. 바로 가기 메뉴 처리기를 등록하려면 확장의 CLSID 키 아래에 ShellEx 키를 만듭니다. 기존의 셸 확장 처리기 만들기와 마찬가지로 처리기의 CLSID를 등록합니다.
  • 루트 폴더의 속성 시트에 페이지를 추가하려면 폴더 에 SFGAO_HASPROPSHEET 특성을 제공하고 속성 시트 처리기를 구현 합니다. 속성 시트 처리기를 등록하려면 확장의 CLSID 키 아래에 ShellEx 키를 만듭니다. 기존의 셸 확장 처리기 만들기와 마찬가지로 처리기의 CLSID를 등록합니다.
  • 루트 폴더의 특성을 지정하려면 확장의 CLSID 하위 키에 ShellFolder 하위 키를 추가합니다. 특성 값을 만들고 SFGAO_XXX 플래그의 적절한 조합으로 설정합니다.

다음 표에서는 루트 폴더에 일반적으로 사용되는 몇 가지 특성을 나열합니다.

플래그 설명
SFGAO_FOLDER 0x20000000 확장의 루트 폴더에는 하나 이상의 항목이 포함되어 있습니다.
SFGAO_HASSUBFOLDER 0x80000000 확장의 루트 폴더에는 하나 이상의 하위 폴더가 포함되어 있습니다. Windows 탐색기는 폴더 아이콘 옆에 더하기 기호(+)를 배치합니다.
SFGAO_CANDELETE 0x00000020 사용자가 확장의 루트 폴더를 삭제할 수 있습니다. 폴더의 바로 가기 메뉴에는 삭제 항목이 있습니다. 이 플래그는 가상 폴더 중 하나에 배치되는 접합점에 대해 설정해야 합니다.
SFGAO_CANRENAME 0x00000010 사용자가 확장의 루트 폴더 이름을 바꿀 수 있습니다. 폴더의 바로 가기 메뉴에는 이름 바꾸기 항목이 있습니다.
SFGAO_HASPROPSHEET 0x00000040 확장의 루트 폴더에는 속성 속성 시트가 있습니다. 폴더의 바로 가기 메뉴에는 속성 항목이 있습니다. 속성 시트를 제공하려면 속성 시트 처리기를 구현해야 합니다. 앞에서 설명한 대로 확장의 CLSID 키 아래에 처리기를 등록합니다.

 

다음 예제에서는 MyExtension의 표시 이름을 가진 확장에 대한 CLSID 레지스트리 항목을 보여 줍니다. 확장에는 인덱스가 1인 확장의 DLL에 포함된 사용자 지정 아이콘이 있습니다. SFGAO_FOLDER, SFGAO_HASSUBFOLDERSFGAO_CANDELETE 특성이 설정됩니다.

HKEY_CLASSES_ROOT
   CLSID
      {Extension CLSID}
         (Default) = MyExtension
         InfoTip = Some appropriate text
      DefaultIcon
         (Default) = c:\MyDir\MyExtension.dll,-1
      InProcServer32
         (Default) = c:\MyDir\MyExtension.dll
         ThreadingModel = Apartment
      ShellFolder
         Attributes = 0xA00000020

PIDL 처리

셸 네임스페이스의 모든 항목에는 고유한 PIDL이 있어야 합니다. Windows 탐색기는 PIDL을 루트 폴더에 할당하고 초기화 중에 확장에 값을 전달합니다. 그러면 확장은 각 개체에 올바르게 생성된 PIDL을 할당하고 요청 시 Windows 탐색기에 해당 PIDL을 제공하는 역할을 담당합니다. Shell에서 PIDL을 사용하여 확장의 개체 중 하나를 식별하는 경우 확장은 PIDL을 해석하고 특정 개체를 식별할 수 있어야 합니다. 또한 확장은 각 개체에 표시 이름과 구문 분석 이름을 할당해야 합니다. PIDL은 거의 모든 폴더 인터페이스에서 사용되므로 확장은 일반적으로 이러한 모든 작업을 처리하기 위해 단일 PIDL 관리자 를 구현합니다.

PIDL이라는 용어는 컨텍스트에 따라 ITEMIDLIST 구조체 또는 이러한 구조체에 대한 포인터에 대해 짧습니다. 선언된 대로 ITEMIDLIST 구조체에는 단일 멤버인 SHITEMID 구조체가 있습니다. 개체의 ITEMIDLIST 구조체는 실제로 둘 이상의 SHITEMID 구조체로 구성된 배열입니다. 이러한 구조체의 순서는 c:\MyDirectory\MyFile이 파일 시스템을 통해 경로를 정의하는 것과 거의 동일한 방식으로 네임스페이스를 통과하는 경로를 정의합니다. 일반적으로 개체의 PIDL은 네임스페이스 경로를 정의하는 폴더에 해당하는 일련의 SHITEMID 구조체와 개체의 SHITEMID 구조, 종결자로 구성됩니다.

종결자는 CB 멤버가 NULL설정된 SHITEMID 구조체입니다. 종결자는 개체의 PIDL에 있는 SHITEMID 구조체의 수가 셸 네임스페이스에 있는 개체의 위치와 경로의 시작점에 따라 달라지므로 필요합니다. 또한 다양한 SHITEMID 구조체의 크기는 다를 수 있습니다. PIDL을 받으면 크기 또는 총 SHITEMID 구조체 수를 확인하는 간단한 방법이 없습니다. 대신 종결자에 도달할 때까지 압축된 배열을 구조별로 "걸어야" 합니다.

PIDL을 만들려면 애플리케이션에서 다음을 수행해야 합니다.

  1. 각 개체에 대한 SHITEMID 구조를 만듭니다.
  2. 관련 SHITEMID 구조를 PIDL로 어셈블합니다.

SHITEMID 구조체 만들기

개체의 SHITEMID 구조체는 해당 폴더 내의 개체를 고유하게 식별합니다. 실제로 많은 IShellFolder 메서드에서 사용하는 PIDL 형식은 개체의 SHITEMID 구조와 종결자만으로 구성됩니다. SHITEMID 구조체의 정의는 다음과 같습니다.

typedef struct _SHITEMID { 
    USHORT cb; 
    BYTE   abID[1]; 
} SHITEMID, * LPSHITEMID;

abID 멤버는 개체의 식별자입니다. abID의 길이가 정의되지 않고 다를 수 있으므로 cb 멤버는 SHITEMID 구조체의 크기(바이트)로 설정됩니다.

abID의 길이나 콘텐츠가 표준화되지 않으므로 abID 값을 개체에 할당하려는 모든 체계를 사용할 수 있습니다. 유일한 요구 사항은 동일한 값을 가진 동일한 폴더에 두 개의 개체를 가질 수 없다는 것입니다. 그러나 성능상의 이유로 SHITEMID 구조체는 DWORD로 정렬되어야 합니다. 즉, cb4의 정수 배수가 되도록 abID 값을 생성해야 합니다.

일반적으로 abID확장 정의 구조를 가리킵니다. 개체의 ID 외에도 이 구조체는 개체의 형식이나 특성과 같은 다양한 관련 정보를 보유하는 데 자주 사용됩니다. 확장의 폴더 개체는 쿼리하지 않고 PIDL에서 정보를 빠르게 추출할 수 있습니다.

참고 항목

PIDL에 대한 데이터 구조를 디자인하는 가장 중요한 측면 중 하나는 구조를 지속 가능하고 전송 가능하게 만드는 것입니다. PIDL의 컨텍스트에서 이러한 용어의 의미는 다음과 같습니다.

  • 지속 가능. 시스템은 자주 바로 가기 파일과 같은 다양한 유형의 장기 스토리지에 PIDL을 배치합니다. 그런 다음 나중에 시스템을 다시 부팅한 후 스토리지에서 이러한 PIDL을 복구할 수 있습니다. 스토리지에서 복구된 PIDL은 확장에 여전히 유효하고 의미가 있어야 합니다. 예를 들어 이 요구 사항은 PIDL 구조에서 포인터 또는 핸들을 사용하면 안 된다는 것을 의미합니다. 이러한 유형의 데이터를 포함하는 PIDL은 일반적으로 시스템에서 나중에 스토리지에서 복구할 때 의미가 없습니다.
  • 처. 한 컴퓨터에서 다른 컴퓨터로 전송할 때 PIDL은 의미 있는 상태를 유지해야 합니다. 예를 들어 PIDL을 바로 가기 파일에 쓰고 플로피 디스크에 복사한 다음 다른 컴퓨터로 전송할 수 있습니다. 해당 PIDL은 두 번째 컴퓨터에서 실행되는 확장에 여전히 의미가 있어야 합니다. 예를 들어 PIDL을 전송할 수 있도록 하려면 ANSI 또는 유니코드 문자를 명시적으로 사용합니다. TCHAR 또는 LPTSTR과 같은 데이터 형식을 사용하지 마세요. 이러한 데이터 형식을 사용하는 경우 확장의 유니코드 버전을 실행하는 컴퓨터에서 만든 PIDL은 다른 컴퓨터에서 실행되는 해당 확장의 ANSI 버전에서 읽을 수 없습니다.

 

다음 선언에서는 데이터 구조의 간단한 예제를 보여 있습니다.

typedef struct tagMYPIDLDATA {
  USHORT cb;
  DWORD dwType;
  WCHAR wszDisplayName[40];
} MYPIDLDATA, *LPMYPIDLDATA;

cb 멤버는 MYPIDLDATA 구조체의 크기로 설정됩니다. 이 멤버는 MYPIDLDATA를 그 자체로 유효한 SHITEMID 구조체로 만듭니다. 나머지 멤버는 SHITEMID 구조체의 abID 멤버와 동일하며 프라이빗 데이터를 보유합니다. dwType 멤버는 개체의 형식을 나타내는 확장 정의 값입니다. 이 예제에서는 dwType이 폴더에 대해 TRUE설정되고 그렇지 않으면 FALSE로 설정됩니다. 예를 들어 이 멤버를 사용하면 개체가 폴더인지 여부를 빠르게 확인할 수 있습니다. wszDisplayName 멤버는 개체의 표시 이름을 포함합니다. 동일한 폴더에 있는 두 개의 서로 다른 개체에 동일한 표시 이름을 할당하지 않으므로 표시 이름도 개체 ID로 사용됩니다. 이 예제에서 wszDisplayName은 SHITEMID 구조체가 DWORD 정렬되도록 40자로 설정됩니다. PIDL의 크기를 제한하려면 대신 가변 길이 문자 배열을 사용하고 그에 따라 cb 값을 조정할 수 있습니다. 구조체의 DWORD 맞춤을 유지하기에 충분한 '\0' 문자로 표시 문자열을 패딩합니다. 구조체에 배치하는 데 유용할 수 있는 다른 멤버에는 개체의 크기, 특성 또는 구문 분석 이름이 포함됩니다.

PIDL 생성

개체에 대한 SHITEMID 구조를 정의한 후에는 이를 사용하여 PIDL을 생성할 수 있습니다. PIDL은 다양한 용도로 생성할 수 있지만 대부분의 작업은 두 가지 유형의 PIDL 중 하나를 사용합니다. 가장 간단한 단일 수준 PIDL은 부모 폴더를 기준으로 개체를 식별합니다. 이 유형의 PIDL은 많은 IShellFolder 메서드에서 사용됩니다. 단일 수준 PIDL에는 개체의 SHITEMID 구조와 종결자가 포함됩니다. 정규화된 PIDL은 바탕 화면에서 개체로 네임스페이스 계층을 통과하는 경로를 정의합니다. 이 유형의 PIDL은 바탕 화면에서 시작되며 경로의 각 폴더에 대해 하나의 SHITEMID 구조와 개체 및 종결자를 포함합니다. 정규화된 PIDL은 전체 셸 네임스페이스 내에서 개체를 고유하게 식별합니다.

PIDL을 생성하는 가장 간단한 방법은 ITEMIDLIST 구조 자체를 직접 사용하는 것입니다. ITEMIDLIST 구조를 만들지만 모든 SHITEMID 구조를 저장할 수 있는 충분한 메모리를 할당합니다. 이 구조체의 주소는 초기 SHITEMID 구조를 가리킵니다. 이 초기 구조체의 멤버에 대한 값을 정의한 다음 필요한 만큼 추가 SHITEMID 구조를 적절한 순서로 추가합니다. 다음 절차에서는 단일 수준 PIDL을 만드는 방법을 간략하게 설명합니다. 여기에는 두 개의 SHITEMID 구조체, 즉 MYPIDLDATA 구조와 종결자가 있습니다.

  1. CoTaskMemAlloc 함수를 사용하여 PIDL에 대한 메모리를 할당합니다. 프라이빗 데이터에 충분한 메모리를 할당하고 종결자에 USHORT (2바이트)를 할당합니다. 결과를 LPMYPIDLDATA로 캐스팅합니다.
  2. 첫 번째 MYPIDLDATA 구조체의 cb 멤버를 해당 구조체의 크기로 설정합니다. 이 예제에서는 cb를 sizeof(MYPIDLDATA)로 설정합니다. 가변 길이 구조를 사용하려면 cb 값을 계산해야 합니다.
  3. 프라이빗 데이터 멤버에 적절한 값을 할당합니다.
  4. 다음 SHITEMID 구조체의 주소를 계산합니다. 현재 MYPIDLDATA 구조체의 주소를 LPBYTE로 캐스팅하고 3단계에서 결정된 cb 값에 해당 값을 추가합니다.
  5. 이 경우 다음 SHITEMID 구조체는 종결자입니다. 구조체의 cb 멤버를 0으로 설정합니다.

더 긴 PIDL의 경우 충분한 메모리를 할당하고 각 추가 SHITEMID 구조에 대해 3-5단계를 반복합니다.

다음 샘플 함수는 개체의 형식 및 표시 이름을 사용하고 개체의 단일 수준 PIDL을 반환합니다. 함수는 종료 null 문자를 포함하여 표시 이름이 MYPIDLDATA 구조에 대해 선언된 문자 수를 초과하지 않는다고 가정합니다. 해당 가정이 잘못된 것으로 판명되면 StringCbCopyW 함수는 표시 이름을 자른다. g_pMalloc 변수는 다른 곳에서 만들어지고 전역 변수에 저장된 IMalloc 포인터입니다.

LPITEMIDLIST CreatePIDL(DWORD dwType, LPCWSTR pwszDisplayName)
{
    LPMYPIDLDATA   pidlOut;
    USHORT         uSize;

    pidlOut = NULL;

    //Calculate the size of the MYPIDLDATA structure.
    uSize = sizeof(MYPIDLDATA);

    // Allocate enough memory for the PIDL to hold a MYPIDLDATA structure 
    // plus the terminator
    pidlOut = (LPMYPIDLDATA)m_pMalloc->Alloc(uSize + sizeof(USHORT));

    if(pidlOut)
    {
       //Assign values to the members of the MYPIDLDATA structure
       //that is the PIDL's first SHITEMID structure
       pidlOut->cb = uSize;
       pidlOut->dwType = dwType;
       hr = StringCbCopyW(pidlOut->wszDisplayName, 
                          sizeof(pidlOut->wszDisplayName), pwszDisplayName);
       
       // TODO: Add error handling here to verify the HRESULT returned 
       // by StringCbCopyW.

       //Advance the pointer to the start of the next SHITEMID structure.
       pidlOut = (LPMYPIDLDATA)((LPBYTE)pidlOut + pidlOut->cb);

       //Create the terminating null character by setting cb to 0.
       pidlOut->cb = 0;
    }

    return pidlOut;

정규화된 PIDL에는 데스크톱에서 개체에 이르는 모든 개체에 대한 SHITEMID 구조체가 있어야 합니다. 확장은 셸에서 IPersistFolder::Initialize를 호출할 때 루트 폴더에 대한 정규화된 PIDL을 받습니다. 개체에 대해 정규화된 PIDL을 생성하려면 Shell이 루트 폴더에 할당한 PIDL을 가져와서 루트 폴더에서 개체로 이동시키는 데 필요한 SHITEMID 구조를 추가합니다.

PIDL 해석

Shell 또는 애플리케이션이 확장의 인터페이스 중 하나를 호출하여 개체에 대한 정보를 요청하는 경우 일반적으로 PIDL로 개체를 식별합니다. IShellFolder::GetUIObjectOf와 같은 일부 메서드는 부모 폴더를 기준으로 하며 해석하기 간단한 PIDL을 사용합니다. 그러나 확장은 정규화된 PIDL도 받을 수 있습니다. 그러면 PIDL 관리자가 PIDL이 참조하는 개체를 결정해야 합니다.

개체를 정규화된 PIDL과 연결해야 하는 복잡한 것은 PIDL의 초기 SHITEMID 구조 중 하나 이상이 셸 네임스페이스의 확장 외부에 있는 개체에 속할 수 있다는 점입니다. 이러한 구조체의 abID 멤버의 의미를 해석할 방법이 없습니다. 확장에서 해야 할 일은 루트 폴더에 해당하는 구조체에 도달할 때까지 SHITEMID 구조 목록을 "탐색"하는 것입니다. 그 때부터 SHITEMID 구조체의 정보를 해석하는 방법을 알게 됩니다.

PIDL을 탐색하려면 첫 번째 cb 값을 가져와서 PIDL의 주소에 추가하여 포인터를 다음 SHITEMID 구조의 시작으로 진행합니다. 그런 다음, 포인터를 다음 SHITEMID 구조의 시작으로 진행하는 데 사용할 수 있는 해당 구조체의 cb 멤버를 가리킵니다. 포인터를 진행할 때마다 SHITEMID 구조를 검사하여 확장 네임스페이스의 루트에 도달했는지 확인합니다.

기본 인터페이스 구현

모든 COM 개체와 마찬가지로 확장 구현은 주로 인터페이스 컬렉션을 구현하는 문제입니다. 이 섹션에서는 모든 확장에서 구현해야 하는 세 가지 기본 인터페이스에 대해 설명합니다. 초기화 및 확장 내용에 대 한 기본 정보를 Windows 탐색기를 제공 하는 데 사용 됩니다. 이러한 인터페이스와 폴더 뷰는 모두 기능 확장에 필요합니다. 그러나 Windows 탐색기의 기능을 완전히 활용하기 위해 대부분의 확장은 하나 이상의 선택적 인터페이스를 구현합니다.

IPersistFolder 인터페이스

IPersistFolder 인터페이스는 새 폴더 개체를 초기화하기 위해 호출됩니다. IPersistFolder::Initialize 메서드는 정규화된 PIDL을 새 개체에 할당합니다. 나중에 사용할 수 있는 이 PIDL을 저장합니다. 예를 들어 폴더 개체는 이 PIDL을 사용하여 개체의 자식에 대해 정규화된 PIDL을 생성해야 합니다. 폴더 개체의 작성자는 IPersist::GetClassID를 호출하여 개체의 CLSID를 요청할 수도 있습니다.

일반적으로 폴더 개체는 부모 폴더의 IShellFolder::BindToObject 메서드에 의해 만들어지고 초기화됩니다. 그러나 사용자가 확장을 탐색할 때 Windows 탐색기는 확장의 루트 폴더 개체를 만들고 초기화합니다. 루트 폴더 개체가 IPersistFolder::Initialize를 통해 수신하는 PIDL에는 확장에 대해 정규화된 PIDL을 생성하는 데 필요한 데스크톱에서 루트 폴더로의 경로가 포함됩니다.

IShellFolder 인터페이스

셸은 확장을 계층적으로 정렬된 폴더 개체 컬렉션으로 처리합니다. IShellFolder 인터페이스는 모든 확장 구현의 핵심입니다. 폴더 개체를 나타내며 폴더의 내용을 표시하는 데 필요한 많은 정보를 Windows 탐색기에 제공합니다.

IShellFolder는 일반적으로 폴더 개체에 의해 직접 노출되는 IPersistFolder 이외의 유일한 폴더 인터페이스입니다. Windows 탐색기는 폴더의 내용에 대한 정보를 얻기 위해 다양한 필수 및 선택적 인터페이스를 사용하지만 IShellFolder를 통해 해당 인터페이스에 대한 포인터를 가져옵니다.

Windows 탐색기는 다양한 방법으로 확장 루트 폴더의 CLSID를 가져옵니다. 자세한 내용은 네임스페이스 확장의 위치 지정 또는 네임스페이스 확장의 자체 포함 보기 표시를 참조하세요. 그런 다음 Windows 탐색기는 해당 CLSID를 사용하여 루트 폴더의 인스턴스를 만들고 초기화하고 IShellFolder 인터페이스에 대한 쿼리를 만듭니다. 확장은 루트 폴더를 나타내는 폴더 개체를 만들고 개체의 IShellFolder 인터페이스를 반환합니다. 확장과 Windows 탐색기 간의 나머지 상호 작용의 대부분은 IShellFolder를 통해 수행됩니다. Windows 탐색기는 IShellFolder를 호출하여 다음을 수행합니다.

  • 루트 폴더의 내용을 열거할 수 있는 개체를 요청합니다.
  • 루트 폴더의 내용에 대한 다양한 유형의 정보를 가져옵니다.
  • 선택적 인터페이스 중 하나를 노출하는 개체를 요청합니다. 그런 다음 이러한 인터페이스를 쿼리하여 아이콘 또는 바로 가기 메뉴와 같은 추가 정보를 쿼리할 수 있습니다.
  • 루트 폴더의 하위 폴더를 나타내는 폴더 개체를 요청합니다.

사용자가 루트 폴더의 하위 폴더를 열면 Windows 탐색기에서 IShellFolder::BindToObject를 호출 합니다. 확장은 하위 폴더를 나타내는 새 폴더 개체를 만들고 초기화하고 해당 IShellFolder 인터페이스를 반환합니다. 그런 다음 Windows 탐색기는 사용자가 셸 네임스페이스의 다른 곳으로 이동하거나 Windows 탐색기를 닫기로 결정할 때까지 다양한 유형의 정보에 대해 이 인터페이스를 호출합니다.

이 섹션의 나머지 부분에서는 더 중요한 IShellFolder 메서드와 구현 방법에 대해 간략하게 설명합니다.

EnumObjects

트리 뷰에 폴더의 내용을 표시하기 전에 먼저 Windows 탐색기는 IShellFolder::EnumObjects 메서드를 호출하여 폴더에 포함된 내용을 결정해야 합니다. 이 메서드는 IEnumIDList 인터페이스를 노출하고 해당 인터페이스 포인터를 반환하는 표준 OLE 열거형 개체를 만듭니다. IEnumIDList 인터페이스를 사용하면 Windows 탐색기에서 폴더에 포함된 모든 개체의 PIDL을 가져올 수 있습니다. 그런 다음 이러한 PIDL을 사용하여 폴더에 포함된 개체에 대한 정보를 가져옵니다. 자세한 내용은 IEnumIDList 인터페이스를 참조 하세요.

참고 항목

IEnumIDList::Next 메서드는 부모 폴더를 기준으로 하는 PIDL만 반환해야 합니다. PIDL에는 개체의 SHITEMID 구조와 종결자만 포함되어야 합니다.

 

CreateViewObject

폴더의 내용이 표시되기 전에 Windows 탐색기는 이 메서드를 호출하여 IShellView 인터페이스에 대한 포인터를 요청합니다. 이 인터페이스는 Windows 탐색기에서 폴더 보기를 관리하는 데 사용됩니다. 폴더 뷰 개체를 만들고 해당 IShellView 인터페이스를 반환합니다.

IShellFolder::CreateViewObject 메서드는 폴더 자체에 대해 IContextMenu와 같은 선택적 인터페이스 중 하나를 요청하기 위해 호출됩니다. 이 메서드의 구현은 요청된 인터페이스를 노출하고 인터페이스 포인터를 반환하는 개체를 만들어야 합니다. Windows 탐색기에 폴더에 포함된 개체 중 하나에 대한 선택적 인터페이스가 필요한 경우 IShellFolder::GetUIObjectOf를 호출합니다.

GetUIObjectOf

폴더 내용에 대한 기본 정보는 IShellFolder 메서드를 통해 사용할 수 있지만 확장은 Windows 탐색기에 다양한 종류의 추가 정보를 제공할 수도 있습니다. 예를 들어 폴더의 내용이나 개체의 바로 가기 메뉴에 대한 아이콘을 지정할 수 있습니다. Windows 탐색기는 IShellFolder::GetUIObjectOf 메서드를 호출하여 폴더에 포함된 개체에 대한 추가 정보를 검색하려고 시도합니다. Windows 탐색기는 정보를 원하는 개체와 관련 인터페이스의 IID를 지정합니다. 그런 다음, 폴더 개체는 요청된 인터페이스를 노출하고 인터페이스 포인터를 반환하는 개체를 만듭니다.

확장에서 끌어서 놓기 또는 클립보드를 사용하여 개체를 전송할 수 있는 경우 Windows 탐색기는 IShellFolder::GetUIObjectOf를 호출하여 IDataObject 또는 IDropTarget 인터페이스를 요청합니다. 자세한 내용은 끌어서 놓기 및 클립보드를 사용하여 셸 개체 전송을 참조 하세요.

Windows 탐색기는 폴더 자체에 대해 동일한 종류의 정보를 원할 때 IShellFolder::CreateViewObject를 호출합니다.

BindToObject

Windows 탐색기는 사용자가 확장의 하위 폴더 중 하나를 열려고 할 때 IShellFolder::BindToObject 메서드를 호출합니다. riid가 IID_IShellFolder 설정된 경우 하위 폴더를 나타내는 폴더 개체를 만들고 초기화하고 개체의 IShellFolder 인터페이스를 반환해야 합니다.

참고 항목

현재 Windows 탐색기는 이 메서드를 호출하여 IShellFolder 인터페이스를 요청합니다. 그러나 항상 그렇지 않다고 가정하지는 않습니다. 계속하기 전에 항상 riid 값을 확인해야 합니다.

 

GetDisplayNameOf

Windows 탐색기는 IShellFolder::GetDisplayNameOf 메서드를 호출하여 폴더 개체 중 하나의 PIDL을 이름으로 변환합니다. 해당 PIDL은 개체의 부모 폴더를 기준으로 해야 합니다. 즉, NULL이 아닌 단일 SHITEMID 구조를 포함해야 합니다. 개체의 이름을 지정할 수 있는 방법이 두 개 이상 있으므로 Windows 탐색기는 uFlags 매개 변수에서 하나 이상의 SHGDNF 플래그를 설정하여 이름 형식을 지정합니다. SHGDN_NORMAL 또는 SHGDN_INFOLDER 두 값 중 하나는 이름이 폴더를 기준으로 할지 아니면 바탕 화면을 기준으로 해야 하는지를 지정하도록 설정됩니다. SHGDN_FOREDITING, SHGDN_FORADDRESSBAR 또는 SHGDN_FORPARSING 다른 세 값 중 하나를 설정하여 이름을 사용할 대상을 지정할 수 있습니다.

STRRET 구조체의 형태로 이름을 반환해야 합니다. SHGDN_FOREDITING, SHGDN_FORADDRESSBARSHGDN_FORPARSING 설정되지 않은 경우 개체의 표시 이름을 반환합니다. SHGDN_FORPARSING 플래그가 설정되면 Windows 탐색기에서 구문 분석 이름을 요청합니다. 구문 분석 이름은 IShellFolder::P arseDisplayName에 전달되어 네임스페이스 계층의 현재 폴더 아래에 있는 하나 이상의 수준에 있을 수 있지만 개체의 PIDL을 가져옵니다. 예를 들어 파일 시스템 개체의 구문 분석 이름은 해당 경로입니다. 파일 시스템의 모든 개체의 정규화된 경로를 데스크톱의 IShellFolder::P arseDisplayName 메서드에 전달할 수 있으며 개체의 정규화된 PIDL을 반환합니다.

구문 분석 이름은 텍스트 문자열이지만 표시 이름을 반드시 포함할 필요는 없습니다. IShellFolder::P arseDisplayName이 호출될 때 가장 효율적으로 작동하는 항목에 따라 구문 분석 이름을 할당해야 합니다. 예를 들어 대부분의 셸 가상 폴더는 파일 시스템의 일부가 아니며 정규화된 경로가 없습니다. 대신 각 폴더에 GUID가 할당되고 구문 분석 이름은 ::{GUID}형식을 사용합니다. 어떤 체계를 사용하든 안정적으로 "왕복"할 수 있어야 합니다. 예를 들어 호출자가 구문 분석 이름을 IShellFolder::P arseDisplayName에 전달하여 개체의 PIDL을 검색한 다음 해당 PIDL을 SHGDN_FORPARSING 플래그 집합으로 IShellFolder::GetDisplayNameOf에 전달하는 경우 호출자는 원래 구문 분석 이름을 복구해야 합니다.

GetAttributesOf

Windows 탐색기는 IShellFolder::GetAttributesOf 메서드를 호출하여 폴더 개체에 포함된 하나 이상의 항목의 특성을 확인합니다. cidl은 쿼리의 항목 수를 제공하고 aPidl은 해당 PIDL 목록을 가리킵니다.

일부 특성에 대한 테스트는 시간이 오래 걸릴 수 있으므로 Windows 탐색기는 일반적으로 rfgInOut에서 값을 설정하여 쿼리를 사용 가능한 플래그의 하위 집합으로 제한합니다. 메서드는 rfgInOut에서 플래그가 설정된 특성만 테스트해야 합니다. 유효한 플래그를 설정한 상태로 두고 나머지를 지웁니다. 둘 이상의 항목이 쿼리에 포함된 경우 모든 항목에 적용되는 플래그만 설정합니다.

참고 항목

항목이 올바르게 표시되려면 특성을 올바르게 설정해야 합니다. 예를 들어 항목이 하위 폴더를 포함하는 폴더인 경우 SFGAO_HASSUBFOLDER 플래그를 설정해야 합니다. 그렇지 않으면 Windows 탐색기는 트리 보기에서 항목의 아이콘 옆에 +를 표시하지 않습니다.

 

ParseDisplayName

IShellFolder::P arseDisplayName 메서드는 어떤 의미에서 IShellFolder::GetDisplayNameOf미러 이미지입니다. 이 메서드의 가장 일반적인 용도는 개체의 구문 분석 이름을 연결된 PIDL로 변환하는 것입니다. 구문 분석 이름은 네임스페이스 계층 구조의 폴더 아래에 있는 모든 개체를 참조할 수 있습니다. 반환된 PIDL은 메서드를 노출하는 폴더 개체를 기준으로 하며 일반적으로 정규화되지 않습니다. 즉, PIDL에 여러 SHITEMID 구조체가 포함될 수 있지만 첫 번째는 개체 자체 또는 폴더에서 개체로의 경로에 있는 첫 번째 하위 폴더입니다. 호출자는 개체에 대한 정규화된 PIDL을 얻으려면 폴더의 정규화된 PIDL에 이 PIDL을 추가해야 합니다.

IShellFolder::P arseDisplayName 을 호출하여 개체의 특성을 요청할 수도 있습니다. 적용 가능한 모든 특성을 결정하는 데 시간이 오래 걸릴 수 있으므로 호출자는 호출자가 관심 있는 정보를 나타내는 SFGAO_XXX 플래그만 설정합니다. 이러한 특성 중 개체에 대해 true인 특성을 확인하고 나머지 플래그를 지워야 합니다.

IEnumIDList 인터페이스

Windows 탐색기가 폴더에 포함된 개체를 열거해야 하는 경우 IShellFolder::EnumObjects를 호출 합니다. 폴더 개체는 IEnumIDList 인터페이스를 노출하고 해당 인터페이스 포인터를 반환하는 열거형 개체를 만들어야 합니다. 그런 다음 Windows 탐색기는 일반적으로 IEnumIDList를 사용하여 폴더에 포함된 모든 개체의 PIDL을 열거합니다.

IEnumIDList 는 표준 OLE 열거형 인터페이스이며 일반적인 방식으로 구현됩니다. 그러나 반환하는 PIDL은 폴더에 상대적이어야 하며 개체의 SHITEMID 구조와 종결자만 포함해야 합니다.

선택적 인터페이스 구현

확장의 폴더 개체에서 지원할 수 있는 선택적 셸 인터페이스는 여러 가지가 있습니다. IExtractIcon과 같은 많은 기능을 사용하면 사용자가 확장을 보는 방식의 다양한 측면을 사용자 지정할 수 있습니다. IDataObject와 같은 다른 사용자는 확장이 끌어서 놓기와 같은 기능을 지원하도록 허용합니다.

선택적 인터페이스는 폴더 개체에 의해 직접 노출되지 않습니다. 대신 Windows 탐색기는 두 IShellFolder 메서드 중 하나를 호출하여 인터페이스를 요청합니다.

  • Windows 탐색기는 폴더 개체의 IShellFolder::GetUIObjectOf 를 호출하여 폴더에 포함된 개체 중 하나에 대한 인터페이스를 요청합니다.
  • Windows 탐색기는 폴더 개체의 IShellFolder::CreateViewObject 를 호출하여 폴더 자체에 대한 인터페이스를 요청합니다.

정보를 제공하기 위해 폴더 개체는 요청된 인터페이스를 노출하고 인터페이스 포인터를 반환하는 개체를 만듭니다. 그런 다음 Windows 탐색기는 해당 인터페이스를 호출하여 필요한 정보를 검색합니다. 이 섹션에서는 가장 일반적으로 사용되는 선택적 인터페이스에 대해 설명합니다.

IExtractIcon

Windows 탐색기는 폴더의 내용을 표시하기 전에 IExtractIcon 인터페이스를 요청합니다. 인터페이스를 사용하면 확장에서 폴더에 포함된 개체에 대한 사용자 지정 아이콘을 지정할 수 있습니다. 그렇지 않으면 표준 파일 및 폴더 아이콘이 사용됩니다. 사용자 지정 아이콘을 제공하려면 IExtractIcon노출하는 아이콘 추출 개체를 만들고 해당 인터페이스에 대한 포인터를 반환합니다. 자세한 내용은 IExtractIcon 참조 설명서 또는 아이콘 처리기 만들기를 참조하세요.

IContextMenu

사용자가 개체를 마우스 오른쪽 단추로 클릭하면 Windows 탐색기가 IContextMenu 인터페이스를 요청합니다. 개체에 대한 바로 가기 메뉴를 제공하려면 메뉴 처리기 개체를 만들고 해당 IContextMenu 인터페이스를 반환합니다.

메뉴 처리기 개체를 만드는 절차는 메뉴 처리기 셸 확장을 만드는 데 사용되는 절차와 매우 유사합니다. 자세한 내용은 상황에 맞는 메뉴 처리기 또는 IContextMenu, IContextMenu2 또는 IContextMenu3 참조 만들기를 참조하세요.

IQueryInfo

Windows 탐색기는 IQueryInfo 인터페이스를 호출하여 정보 설명 텍스트 문자열을 검색합니다.

IDataObject 및 IDropTarget

Windows 탐색기에서 개체를 표시할 때 폴더 개체는 사용자가 개체를 잘라내거나 복사하거나 끌 때를 직접 알 수 없습니다. 대신 Windows 탐색기는 IDataObject 인터페이스를 요청합니다. 개체를 전송할 수 있도록 하려면 데이터 개체를 만들고 해당 IDataObject 인터페이스에 대한 포인터를 반환합니다.

마찬가지로 사용자는 아이콘 또는 주소 표시줄 경로와 같은 개체 중 하나의 Windows 탐색기 표현에서 데이터 개체를 삭제하려고 할 수 있습니다. 그런 다음 Windows 탐색기는 IDropTarget 인터페이스를 요청합니다. 데이터 개체를 삭제할 수 있도록 하려면 IDropTarget 인터페이스를 노출하는 개체를 만들고 인터페이스 포인터를 반환합니다.

데이터 전송 처리는 네임스페이스 확장 작성의 까다로운 측면 중 하나입니다. 자세한 내용은 끌어서 놓기 및 클립보드를 사용하여 셸 개체 전송을 참조하세요.

기본 셸 폴더 뷰 구현 작업

기본 Shell 폴더 뷰 개체(DefView)를 사용하는 데이터 원본은 다음 인터페이스를 구현해야 합니다.

필요에 따라 IPersistFolder3을 구현할 수도 있습니다.