다음을 통해 공유


셸 데이터 전송 시나리오 처리

Shell 데이터 개체 문서에서는 끌어서 놓기 또는 클립보드를 사용하여 셸 데이터를 전송하는 데 사용되는 일반적인 방법을 설명했습니다. 그러나 애플리케이션에서 Shell 데이터 전송을 구현하려면 이러한 일반적인 원칙과 기술을 Shell 데이터를 전송할 수 있는 다양한 방법에 적용하는 방법도 이해해야 합니다. 이 문서에서는 일반적인 Shell 데이터 전송 시나리오를 제시하고 애플리케이션에서 각 시나리오를 구현하는 방법을 설명합니다.

참고 항목

이러한 각 시나리오는 특정 데이터 전송 작업에 대해 설명하지만 많은 시나리오가 다양한 관련 시나리오에 적용됩니다. 예를 들어 대부분의 클립보드와 끌어서 놓기 전송 간의 주요 차이점은 데이터 개체가 대상에 도착하는 방식입니다. 대상에 데이터 개체의 IDataObject 인터페이스에 대한 포인터가 있으면 정보 추출 절차는 두 유형의 데이터 전송에 대해 거의 동일합니다. 그러나 일부 시나리오는 특정 유형의 작업으로 제한됩니다. 자세한 내용은 개별 시나리오를 참조하세요.

 

일반 지침

다음 각 섹션에서는 매우 구체적인 단일 데이터 전송 시나리오에 대해 설명합니다. 그러나 데이터 전송은 종종 더 복잡하며 여러 시나리오의 측면을 포함할 수 있습니다. 일반적으로 실제로 처리해야 하는 시나리오를 미리 알 수 없습니다. 다음은 염두에 두어야 할 몇 가지 일반적인 지침입니다.

데이터 원본의 경우:

  • CF_HDROP 제외한 셸 클립보드 형식은 미리 정의되지 않습니다. 사용할 각 형식은 RegisterClipboardFormat을 호출하여 등록해야 합니다.
  • 데이터 개체의 형식은 원본에서 기본 설정 순서로 제공됩니다. 데이터 개체를 열거하고 사용할 수 있는 첫 번째 개체를 선택합니다.
  • 지원할 수 있는 만큼의 형식을 포함합니다. 일반적으로 데이터 개체가 삭제될 위치를 알 수 없습니다. 이렇게 하면 데이터 개체에 놓기 대상이 허용할 수 있는 형식이 포함될 확률이 높아집니다.
  • 기존 파일은 CF_HDROP 형식으로 제공되어야 합니다.
  • CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/ 형식으로 파일과 유사한 데이터를 제공합니다. 이 방법을 사용하면 대상이 기본 데이터 스토리지에 대해 아무것도 알 필요 없이 데이터 개체에서 파일을 만들 수 있습니다. 일반적으로 데이터를 IStream 인터페이스로 표시해야 합니다. 이 데이터 전송 메커니즘은 전역 메모리 개체보다 더 유연하며 메모리를 훨씬 적게 사용합니다.
  • 끌기 원본은 셸 항목을 끌 때 CFSTR_SHELLIDLIST 형식을 제공해야 합니다. 항목에 대한 데이터 개체는 IShellFolder::GetUIObjectOf 또는 IShellItem::BindToHandler 메서드를 통해 가져올 수 있습니다. 데이터 원본은 SHCreateDataObject를 사용하여 CFSTR_SHELLIDLIST 형식을 지원하는 표준 데이터 개체 구현을 만들 수 있습니다.
  • 셸 항목 프로그래밍 모델을 사용하여 끌어오려는 항목을 추론하려는 놓기 대상은 SHCreateShellItemArrayFromDataObject를 사용하여 IDataObject를 IShellItemArray변환할 수 있습니다.
  • 표준 피드백 커서를 사용합니다.
  • 왼쪽 및 오른쪽 끌기를 지원합니다.
  • 포함된 개체에서 데이터 개체 자체를 사용합니다. 이 방법을 사용하면 애플리케이션에서 데이터 개체가 제공해야 하는 추가 형식을 검색할 수 있으며 추가 포함 계층을 만들지 않습니다. 예를 들어 서버 A의 포함된 개체는 서버/컨테이너 B에서 끌어서 컨테이너 C에 놓습니다. C는 서버 A의 포함된 개체를 포함하는 서버 B의 포함된 개체가 아닌 서버 A의 포함된 개체를 만들어야 합니다.
  • 셸은 파일을 이동할 때 최적화된 이동 또는 붙여넣기 삭제 작업을 사용할 수 있습니다. 애플리케이션은 이러한 작업을 인식하고 적절하게 응답할 수 있어야 합니다.

데이터 대상의 경우:

  • CF_HDROP 제외한 셸 클립보드 형식은 미리 정의되지 않습니다. 사용할 각 형식은 RegisterClipboardFormat을 호출하여 등록해야 합니다.
  • OLE 삭제 대상을 구현하고 등록합니다. 가능한 경우 Windows 3.1 대상 또는 WM_DROPFILES 메시지를 사용하지 마세요.
  • 데이터 개체에 포함된 형식은 개체의 원본 위치에 따라 달라집니다. 일반적으로 데이터 개체의 원본 위치를 미리 알지 못하므로 특정 형식이 있다고 가정하지 마세요. 데이터 개체는 최상의 형식부터 시작하여 품질 순서로 형식을 열거해야 합니다. 따라서 사용 가능한 최상의 형식을 얻기 위해 애플리케이션은 일반적으로 사용 가능한 형식을 열거하고 지원할 수 있는 열거형의 첫 번째 형식을 사용합니다.
  • 오른쪽 끌기를 지원합니다. 끌어서 놓기 처리기를 만들어 끌기 바로 가기 메뉴를 사용자 지정할 수 있습니다.
  • 애플리케이션에서 기존 파일을 수락하는 경우 CF_HDROP 형식을 처리할 수 있어야 합니다.
  • 일반적으로 파일을 허용하는 애플리케이션은 CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/ 형식도 처리해야 합니다. 파일 시스템의 파일은 CF_HDROP 형식이지만 네임스페이스 확장명 같은 공급자의 파일은 일반적으로 CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/ 사용합니다. Windows CE 폴더, FTP(파일 전송 프로토콜) 폴더, 웹 폴더 및 CAB 폴더를 예로 들 수 있습니다. 원본은 일반적으로 IStream 인터페이스를 구현하여 스토리지의 데이터를 파일로 표시합니다.
  • 셸은 파일을 이동할 때 최적화된 이동 또는 붙여넣기 삭제 작업을 사용할 수 있습니다. 애플리케이션은 이러한 작업을 인식하고 적절하게 응답할 수 있어야 합니다.

클립보드에서 애플리케이션으로 파일 이름 복사

시나리오: 사용자가 Windows 탐색기에서 하나 이상의 파일을 선택하고 클립보드에 복사합니다. 애플리케이션에서 파일 이름을 추출하여 문서에 붙여넣습니다.

예를 들어 사용자가 파일을 잘라내어 애플리케이션에 붙여넣어 HTML 링크를 만들 수 있도록 이 시나리오를 사용할 수 있습니다. 그러면 애플리케이션이 데이터 개체에서 파일 이름을 추출하고 처리하여 앵커 태그를 만들 수 있습니다.

사용자가 Windows 탐색기에서 파일을 선택하고 클립보드에 복사하면 Shell에서 데이터 개체를 만듭니다. 그런 다음 OleSetClipboard를 호출하여 데이터 개체의 IDataObject 인터페이스에 대한 포인터를 클립보드에 배치합니다.

사용자가 애플리케이션의 메뉴 또는 도구 모음에서 붙여 넣기 명령을 선택하는 경우:

  1. OleGetClipboard를 호출하여 데이터 개체의 IDataObject 인터페이스를 검색합니다.
  2. IDataObject::EnumFormatEtc를 호출하여 열거자 개체를 요청합니다.
  3. 열거자 개체의 IEnumFORMATETC 인터페이스를 사용하여 데이터 개체에 포함된 형식을 열거합니다.

참고 항목

이 절차의 마지막 두 단계는 완전성을 위해 포함됩니다. 일반적으로 간단한 파일 전송에는 필요하지 않습니다. 이러한 형식의 데이터 전송에 사용되는 모든 데이터 개체는 개체에 포함된 파일의 이름을 확인하는 데 사용할 수 있는 CF_HDROP 형식을 포함해야 합니다. 그러나 보다 일반적인 데이터 전송의 경우 형식을 열거하고 애플리케이션에서 처리할 수 있는 최상의 형식을 선택해야 합니다.

 

데이터 개체에서 파일 이름 추출

다음 단계는 데이터 개체에서 하나 이상의 파일 이름을 추출하여 애플리케이션에 붙여넣는 것입니다. 데이터 개체에서 파일 이름을 추출하기 위해 이 섹션에서 설명한 절차는 끌어서 놓기 전송에도 동일하게 적용됩니다.

데이터 개체에서 파일 이름을 검색하는 가장 간단한 방법은 CF_HDROP 형식입니다.

  1. IDataObject::GetData를 호출합니다. FORMATETC 구조체의 cfFormat 멤버를 CF_HDROP, tymed 멤버 TYMED_HGLOBAL 설정합니다. dwAspect 멤버는 일반적으로 DVASPECT_CONTENT 설정됩니다. 그러나 파일의 경로가 짧은(8.3) 형식으로 있어야 하는 경우 dwAspect를 DVASPECT_SHORT 설정합니다.

    IDataObject::GetData가 반환되면 STGMEDIUM 구조체의 hGlobal 멤버는 데이터가 포함된 전역 메모리 개체를 가리킵니다.

  2. HDROP 변수를 만들고 STGMEDIUM 구조체의 hGlobal 멤버로 설정합니다. 이제 HDROP 변수는 DROPFILES 구조에 대한 핸들이 된 다음 복사된 파일의 정규화된 파일 경로를 포함하는 이중 null로 끝나는 문자열이 됩니다.

  3. iFile 매개 변수가 0xFFFFFFFF 설정된 DragQueryFile을 호출하여 목록에 있는 파일 경로 수를 확인합니다. 이 함수는 목록의 파일 경로 수를 반환합니다. 이 목록에 있는 파일 경로의 인덱스(0부터 시작하는 인덱스)는 다음 단계에서 특정 경로를 식별하는 데 사용됩니다.

  4. iFile이 파일의 인덱스로 설정된 상태에서 각 파일에 대해 DragQueryFile을 한 번 호출하여 전역 메모리 개체에서 파일 경로를 추출합니다.

  5. 필요에 따라 파일 경로를 처리하고 애플리케이션에 붙여넣습니다.

  6. ReleaseStgMedium을 호출하고 1단계에서 IDataObject::GetData전달한 STGMEDIUM 구조체에 대한 포인터를 전달합니다. 구조를 릴리스한 후에는 2단계에서 만든 HDROP 값이 더 이상 유효하지 않으므로 사용하면 안 됩니다.

삭제된 파일의 내용을 애플리케이션에 복사

시나리오: 사용자가 Windows 탐색기에서 하나 이상의 파일을 끌어 애플리케이션의 창에 놓습니다. 애플리케이션은 파일의 콘텐츠를 추출하여 애플리케이션에 붙여넣습니다.

이 시나리오에서는 끌어서 놓기를 사용하여 Windows 탐색기에서 애플리케이션으로 파일을 전송합니다. 작업 전에 애플리케이션은 다음을 수행해야 합니다.

  1. RegisterClipboardFormat을 호출하여 필요한 셸 클립보드 형식을 등록합니다.
  2. RegisterDragDrop을 호출하여 대상 창 및 애플리케이션의 IDropTarget 인터페이스를 등록합니다.

사용자가 하나 이상의 파일을 선택하고 끌어 작업을 시작한 후 다음을 수행합니다.

  1. Windows 탐색기는 데이터 개체를 만들고 지원되는 형식을 로드합니다.
  2. Windows 탐색기는 DoDragDrop을 호출하여 끌기 루프를 시작합니다.
  3. 끌기 이미지가 대상 창에 도달하면 시스템에서 IDropTarget::D ragEnter를 호출하여 사용자에게 알립니다.
  4. 데이터 개체에 포함된 내용을 확인하려면 데이터 개체의 IDataObject::EnumFormatEtc 메서드를 호출합니다. 메서드에서 반환된 열거자 개체를 사용하여 데이터 개체에 포함된 형식을 열거합니다. 애플리케이션에서 이러한 형식을 허용하지 않으려면 DROPEFFECT_NONE 반환합니다. 이 시나리오에서는 애플리케이션이 파일을 전송하는 데 사용되는 형식(예: CF_HDROP)을 포함하지 않는 데이터 개체를 무시해야 합니다.
  5. 사용자가 데이터를 삭제하면 시스템에서 IDropTarget::D rop을 호출합니다.
  6. IDataObject 인터페이스를 사용하여 파일의 내용을 추출합니다.

데이터 개체에서 Shell 개체의 내용을 추출하는 방법에는 여러 가지가 있습니다. 일반적으로 다음 순서를 사용합니다.

데이터 추출 프로세스가 오래 걸리는 경우 백그라운드 스레드에서 비동기적으로 작업을 수행할 수 있습니다. 그러면 기본 스레드는 불필요한 지연 없이 진행할 수 있습니다. 비동기 데이터 추출을 처리하는 방법에 대한 자세한 내용은 셸 개체를 비동기적으로 끌어서 놓기를 참조 하세요.

CFSTR_FILECONTENTS 형식을 사용하여 파일에서 데이터 추출

CFSTR_FILECONTENTS 형식은 파일의 콘텐츠를 전송하는 매우 유연하고 강력한 방법을 제공합니다. 데이터를 단일 파일로 저장할 필요도 없습니다. 이 형식에 필요한 것은 데이터 개체가 마치 파일인 것처럼 대상에 데이터를 표시하는 것입니다. 예를 들어 실제 데이터는 텍스트 문서의 섹션 또는 데이터베이스에서 추출된 데이터 블록일 수 있습니다. 대상은 데이터를 파일로 처리할 수 있으며 기본 스토리지 메커니즘에 대해 아무것도 알 필요가 없습니다.

이 형식은 특정 스토리지 메커니즘을 가정하지 않으므로 네임스페이스 확장은 일반적으로 CFSTR_FILECONTENTS 사용하여 데이터를 전송합니다. 네임스페이스 확장은 편리한 스토리지 메커니즘을 사용할 수 있으며, 이 형식을 사용하여 파일인 것처럼 애플리케이션에 개체를 표시할 수 있습니다.

CFSTR_FILECONTENTS 대한 데이터 전송 메커니즘은 일반적으로 TYMED_ISTREAM. IStream 인터페이스 포인터를 전송하려면 데이터를 전역 메모리 개체로 로드하는 것보다 훨씬 적은 메모리가 필요하며 IStream 은 IStorage보다 데이터를 나타내는 더 간단한 방법입니다.

CFSTR_FILECONTENTS 형식은 항상 CFSTR_FILEDESCRIPTOR 형식과 함께 제공됩니다. 먼저 이 형식의 내용을 검사해야 합니다. 둘 이상의 파일을 전송하는 경우 데이터 개체에는 실제로 각 파일에 대해 하나씩 여러 CFSTR_FILECONTENTS 형식이 포함됩니다. CFSTR_FILEDESCRIPTOR 형식은 각 파일의 이름과 특성을 포함하며 특정 파일의 CFSTR_FILECONTENTS 형식을 추출하는 데 필요한 각 파일에 대한 인덱스 값을 제공합니다.

CFSTR_FILECONTENTS 형식을 추출하려면 다음을 수행합니다.

  1. CFSTR_FILEDESCRIPTOR 형식을 TYMED_HGLOBAL 값으로 추출합니다.
  2. 반환된 STGMEDIUM 구조체의 hGlobal 멤버는 전역 메모리 개체를 가리킵니다. hGlobal 값을 GlobalLock에 전달하여 해당 개체를 잠급 수 있습니다.
  3. GlobalLock에서 반환된 포인터를 FILEGROUPDESCRIPTOR 포인터로 캐스팅합니다. FILEGROUPDESCRIPTOR 구조체와 하나 이상의 FILEDESCRIPTOR 구조체를 가리킵니다. 각 FILEDESCRIPTOR 구조체에는 함께 제공되는 CFSTR_FILECONTENTS 형식 중 하나에 포함된 파일에 대한 설명이 포함되어 있습니다.
  4. FILEDESCRIPTOR 구조를 검사하여 추출할 파일에 해당하는 구조를 확인합니다. 해당 FILEDESCRIPTOR 구조체의 인덱스(0부터 시작하는 인덱스)는 파일의 CFSTR_FILECONTENTS 형식을 식별하는 데 사용됩니다. 전역 메모리 블록의 크기가 바이트 정밀하지 않으므로 구조체의 nFileSizeLownFileSizeHigh 멤버를 사용하여 전역 메모리 개체의 파일을 나타내는 바이트 수를 결정합니다.
  5. FORMATETC 구조체의 cfFormat 멤버를 CFSTR_FILECONTENTS으로 설정하고 이전 단계에서 결정한 인덱스로 설정된 lIndex 멤버를 사용하여 IDataObject::GetData를 호출합니다. tymed 멤버는 일반적으로 TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE. 그런 다음 데이터 개체는 기본 설정 데이터 전송 메커니즘을 선택할 수 있습니다.
  6. IDataObject::GetData가 반환하는 STGMEDIUM 구조체에는 파일의 데이터에 대한 포인터가 포함됩니다. 구조체의 tymed 멤버를 검사하여 데이터 전송 메커니즘을 확인합니다.
  7. tymed가 TYMED_ISTREAM 또는 TYMED_ISTORAGE 설정되면 인터페이스를 사용하여 데이터를 추출합니다. tymed가 TYMED_HGLOBAL 설정되면 데이터는 전역 메모리 개체에 포함됩니다. 전역 메모리 개체에서 데이터를 추출하는 방법에 대한 자세한 내용은 Shell Data Object의 데이터 개체 섹션에서 전역 메모리 개체 추출 섹션을 참조하세요.
  8. GlobalLock을 호출하여 2단계에서 잠근 전역 메모리 개체의 잠금을 해제합니다.

최적화된 이동 작업 처리

시나리오: 최적화된 이동을 사용하여 파일이 파일 시스템에서 네임스페이스 확장으로 이동됩니다.

기존의 이동 작업에서 대상은 데이터의 복사본을 만들고 원본은 원본을 삭제합니다. 이 절차는 두 개의 데이터 복사본이 필요하기 때문에 비효율적일 수 있습니다. 데이터베이스와 같은 큰 개체의 경우 기존의 이동 작업도 실용적이지 않을 수 있습니다.

최적화된 이동을 통해 대상은 데이터가 저장되는 방식을 이해하여 전체 이동 작업을 처리합니다. 데이터의 두 번째 복사본은 없으며 원본에서 원본 데이터를 삭제할 필요가 없습니다. 셸 데이터는 대상에서 셸 API를 사용하여 전체 작업을 처리할 수 있으므로 최적화된 이동에 적합합니다. 일반적인 예는 파일을 이동하는 것입니다. 대상에 이동할 파일의 경로가 있으면 SHFileOperation을 사용하여 이동할 수 있습니다. 원본에서 원본 파일을 삭제할 필요가 없습니다.

참고 항목

셸은 일반적으로 최적화된 이동을 사용하여 파일을 이동합니다. 셸 데이터 전송을 제대로 처리하려면 애플리케이션이 최적화된 이동을 감지하고 처리할 수 있어야 합니다.

 

최적화된 이동은 다음과 같은 방식으로 처리됩니다.

  1. 원본은 dwEffect 매개 변수가 DROPEFFECT_MOVE 설정된 DoDragDrop을 호출하여 원본 개체를 이동할 수 있음을 나타냅니다.

  2. 대상은 IDropTarget 메서드 중 하나를 통해 DROPEFFECT_MOVE 값을 받으며 이는 이동이 허용됨을 나타냅니다.

  3. 대상은 개체를 복사하거나(최적화되지 않은 이동) 개체를 이동합니다(최적화된 이동).

  4. 그런 다음 대상은 원본 데이터를 삭제해야 하는지 여부를 원본에 알려줍니다.

    최적화된 이동은 대상에 의해 삭제된 데이터가 있는 기본 작업입니다. 원본에 최적화된 이동이 수행되었음을 알리려면 다음을 수행합니다.

    대상이 최적이 아닌 이동을 수행한 경우 원본에서 데이터를 삭제해야 합니다. 원본에 최적이 아닌 이동이 수행되었음을 알리려면 다음을 수행합니다.

  5. 원본은 대상에서 반환할 수 있는 두 값을 검사합니다. 둘 다 DROPEFFECT_MOVE 설정되면 원래 데이터를 삭제하여 최적이 아닌 이동을 완료합니다. 그렇지 않으면 대상이 최적화된 이동을 수행하고 원래 데이터가 삭제되었습니다.

붙여넣기 작업 삭제 처리

시나리오: 하나 이상의 파일이 Windows 탐색기의 폴더에서 잘라내어 네임스페이스 확장에 붙여넣습니다. Windows 탐색기는 붙여넣기 작업의 결과에 대한 피드백을 받을 때까지 파일을 강조 표시합니다.

일반적으로 사용자가 데이터를 잘라내면 보기에서 즉시 사라집니다. 이는 효율적이지 않을 수 있으며, 사용자가 데이터에 어떤 일이 일어났는지 염려하는 경우 유용성 문제가 발생할 수 있습니다. 다른 방법은 붙여넣기 삭제 작업을 사용하는 것입니다.

붙여넣기 작업을 삭제하면 선택한 데이터가 보기에서 즉시 제거되지 않습니다. 대신 원본 애플리케이션은 글꼴 또는 배경색을 변경하여 선택한 것으로 표시합니다. 대상 애플리케이션이 데이터를 붙여넣은 후 원본에 작업 결과에 대해 알 수 있습니다. 대상이 최적화된 이동을 수행한 경우 원본은 단순히 디스플레이를 업데이트할 수 있습니다. 대상이 정상적인 이동을 수행한 경우 원본은 데이터의 복사본도 삭제해야 합니다. 붙여넣기를 실패하면 원본 애플리케이션은 선택한 데이터를 원래 모양으로 복원합니다.

참고 항목

셸은 일반적으로 잘라내기/붙여넣기 작업을 사용하여 파일을 이동할 때 붙여넣기 삭제를 사용합니다. Shell 개체를 사용하여 붙여넣기 작업 삭제는 일반적으로 최적화된 이동을 사용하여 파일을 이동합니다. 셸 데이터 전송을 제대로 처리하려면 애플리케이션에서 붙여넣기 삭제 작업을 검색하고 처리할 수 있어야 합니다.

 

붙여넣기 삭제에 대한 필수 요구 사항은 대상에서 작업의 결과를 원본에 보고해야 한다는 것입니다. 그러나 표준 클립보드 기술은 대상에서 원본과 통신할 수 있는 방법을 제공하지 않으므로 붙여넣기 삭제를 구현하는 데 사용할 수 없습니다. 대신 대상 애플리케이션은 데이터 개체의 IDataObject::SetData 메서드를 사용하여 결과를 데이터 개체에 보고합니다. 그런 다음 데이터 개체는 프라이빗 인터페이스를 통해 원본과 통신할 수 있습니다.

붙여넣기 작업 삭제에 대한 기본 절차는 다음과 같습니다.

  1. 원본은 선택한 데이터의 화면 표시를 표시합니다.
  2. 원본은 데이터 개체를 만듭니다. 데이터 값이 DROPEFFECT_MOVE CFSTR_PREFERREDDROPEFFECT 형식을 추가하여 잘라내기 작업을 나타냅니다.
  3. 원본은 OleSetClipboard를 사용하여 데이터 개체를 클립보드에 배치합니다.
  4. 대상은 OleGetClipboard를 사용하여 클립보드에서 데이터 개체를 검색합니다.
  5. 대상은 CFSTR_PREFERREDDROPEFFECT 데이터를 추출합니다. DROPEFFECT_MOVE만 설정하면 대상은 최적화된 이동을 수행하거나 단순히 데이터를 복사할 수 있습니다.
  6. 대상이 최적화된 이동을 수행하지 않으면 CFSTR_PERFORMEDDROPEFFECT 형식이 DROPEFFECT_MOVE 설정된 IDataObject::SetData 메서드를 호출합니다.
  7. 붙여넣기를 완료하면 대상은 CFSTR_PASTESUCCEEDED 형식이 DROPEFFECT_MOVE 설정된 IDataObject::SetData 메서드를 호출합니다.
  8. 원본의 IDataObject::SetData 메서드가 DROPEFFECT_MOVE 설정된 CFSTR_PASTESUCCEEDED 형식으로 호출되면 DROPEFFECT_MOVE CFSTR_PERFORMEDDROPEFFECT 형식도 수신했는지 확인해야 합니다. 두 형식이 모두 대상에서 전송되는 경우 원본은 데이터를 삭제해야 합니다. CFSTR_PASTESUCCEEDED 형식만 수신된 경우 원본은 표시에서 데이터를 제거할 수 있습니다. 전송에 실패하면 원본이 디스플레이를 원래 모양으로 업데이트합니다.

가상 폴더와 데이터 전송

시나리오: 사용자가 개체를 가상 폴더에서 끌어서 끕니다.

가상 폴더에는 일반적으로 파일 시스템의 일부가 아닌 개체가 포함됩니다. 휴지통과 같은 일부 가상 폴더는 하드 디스크에 저장되지만 일반 파일 시스템 개체로는 저장되지 않는 데이터를 나타낼 수 있습니다. 일부는 핸드헬드 PC 또는 FTP 사이트와 같은 원격 시스템에 저장된 데이터를 나타낼 수 있습니다. 프린터 폴더와 같은 다른 항목에는 저장된 데이터를 전혀 나타내지 않는 개체가 포함되어 있습니다. 일부 가상 폴더는 시스템의 일부이지만 개발자는 네임스페이스 확장을 구현하여 사용자 지정 가상 폴더를 만들고 설치할 수도 있습니다.

데이터 형식이나 저장 방법에 관계없이 가상 폴더에 포함된 폴더 및 파일 개체는 일반 파일 및 폴더인 것처럼 Shell에 의해 표시됩니다. 포함된 모든 데이터를 가져와서 셸에 적절하게 제공하는 것은 가상 폴더의 책임입니다. 이 요구 사항은 가상 폴더가 일반적으로 끌어서 놓기 및 클립보드 데이터 전송을 지원한다는 것을 의미합니다.

따라서 가상 폴더 간에 데이터 전송을 고려해야 하는 두 개의 개발자 그룹이 있습니다.

  • 애플리케이션이 가상 폴더에서 전송된 데이터를 수락해야 하는 개발자.
  • 네임스페이스 확장이 데이터 전송을 제대로 지원해야 하는 개발자.

가상 폴더에서 데이터 수락

가상 폴더는 거의 모든 유형의 데이터를 나타낼 수 있으며 선택한 방식으로 해당 데이터를 저장할 수 있습니다. 일부 가상 폴더는 실제로 일반 파일 시스템 파일 및 폴더를 포함할 수 있습니다. 예를 들어 다른 개체는 모든 개체를 단일 문서 또는 데이터베이스에 압축할 수 있습니다.

파일 시스템 개체가 애플리케이션으로 전송되는 경우 데이터 개체는 일반적으로 개체의 정규화된 경로가 있는 CF_HDROP 형식을 포함합니다. 애플리케이션은 이 문자열을 추출하고 일반 파일 시스템 함수를 사용하여 파일을 열고 해당 데이터를 추출할 수 있습니다. 그러나 가상 폴더는 일반적으로 일반 파일 시스템 개체를 포함하지 않으므로 일반적으로 CF_HDROP 사용하지 않습니다.

CF_HDROP 대신 데이터는 일반적으로 CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS/ 형식으로 가상 폴더에서 전송됩니다. CFSTR_FILECONTENTS 형식은 CF_HDROP 비해 두 가지 이점이 있습니다.

전역 메모리 개체는 데이터를 메모리 전체에 복사해야 하므로 가상 개체 간에 데이터를 전송하는 데 거의 사용되지 않습니다. 인터페이스 포인터를 전송하려면 메모리가 거의 필요하지 않으며 훨씬 더 효율적입니다. 매우 큰 파일을 사용하는 경우 인터페이스 포인터가 유일한 실제 데이터 전송 메커니즘일 수 있습니다. 일반적으로 데이터는 IStorage보다 약간 더 유연하기 때문에 IStream 포인터로 표시됩니다. 대상은 데이터 개체에서 포인터를 추출하고 인터페이스 메서드를 사용하여 데이터를 추출합니다.

CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS/ 형식을 처리하는 방법에 대한 자세한 내용은 CFSTR_FILECONTENTS 형식을 사용하여 파일에서 데이터를 추출하는 방법을 참조하세요.

네임스페이스 확장과 데이터 전송

네임스페이스 확장을 구현하는 경우 일반적으로 끌어서 놓기 기능을 지원하려고 합니다. 일반 지침에 설명된 드롭 소스 및 대상에 대한 권장 사항을 따릅니다. 특히 네임스페이스 확장은 다음을 수행해야 합니다.

  • CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS/ 형식을 처리할 수 있습니다. 이러한 두 형식은 일반적으로 네임스페이스 확장 간에 개체를 전송하는 데 사용됩니다.
  • 최적화된 이동을 처리할 수 있습니다. Shell은 셸 개체가 최적화된 이동으로 이동될 것으로 예상합니다.
  • 붙여넣기 삭제 작업을 처리할 수 있습니다. 셸은 잘라내기/붙여넣기 작업으로 개체를 Shell에서 이동할 때 붙여넣기 삭제를 사용합니다.
  • IStream 또는 IStorage 인터페이스를 통해 데이터 전송을 처리할 수 있어야 합니다. 가상 폴더 간 데이터 전송은 일반적으로 이러한 두 인터페이스 포인터 중 하나(일반적으로 IStream 포인터)를 전송하여 처리됩니다 . 그런 다음 대상은 인터페이스 메서드를 호출하여 데이터를 추출합니다.
      • 드롭 소스로서 네임스페이스 확장은 스토리지에서 데이터를 추출하고 이 인터페이스를 통해 대상에 전달해야 합니다.
      • 삭제 대상인 네임스페이스 확장은 이 인터페이스를 통해 원본의 데이터를 수락하고 제대로 저장해야 합니다.

휴지통에 파일 삭제

시나리오: 사용자가 휴지통에 파일을 삭제합니다. 애플리케이션 또는 네임스페이스 확장명은 원래 파일을 삭제합니다.

휴지통은 더 이상 필요하지 않은 파일의 리포지토리로 사용되는 가상 폴더입니다. 휴지통이 비워지지 않은 한 사용자는 나중에 파일을 복구하고 파일 시스템으로 반환할 수 있습니다.

대부분의 경우 셸 개체를 휴지통으로 전송하는 것은 다른 폴더와 매우 유사합니다. 그러나 사용자가 휴지통파일을 삭제하는 경우 원본은 폴더의 피드백이 복사 작업을 나타내는 경우에도 원본을 삭제해야 합니다. 일반적으로 삭제 원본은 해당 데이터 개체가 삭제된 폴더를 알 수 없습니다. 그러나 Windows 2000 이상 시스템의 경우 휴지통에 데이터 개체가 놓이면 셸은 CFSTR_TARGETCLSID 형식이 CLSID(휴지통의 클래스 식별자)(CLSID_RecycleBin)로 설정된 데이터 개체의 IDataObject::SetData 메서드를 호출합니다. 휴지통 케이스를 제대로 처리하려면 데이터 개체가 이 형식을 인식하고 프라이빗 인터페이스를 통해 원본에 정보를 전달할 수 있어야 합니다.

참고 항목

IDataObject::SetData가 CLSID_RecycleBin 설정된 CFSTR_TARGETCLSID 형식으로 호출되면 데이터 원본은 메서드에서 반환하기 전에 전송되는 개체에 대해 열려 있는 핸들을 닫아야 합니다. 그렇지 않으면 공유 위반을 만들 수 있습니다.

 

스크랩 파일 만들기 및 가져오기

시나리오: 사용자가 OLE 애플리케이션의 데이터 파일에서 일부 데이터를 끌어 데스크톱 또는 Windows 탐색기에 삭제합니다.

Windows를 사용하면 사용자가 OLE 애플리케이션의 데이터 파일에서 개체를 끌어 데스크톱 또는 파일 시스템 폴더에 놓을 수 있습니다. 이 작업은 데이터 또는 데이터에 대한 링크를 포함하는 스크랩 파일을 만듭니다. 파일 이름은 개체의 CLSID 및 CF_TEXT 데이터에 대해 등록된 짧은 이름에서 가져옵니다. 셸이 데이터를 포함하는 스크랩 파일을 만들려면 애플리케이션의 IDataObject 인터페이스가 CF_EMBEDSOURCE 클립보드 형식을 지원해야 합니다. 링크 가 포함된 파일을 만들려면 IDataObject 에서 CF_LINKSOURCE 형식을 지원해야 합니다.

애플리케이션에서 스크랩 파일을 지원하기 위해 구현할 수 있는 세 가지 선택적 기능도 있습니다.

  • 왕복 지원
  • 캐시된 데이터 형식
  • 지연된 렌더링

왕복 지원

왕복에는 데이터 개체를 다른 컨테이너로 전송한 다음 원래 문서로 다시 전송하는 작업이 포함됩니다. 예를 들어 사용자는 스프레드시트에서 바탕 화면으로 셀 그룹을 전송하여 데이터가 포함된 스크랩 파일을 만들 수 있습니다. 그런 다음 사용자가 스크랩을 다시 스프레드시트로 전송하는 경우 데이터는 원래 전송 이전과 마찬가지로 문서에 통합되어야 합니다.

Shell은 스크랩 파일을 만들 때 데이터를 포함 개체로 나타냅니다. 스크랩이 다른 컨테이너로 전송되면 원본 문서로 반환되더라도 포함 개체로 전송됩니다. 애플리케이션은 스크랩에 포함된 데이터 형식을 결정하고 필요한 경우 데이터를 다시 기본 형식으로 전환해야 합니다.

포함된 개체의 형식을 설정하려면 개체의 CF_OBJECTDESCRIPTOR 형식을 검색하여 CLSID를 확인합니다. CLSID가 애플리케이션에 속하는 데이터 형식을 나타내는 경우 OleCreateFromData를 호출하는 대신 네이티브 데이터를 전송해야 합니다.

캐시된 데이터 형식

Shell에서 스크랩 파일을 만들 때 레지스트리에서 사용 가능한 형식 목록을 확인합니다. 기본적으로 CF_EMBEDSOURCE 및 CF_LINKSOURCE 두 가지 형식을 사용할 수 있습니다. 그러나 애플리케이션에 다른 형식의 스크랩 파일이 필요할 수 있는 여러 시나리오가 있습니다.

  • 포함된 개체 형식을 수락할 수 없는 비 OLE 컨테이너로 스크랩을 전송할 수 있도록 합니다.
  • 애플리케이션 제품군이 프라이빗 형식과 통신할 수 있도록 허용합니다.
  • 왕복을 더 쉽게 처리할 수 있도록 합니다.

애플리케이션은 레지스트리에서 캐싱하여 스크랩에 형식을 추가할 수 있습니다. 캐시된 형식에는 다음 두 가지 유형이 있습니다.

  • 우선 순위 캐시 형식입니다. 이러한 형식의 경우 데이터는 데이터 개체의 스크랩에 전체적으로 복사됩니다.
  • 지연 렌더링 형식입니다. 이러한 형식의 경우 데이터 개체는 스크랩에 복사되지 않습니다. 대신 대상에서 데이터를 요청할 때까지 렌더링이 지연됩니다. 지연 렌더링은 다음 섹션에서 자세히 설명합니다.

우선 순위 캐시 또는 지연 렌더링 형식을 추가하려면 데이터 원본인 애플리케이션의 CLSID 키 아래에 DataFormat 하위 키를 만듭니다. 해당 하위 키에서 PriorityCacheFormats 또는 DelayRenderFormats 하위 키를 만듭니다. 각 우선 순위 캐시 또는 지연 렌더링 형식에 대해 0부터 번호가 매겨진 하위 키를 만듭니다. 이 키의 값을 형식의 등록된 이름을 가진 문자열 또는 #X 값으로 설정합니다. 여기서 X는 표준 클립보드 형식의 형식 번호를 나타냅니다.

다음 샘플에서는 두 애플리케이션에 대해 캐시된 형식을 보여 줍니다. MyProg1 애플리케이션은 서식 있는 텍스트 형식을 우선 순위 캐시 형식으로 사용하고 프라이빗 형식 "My Format"을 지연 렌더링 형식으로 사용합니다. MyProg2 애플리케이션에는 우선 순위 캐시 형식으로 CF_BITMAP 형식(#8")이 있습니다.

HKEY_CLASSES_ROOT
   CLSID
      {GUID}
         (Default) = MyProg1
         DataFormats
            PriorityCacheFormats
               0
                  (Default) = Rich Text Format
            DelayRenderFormats
               0
                  (Default) = My Format
      {GUID}
         (Default) = MyProg2
         DataFormats
            PriorityCacheFormats
               0
                  (Default) = #8

번호가 매겨진 추가 하위 키를 만들어 추가 형식을 추가할 수 있습니다.

지연된 렌더링

지연된 렌더링 형식을 사용하면 애플리케이션에서 스크랩 파일을 만들 수 있지만 대상에서 요청할 때까지 데이터 렌더링 비용을 지연할 수 있습니다. 스크랩의 IDataObject 인터페이스는 네이티브 및 캐시된 데이터와 함께 대상에 지연된 렌더링 형식을 제공합니다. 대상에서 지연된 렌더링 형식을 요청하는 경우 Shell은 애플리케이션을 실행하고 활성 개체에서 대상에 데이터를 제공합니다.

참고 항목

지연된 렌더링은 다소 위험하므로 주의해서 사용해야 합니다. 서버를 사용할 수 없거나 OLE를 사용하지 않는 애플리케이션에서는 작동하지 않습니다.

 

셸 개체를 비동기적으로 끌어서 놓기

시나리오: 사용자가 큰 데이터 블록을 원본에서 대상으로 전송합니다. 두 애플리케이션이 상당한 시간 동안 차단되는 것을 방지하기 위해 대상은 데이터를 비동기적으로 추출합니다.

일반적으로 끌어서 놓기는 동기 작업입니다. 개요:

  1. 드롭 소스는 DoDragDrop을 호출하고 함수가 반환될 때까지 기본 스레드를 차단합니다. 기본 스레드를 차단하면 일반적으로 UI 처리가 차단됩니다.
  2. 대상의 IDropTarget::D rop 메서드가 호출되면 대상은 기본 스레드의 데이터 개체에서 데이터를 추출합니다. 이 절차는 일반적으로 추출 프로세스 기간 동안 대상의 UI 처리를 차단합니다.
  3. 데이터가 추출되면 대상은 IDropTarget::D rop 호출을 반환하고 시스템은 DoDragDrop을 반환하며 두 스레드를 모두 진행할 수 있습니다.

즉, 동기 데이터 전송은 상당한 시간 동안 두 애플리케이션의 기본 스레드를 차단할 수 있습니다. 특히 두 스레드는 대상이 데이터를 추출하는 동안 기다려야 합니다. 적은 양의 데이터의 경우 데이터를 추출하는 데 필요한 시간이 적고 동기 데이터 전송이 매우 잘 작동합니다. 그러나 대량의 데이터를 동기적으로 추출하면 긴 지연이 발생하고 대상 및 원본의 UI를 방해할 수 있습니다.

IAsyncOperation/IDataObjectAsyncCapability 인터페이스는 데이터 개체에서 구현할 수 있는 선택적 인터페이스입니다. 드롭 대상은 백그라운드 스레드에서 데이터 개체에서 데이터를 비동기적으로 추출하는 기능을 제공합니다. 데이터 추출이 백그라운드 스레드로 전달되면 두 애플리케이션의 기본 스레드를 자유롭게 진행할 수 있습니다.

IASyncOperation/IDataObjectAsyncCapability 사용

참고 항목

인터페이스 이름은 원래 IAsyncOperation이었지만 나중에 IDataObjectAsyncCapability변경되었습니다. 그렇지 않으면 두 인터페이스가 동일합니다.

 

IAsyncOperation/IDataObjectAsyncCapability목적은 놓기 원본 및 놓기 대상이 데이터를 비동기적으로 추출할 수 있는지 여부를 협상하도록 허용하는 것입니다. 다음 절차에서는 드롭 소스에서 인터페이스를 사용하는 방법을 간략하게 설명합니다.

  1. IAsyncOperation/IDataObjectAsyncCapability를 노출하는 데이터 개체를 만듭니다.
  2. fDoOpAsync가 VARIANT_TRUE 설정된 SetAsyncMode를 호출하여 비동기 작업이 지원됨을 나타냅니다.
  3. DoDragDrop이 반환되면 InOperation을 호출합니다.
  4. 데이터 개체를 해제합니다.
  5. 비동기 데이터 전송이 완료되면 데이터 개체는 일반적으로 프라이빗 인터페이스를 통해 원본에 알깁니다.

다음 절차에서는 놓기 대상이 IAsyncOperation/IDataObjectAsyncCapability 인터페이스를 사용하여 데이터를 비동기적으로 추출하는 방법을 간략하게 설명합니다.

  1. 시스템에서 IDropTarget::D rop을 호출하는 경우 IDataObject::QueryInterface를 호출하고 데이터 개체에서 IAsyncOperation/IDataObjectAsyncCapability 인터페이스(IID_IAsyncOperation/IID_IDataObjectAsyncCapability)를 요청합니다.
  2. GetAsyncMode를 호출합니다. 메서드가 VARIANT_TRUE 반환하는 경우 데이터 개체는 비동기 데이터 추출을 지원합니다.
  3. 데이터 추출을 처리하고 StartOperation을 호출하는 별도의 스레드를 만듭니다.
  4. 일반적인 데이터 전송 작업과 마찬가지로 IDropTarget::D rop 호출을 반환합니다. DoDragDrop 은 드롭 소스를 반환하고 차단을 해제합니다. IDataObject::SetData를 호출하여 최적화된 이동 또는 붙여넣기 삭제 작업의 결과를 나타내지 마세요. 작업이 완료될 때까지 기다립니다.
  5. 백그라운드 스레드에서 데이터를 추출합니다. 대상의 기본 스레드는 차단 해제되어 있으며 자유롭게 진행할 수 있습니다.
  6. 데이터 전송이 최적화된 이동 또는 붙여넣기 삭제 작업인 경우 IDataObject::SetData를 호출하여 결과를 나타냅니다.
  7. EndOperation을 호출 하여 추출이 완료되었음을 데이터 개체에 알립니다.