다음을 통해 공유


셸 데이터 개체

데이터 개체는 모든 Shell 데이터 전송의 중심입니다. 주로 전송된 데이터를 보관하는 컨테이너입니다. 그러나 대상은 데이터 개체와 통신하여 최적화된 이동과 같은 일부 특수한 유형의 Shell 데이터 전송을 용이하게 할 수도 있습니다. 이 항목에서는 Shell 데이터 개체의 작동 방식, 원본에 의해 생성되는 방법 및 대상에서 처리하는 방법에 대한 일반적인 설명을 제공합니다. 데이터 개체를 사용하여 다양한 유형의 셸 데이터를 전송하는 방법에 대한 자세한 내용은 셸 데이터 전송 시나리오 처리를 참조하세요.

데이터 개체의 작동 방식

데이터 개체는 데이터를 대상으로 전송하기 위해 데이터 원본에서 만든 COM(Component Object Model) 개체입니다. 일반적으로 둘 이상의 데이터 항목을 전달합니다. 이 방법에는 두 가지 이유가 있습니다.

  • 데이터 개체를 사용하여 거의 모든 형식의 데이터를 전송할 수 있지만 원본은 일반적으로 대상이 허용할 수 있는 데이터의 종류를 알지 못합니다. instance 경우 데이터는 서식이 지정된 텍스트 문서의 일부일 수 있습니다. 대상이 복잡한 서식 정보를 처리할 수 있지만 ANSI 텍스트만 수락할 수도 있습니다. 이러한 이유로 데이터 개체는 여러 가지 형식으로 동일한 데이터를 포함하는 경우가 많습니다. 그런 다음 대상은 처리할 수 있는 형식으로 데이터를 추출할 수 있습니다.
  • 데이터 개체에는 원본 데이터의 버전이 아닌 보조 데이터 항목도 포함될 수 있습니다. 이 유형의 데이터 항목은 일반적으로 데이터 전송 작업에 대한 추가 정보를 제공합니다. instance 경우 Shell은 보조 데이터 항목을 사용하여 파일을 복사하거나 이동할지 여부를 나타냅니다.

클립보드 형식

데이터 개체의 각 데이터 항목에는 일반적으로 클립보드 형식이라고 하는 연결된 형식이 있습니다. 일반적으로 사용되는 데이터 형식에 해당하는 여러 표준 클립보드 형식이 Winuser.h에 선언되어 있습니다. 클립보드 형식은 정수이지만 일반적으로 해당 이름으로 참조되며 형식은 CF_XXX입니다. instance 경우 ANSI 텍스트의 클립보드 형식이 CF_TEXT.

애플리케이션은 프라이빗 형식을 정의하여 사용 가능한 클립보드 형식의 범위를 확장할 수 있습니다. 프라이빗 형식을 정의하기 위해 애플리케이션은 형식을 식별하는 문자열을 사용하여 RegisterClipboardFormat 을 호출합니다. 함수가 반환하는 부호 없는 정수는 표준 클립보드 형식처럼 사용할 수 있는 유효한 형식 값입니다. 그러나 원본과 대상 모두 형식을 사용하려면 형식을 등록해야 합니다. CF_HDROP 한 가지 예외를 제외하고 Shell 데이터를 전송하는 데 사용되는 클립보드 형식은 프라이빗 형식으로 정의됩니다. 사용하려면 먼저 원본 및 대상에 의해 등록되어야 합니다. 사용 가능한 셸 클립보드 형식에 대한 설명은 셸 클립보드 형식을 참조하세요.

몇 가지 예외가 있지만 데이터 개체는 일반적으로 지원하는 각 클립보드 형식에 대해 하나의 데이터 항목만 포함합니다. 형식과 데이터 간의 이 일대일 상관 관계를 통해 서식 값을 연결된 데이터 항목의 식별자로 사용할 수 있습니다. 실제로 데이터 개체의 내용을 논의할 때 데이터의 특정 항목을 일반적으로 "형식"이라고 하며 해당 형식 이름으로 참조됩니다. 예를 들어 "CF_TEXT 형식 추출..."과 같은 구문이 있습니다. 는 일반적으로 데이터 개체의 ANSI 텍스트 데이터 항목을 논의할 때 사용됩니다.

놓기 대상이 데이터 개체에 대한 포인터를 받으면 놓기 대상은 사용 가능한 형식을 열거하여 사용 가능한 데이터 형식을 결정합니다. 그런 다음 사용 가능한 형식 중 하나 이상을 요청하고 데이터를 추출합니다. 대상에서 데이터 개체에서 Shell 데이터를 추출하는 특정 방법은 형식에 따라 다릅니다. 대상에서 데이터 개체를 처리하는 방법에 대해 자세히 설명합니다.

간단한 클립보드 데이터 전송을 사용하면 데이터가 전역 메모리 개체에 배치됩니다. 해당 개체의 주소는 해당 형식과 함께 클립보드에 배치됩니다. 클립보드 형식은 대상에게 연결된 주소에서 찾을 데이터의 종류를 알려줍니다. 간단한 클립보드 전송은 쉽게 구현할 수 있지만:

  • 데이터 개체는 데이터를 전송하는 훨씬 더 유연한 방법을 제공합니다.
  • 데이터 개체는 대량의 데이터를 전송하는 데 더 적합합니다.
  • 끌어서 놓기 작업을 사용하여 데이터를 전송하려면 데이터 개체를 사용해야 합니다.

이러한 이유로 모든 셸 데이터 전송은 데이터 개체를 사용합니다. 데이터 개체를 사용하면 클립보드 형식이 직접 사용되지 않습니다. 대신 데이터 항목은 클립보드 형식의 일반화인 FORMATETC 구조로 식별됩니다.

FORMATETC 구조체

FORMATETC 구조체는 클립보드 형식의 확장 버전입니다. Shell 데이터 전송에 사용되는 FORMATETC 구조에는 다음과 같은 특성이 있습니다.

  • 데이터 항목은 여전히 cfFormat 멤버의 클립보드 형식으로 식별됩니다.

  • 데이터 전송은 전역 메모리 개체로 제한되지 않습니다. tymed 멤버는 연결된 STGMEDIUM 구조에 포함된 데이터 전송 메커니즘을 나타내는 데 사용됩니다. TYMED_XXX 값 중 하나로 설정됩니다.

  • Shell은 CFSTR_FILECONTENTS 형식의 lIndex 멤버를 사용하여 데이터 개체가 형식당 둘 이상의 데이터 항목을 포함할 수 있도록 합니다. 이 형식을 사용하는 방법에 대한 자세한 내용은 셸 데이터 전송 시나리오 처리의 파일에서 CFSTR_FILECONTENTS 형식을 사용하여 데이터 추출 섹션을 참조하세요.

  • dwAspect 멤버는 일반적으로 DVASPECT_CONTENT 설정됩니다. 그러나 Shlobj.h에는 셸 데이터 전송에 사용할 수 있는 세 가지 값이 정의되어 있습니다.

    Description
    DVASPECT_COPY 형식이 데이터의 복사본을 나타낸다는 것을 나타내는 데 사용됩니다.
    DVASPECT_LINK 형식이 데이터의 바로 가기를 나타낸다는 것을 나타내는 데 사용됩니다.
    DVASPECT_SHORTNAME 이름이 8.3 형식으로 단축된 파일 경로를 요청하기 위해 CF_HDROP 형식과 함께 사용됩니다.

     

  • ptd 멤버는 셸 데이터 전송에 사용되지 않으며 일반적으로 NULL로 설정됩니다.

STGMEDIUM 구조체

STGMEDIUM 구조는 전송되는 데이터에 대한 액세스를 제공합니다. Shell 데이터에 대해 세 가지 데이터 전송 메커니즘이 지원됩니다.

  • 전역 메모리 개체입니다.
  • IStream 인터페이스입니다.
  • IStorage 인터페이스입니다.

STGMEDIUM 구조체의 tymed 멤버는 데이터 전송 메커니즘을 식별하는 TYMED_XXX 값입니다. 두 번째 멤버는 대상에서 데이터를 추출하는 데 사용되는 포인터입니다. 포인터는 tymed 값에 따라 다양한 형식 중 하나일 수 있습니다. 셸 데이터 전송에 사용되는 세 개의 tymed 값은 해당 STGMEDIUM 멤버 이름과 함께 다음 표에 요약되어 있습니다.

tymed 값 멤버 이름 설명
TYMED_HGLOBAL Hglobal 전역 메모리 개체에 대한 포인터입니다. 이 포인터 형식은 일반적으로 소량의 데이터를 전송하는 데 사용됩니다. instance 경우 Shell은 전역 메모리 개체를 사용하여 파일 이름 또는 URL과 같은 짧은 텍스트 문자열을 전송합니다.
TYMED_ISTREAM pstm IStream 인터페이스에 대한 포인터입니다. 이 포인터 형식은 TYMED_HGLOBAL 비해 메모리가 상대적으로 적기 때문에 대부분의 Shell 데이터 전송에 선호됩니다. 또한 TYMED_ISTREAM 데이터 전송 메커니즘은 원본이 특정 방식으로 데이터를 저장할 필요가 없습니다.
TYMED_ISTORAGE pstg IStorage 인터페이스에 대한 포인터입니다. 대상은 인터페이스 메서드를 호출하여 데이터를 추출합니다. TYMED_ISTREAM 마찬가지로 이 포인터 형식에는 상대적으로 적은 메모리가 필요합니다. 그러나 TYMED_ISTORAGE TYMED_ISTREAM 보다 덜 유연하기 때문에 일반적으로 사용되지 않습니다.

 

원본에서 데이터 개체를 만드는 방법

사용자가 Shell 데이터 전송을 시작하면 원본은 데이터 개체를 만들고 데이터로 로드합니다. 다음 절차에서는 프로세스를 요약합니다.

  1. RegisterClipboardFormat을 호출하여 데이터 개체에 포함될 각 Shell 형식에 대한 유효한 클립보드 형식 값을 가져옵니다. CF_HDROP 이미 유효한 클립보드 형식이며 등록할 필요가 없습니다.
  2. 전송할 각 형식에 대해 연결된 데이터를 전역 메모리 개체에 넣거나 IStream 또는 IStorage 인터페이스를 통해 해당 데이터에 대한 액세스를 제공하는 개체를 만듭니다. IStreamIStorage 인터페이스는 표준 COM 기술을 사용하여 만들어집니다. 전역 메모리 개체를 처리하는 방법에 대한 자세한 내용은 데이터 개체에 전역 메모리 개체를 추가하는 방법을 참조하세요.
  3. 각 형식 에 대한 FORMATETCSTGMEDIUM 구조를 만듭니다.
  4. 데이터 개체를 인스턴스화합니다.
  5. 지원되는 각 형식에 대해 IDataObject::SetData 메서드를 호출하고 형식의 FORMATETCSTGMEDIUM 구조를 전달하여 데이터를 데이터 개체에 로드합니다.
  6. 클립보드 데이터 전송을 사용하면 OleSetClipboard 를 호출하여 데이터 개체의 IDataObject 인터페이스에 대한 포인터를 클립보드에 배치합니다. 끌어서 놓기 전송의 경우 DoDragDrop을 호출하여 끌기 루프를 시작합니다. 데이터가 삭제되면 IDataObject 포인터가 놓기 대상에 전달되어 끌기 루프가 종료됩니다.

이제 데이터 개체를 대상으로 전송할 준비가 되었습니다. 클립보드 데이터 전송의 경우 개체는 대상이 OleGetClipboard를 호출하여 요청할 때까지 유지됩니다. 끌어서 놓기 데이터 전송의 경우 데이터 개체는 데이터를 나타내는 아이콘을 만들고 사용자가 커서를 이동할 때 이동해야 합니다. 개체가 끌기 루프에 있는 동안 원본은 IDropSource 인터페이스를 통해 상태 정보를 받습니다. 자세한 내용은 IDropSource 구현을 참조하세요.

대상에 의해 클립보드에서 데이터 개체를 검색하는 경우 원본은 알림을 받지 않습니다. 끌어서 놓기 작업으로 대상에 개체를 놓으면 끌기 루프를 시작하기 위해 호출된 DoDragDrop 함수가 반환됩니다.

데이터 개체에 전역 메모리 개체를 추가하는 방법

대부분의 Shell 데이터 형식은 전역 메모리 개체 형식입니다. 다음 절차에 따라 전역 메모리 개체가 포함된 형식을 만들고 데이터 개체에 로드합니다.

  1. FORMATETC 구조를 만듭니다. cfFormat 멤버를 적절한 클립보드 형식 값으로 설정하고 tymed 멤버를 TYMED_HGLOBAL.
  2. STGMEDIUM 구조를 만듭니다. tymed 멤버를 TYMED_HGLOBAL 설정합니다.
  3. GlobalAlloc을 호출하여 적절한 크기의 메모리 블록을 할당하여 전역 메모리 개체를 만듭니다.
  4. GlobalAlloc에서 반환한 주소로 전송할 데이터 블록을 할당합니다.
  5. STGMEDIUM 구조체의 hGlobal 멤버에 전역 메모리 개체의 주소를 할당합니다.
  6. IDataObject::SetData를 호출하고 이전 단계에서 만든 FORMATETCSTGMEDIUM 구조를 전달하여 형식을 데이터 개체에 로드합니다.

다음 샘플 함수는 DWORD 값이 포함된 전역 메모리 개체를 만들어 데이터 개체에 로드합니다. pdtobj 매개 변수는 데이터 개체의 IDataObject 인터페이스에 대한 포인터이고 cf는 클립보드 형식 값이고 dw는 데이터 값입니다.

STDAPI DataObj_SetDWORD(IDataObject *pdtobj, UINT cf, DWORD dw)
{
    FORMATETC fmte = {(CLIPFORMAT) cf, 
                      NULL, 
                      DVASPECT_CONTENT, 
                      -1, 
                      TYMED_HGLOBAL};
    STGMEDIUM medium;

    HRESULT hres = E_OUTOFMEMORY;
    DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
    
    if (pdw)
    {
        *pdw = dw;       
        medium.tymed = TYMED_HGLOBAL;
        medium.hGlobal = pdw;
        medium.pUnkForRelease = NULL;

        hres = pdtobj->SetData(&fmte, &medium, TRUE);
 
        if (FAILED(hres))
            GlobalFree((HGLOBAL)pdw);
    }
    return hres;
}

IDataObject 구현

IDataObject 는 데이터 개체의 기본 인터페이스입니다. 모든 데이터 개체에서 구현해야 합니다. 다음을 비롯한 다양한 용도로 원본 및 대상에서 사용됩니다.

  • 데이터 개체에 데이터 로드
  • 데이터 개체에서 데이터 추출
  • 데이터 개체에 있는 데이터 형식 결정
  • 데이터 전송 결과에 대한 피드백을 데이터 개체에 제공합니다.

IDataObject 는 다양한 메서드를 지원합니다. 이 섹션에서는 Shell 데이터 개체, SetData, EnumFormatEtcGetData에 대해 가장 중요한 세 가지 메서드를 구현하는 방법에 대해 설명합니다. 다른 메서드에 대한 자세한 내용은 IDataObject 참조를 참조하세요.

SetData 메서드

IDataObject::SetData 메서드의 기본 함수는 원본이 데이터 개체에 데이터를 로드할 수 있도록 하는 것입니다. 포함할 각 형식에 대해 원본은 형식을 식별하는 FORMATETC 구조체와 데이터에 대한 포인터를 저장할 STGMEDIUM 구조를 만듭니다. 그런 다음 소스는 개체의 IDataObject::SetData 메서드를 호출하고 형식의 FORMATETCSTGMEDIUM 구조를 전달합니다. 대상에서 IDataObject::GetData 를 호출하여 개체에서 데이터를 추출할 때 사용할 수 있도록 메서드는 이 정보를 저장해야 합니다.

그러나 파일을 전송할 때 Shell은 종종 각 파일에 대한 정보를 별도의 CFSTR_FILECONTENTS 형식으로 전송합니다. 다른 파일을 구분하기 위해 각 파일의 FORMATETC 구조체의 lIndex 멤버가 특정 파일을 식별하는 인덱스 값으로 설정됩니다. IDataObject::SetData 구현은 lIndex 멤버만 다른 여러 CFSTR_FILECONTENTS 형식을 저장할 수 있어야 합니다.

커서가 대상 창 위에 있는 동안 대상은 끌어서 놓기 도우미 개체 를 사용하여 끌기 이미지를 지정할 수 있습니다. 끌어서 놓기 도우미 개체는 IDataObject::SetData 를 호출하여 프로세스 간 지원에 사용되는 데이터 개체에 프라이빗 형식을 로드합니다. 끌어서 놓기 도우미 개체를 지원하려면 IDataObject::SetData 구현에서 임의의 프라이빗 형식을 수락하고 저장할 수 있어야 합니다.

데이터가 삭제된 후 일부 유형의 Shell 데이터 전송에서는 대상에서 IDataObject::SetData 를 호출하여 데이터 개체에 삭제 작업의 결과에 대한 정보를 제공해야 합니다. 예를 들어, 최적화된 이동 작업으로 파일을 이동할 때 대상은 일반적으로 원래 파일을 삭제하지만 그렇게 할 필요는 없습니다. 대상은 CFSTR_LOGICALPERFORMEDDROPEFFECT 형식으로IDataObject::SetData를 호출하여 파일을 삭제했는지 여부를 데이터 개체에 알릴 수 있습니다. 대상에서 데이터 개체에 정보를 전달하는 데 사용되는 다른 셸 클립보드 형식 도 몇 가지 있습니다. IDataObject::SetData 구현은 이러한 형식을 인식하고 적절하게 응답할 수 있어야 합니다. 자세한 내용은 셸 데이터 전송 시나리오 처리를 참조하세요.

EnumFormatEtc 메서드

대상은 데이터 개체를 받으면 일반적으로 FORMATETC 를 호출하여 개체에 포함된 형식을 결정합니다. 메서드는 OLE 열거형 개체를 만들고 개체의 IEnumFORMATETC 인터페이스에 대한 포인터를 반환합니다. 그런 다음 대상은 인터페이스를 사용하여 사용 가능한 형식을 열거합니다.

열거형 개체는 항상 최고부터 시작하여 품질 순서대로 사용 가능한 형식을 열거해야 합니다. 형식의 상대적 품질은 드롭 소스에 의해 정의됩니다. 일반적으로 최고 품질의 형식에는 가장 풍부하고 가장 완전한 데이터가 포함됩니다. instance 경우 24비트 색 이미지는 일반적으로 해당 이미지의 회색 배율 버전보다 더 높은 품질로 간주됩니다. 형식을 품질 순서대로 열거하는 이유는 대상이 지원하는 형식에 도달한 다음 해당 형식을 사용하여 데이터를 추출할 때까지 일반적으로 열거하기 때문입니다. 이 절차에서 대상에서 지원할 수 있는 최상의 형식을 생성하려면 형식을 품질 순서대로 열거해야 합니다.

Shell 데이터에 대한 열거형 개체는 주목할 만한 한 가지 예외를 제외하고 다른 형식의 데이터 전송과 거의 동일한 방식으로 구현됩니다. 데이터 개체는 일반적으로 형식당 하나의 데이터 항목만 포함하므로 일반적으로 IDataObject::SetData에 전달되는 모든 형식을 열거합니다. 그러나 SetData 메서드 섹션에서 설명한 대로 Shell 데이터 개체에는 여러 CFSTR_FILECONTENTS 형식이 포함될 수 있습니다.

IDataObject::EnumFormatEtc의 목적은 대상이 존재하는 데이터 형식을 결정할 수 있도록 하는 것이므로 둘 이상의 CFSTR_FILECONTENTS 형식을 열거할 필요가 없습니다. 대상에서 데이터 개체에 포함된 이러한 형식의 수를 알아야 하는 경우 대상은 해당 정보를 함께 제공되는 CFSTR_FILEDESCRIPTOR 형식에서 검색할 수 있습니다. IDataObject::EnumFormatEtc를 구현하는 방법에 대한 자세한 내용은 메서드의 참조 설명서를 참조하세요.

GetData 메서드

대상은 IDataObject::GetData 를 호출하여 특정 데이터 형식을 추출합니다. 대상은 적절한 FORMATETC 구조를 전달하여 형식을 지정합니다. IDataObject::GetData 는 형식의 STGMEDIUM 구조를 반환합니다.

대상은 FORMATETC 구조의 tymed 멤버를 특정 TYMED_XXX 값으로 설정하여 데이터를 추출하는 데 사용할 데이터 전송 메커니즘을 지정할 수 있습니다. 그러나 대상은 보다 일반적인 요청을 수행하고 데이터 개체를 결정하도록 할 수도 있습니다. 데이터 개체에 데이터 전송 메커니즘을 선택하도록 요청하기 위해 대상은 지원하는 모든 TYMED_XXX 값을 설정합니다. IDataObject::GetData 는 이러한 데이터 전송 메커니즘 중 하나를 선택하고 적절한 STGMEDIUM 구조를 반환합니다. instance 경우 tymed는 일반적으로 TYMED_HGLOBAL | 로 설정됩니다. TYMED_ISTREAM | 세 가지 Shell 데이터 전송 메커니즘 중 하나라도 요청하도록 TYMED_ISTORAGE.

참고

여러 CFSTR_FILECONTENTS 형식이 있을 수 있으므로 FORMATETC 구조체의 cfFormattymed 멤버는 반환해야 하는 STGMEDIUM 구조체 IDataObject::GetData를 나타내기에 충분하지 않습니다. CFSTR_FILECONTENTS 형식의 경우 IDataObject::GetData는 올바른 STGMEDIUM 구조를 반환하기 위해 FORMATETC 구조체의 lIndex 멤버도 검사해야 합니다.

 

CFSTR_INDRAGLOOP 형식은 개체 데이터의 메모리 집약적 렌더링을 피하면서 대상에서 끌어서 놓기 루프의 상태 검사 수 있도록 데이터 개체에 배치됩니다. 형식의 데이터는 데이터 개체가 끌기 루프 내에 있는 경우 0이 아닌 값으로 설정된 DWORD 값입니다. 데이터가 삭제된 경우 형식의 데이터 값은 0으로 설정됩니다. 대상이 이 형식을 요청하고 원본에서 로드하지 않은 경우 IDataObject::GetData 는 원본이 값이 0인 형식을 로드한 것처럼 응답해야 합니다.

커서가 대상 창 위에 있는 동안 대상은 끌어서 놓기 도우미 개체 를 사용하여 끌기 이미지를 지정할 수 있습니다. 끌어서 놓기 도우미 개체는 IDataObject::SetData 를 호출하여 프로세스 간 지원에 사용되는 데이터 개체에 프라이빗 형식을 로드합니다. 나중에 IDataObject::GetData 를 호출하여 검색합니다. 끌어서 놓기 도우미 개체를 지원하려면 Shell Data Object 구현이 요청될 때 임의의 프라이빗 형식을 반환할 수 있어야 합니다.

IDropSource 구현

원본은 IDropSource 인터페이스를 노출하는 개체를 만들어야 합니다. 이 인터페이스를 사용하면 원본이 커서의 현재 위치를 나타내는 끌기 이미지를 업데이트하고 끌어서 놓기 작업을 종료하는 방법에 대한 피드백을 시스템에 제공할 수 있습니다. IDropSource 에는 GiveFeedbackQueryContinueDrag라는 두 가지 메서드가 있습니다.

GiveFeedback 메서드

끌어서 놓기 루프에 있는 동안 드롭 소스는 커서 위치를 추적하고 적절한 끌기 이미지를 표시합니다. 그러나 경우에 따라 끌어서 놓기 대상의 창 위에 있을 때 끌어서 놓기 이미지의 모양을 변경할 수 있습니다.

커서가 대상 창에 들어가거나 나가고 대상 창 위로 이동하는 동안 시스템은 대상의 IDropTarget 인터페이스를 주기적으로 호출합니다. 대상은 GiveFeedback 메서드를 통해 원본으로 전달되는 DROPEFFECT 값으로 응답합니다. 적절한 경우 원본은 DROPEFFECT 값에 따라 커서의 모양을 수정할 수 있습니다. 자세한 내용은 GiveFeedbackDoDragDrop 참조를 참조하세요.

QueryContinueDrag 메서드

데이터 개체가 끌기 루프에 있는 동안 마우스 단추 또는 키보드 상태가 변경되면 이 메서드가 호출됩니다. ESC 키를 눌렀는지 여부를 소스에 알리고 Ctrl 또는 Shift와 같은 키보드 한정자 키의 현재 상태를 제공합니다. QueryContinueDrag 메서드의 반환 값은 다음 세 가지 작업 중 하나를 지정합니다.

  • S_ok. 끌기 작업 계속
  • DRAGDROP_S_DROP. 데이터를 삭제합니다. 그런 다음 시스템은 대상의 IDropTarget::D rop 메서드를 호출합니다.
  • DRAGDROP_S_CANCEL. 데이터를 삭제하지 않고 끌기 루프를 종료합니다. 이 값은 일반적으로 ESCAPE 키를 누른 경우 반환됩니다.

자세한 내용은 QueryContinueDragDoDragDrop 참조를 참조하세요.

대상에서 데이터 개체를 처리하는 방법

대상은 클립보드에서 데이터 개체를 검색하거나 사용자가 대상 창에 놓으면 데이터 개체를 받습니다. 그런 다음 대상은 데이터 개체에서 데이터를 추출할 수 있습니다. 필요한 경우 대상은 데이터 개체에 작업 결과를 알릴 수도 있습니다. 셸 데이터 전송 전에 삭제 대상은 작업에 대비해야 합니다.

  1. 대상은 RegisterClipboardFormat 을 호출하여 데이터 개체에 포함될 수 있는 CF_HDROP 이외의 모든 Shell 형식에 유효한 클립보드 형식 값을 가져와야 합니다. CF_HDROP 이미 유효한 클립보드 형식이며 등록할 필요가 없습니다.
  2. 끌어서 놓기 작업을 지원하려면 대상이 IDropTarget 인터페이스를 구현하고 대상 창을 등록해야 합니다. 대상 창을 등록하기 위해 대상은 RegisterDragDrop 을 호출하고 창의 핸들과 IDropTarget 인터페이스 포인터를 전달합니다.

클립보드 전송의 경우 대상은 데이터 개체가 클립보드에 배치되었다는 알림을 받지 않습니다. 일반적으로 애플리케이션은 애플리케이션의 도구 모음에서 붙여넣기 단추를 클릭하는 등의 사용자 작업으로 개체가 클립보드에 있다는 알림을 받습니다. 그런 다음 대상은 OleGetClipboard를 호출하여 클립보드에서 데이터 개체의 IDataObject 포인터를 검색합니다. 끌어서 놓기 데이터 전송의 경우 시스템은 대상의 IDropTarget 인터페이스를 사용하여 대상에 데이터 전송 진행률에 대한 정보를 제공합니다.

  • 커서가 대상 창에 들어가면 시스템에서 IDropTarget::D ragEnter 를 호출합니다.
  • 시스템은 커서가 대상 창을 통과할 때 IDropTarget::D ragOver 를 주기적으로 호출하여 대상에 현재 커서 위치를 지정합니다.
  • 커서가 대상 창을 벗어나면 시스템에서 IDropTarget::D ragLeave 를 호출합니다.
  • 사용자가 대상 창에서 데이터 개체를 삭제하면 시스템에서 IDropTarget::D rop 을 호출합니다.

이러한 메서드를 구현하는 방법에 대한 자세한 내용은 IDropTarget을 참조하세요.

데이터가 삭제되면 IDropTarget::D rop 은 대상에 데이터 개체의 IDataObject 인터페이스에 대한 포인터를 제공합니다. 그런 다음 대상은 이 인터페이스를 사용하여 데이터 개체에서 데이터를 추출합니다.

데이터 개체에서 셸 데이터 추출

클립보드에서 데이터 개체를 삭제하거나 검색하면 대상에서 필요한 데이터를 추출할 수 있습니다. 추출 프로세스의 첫 번째 단계는 일반적으로 데이터 개체에 포함된 형식을 열거하는 것입니다.

  • IDataObject::EnumFormatEtc를 호출합니다. 데이터 개체는 표준 OLE 열거형 개체를 만들고 해당 IEnumFORMATETC 인터페이스에 대한 포인터를 반환합니다.
  • IEnumFORMATETC 메서드를 사용하여 데이터 개체에 포함된 형식을 열거합니다. 이 작업은 일반적으로 개체에 포함된 각 형식에 대해 하나의 FORMATETC 구조를 검색합니다. 그러나 열거형 개체는 일반적으로 데이터 개체에 포함된 형식 수에 관계없이 CFSTR_FILECONTENTS 형식에 대해 하나의 FORMATETC 구조만 반환합니다.
  • 추출할 형식을 하나 이상 선택하고 FORMATETC 구조를 저장합니다.

특정 형식을 검색하려면 연결된 FORMATETC 구조를 IDataObject::GetData에 전달합니다. 이 메서드는 데이터에 대한 액세스를 제공하는 STGMEDIUM 구조를 반환합니다. 특정 데이터 전송 메커니즘을 지정하려면 FORMATETC 구조체의 tymed 값을 해당 TYMED_XXX 값으로 설정합니다. 데이터 개체에 데이터 전송 메커니즘을 선택하도록 요청하기 위해 대상은 대상이 처리할 수 있는 모든 데이터 전송 메커니즘에 대해 TYMED_XXX 값을 설정합니다. 데이터 개체는 이러한 데이터 전송 메커니즘 중 하나를 선택하고 적절한 STGMEDIUM 구조를 반환합니다.

대부분의 형식에서 대상은 사용 가능한 형식을 열거할 때 받은 FORMATETC 구조를 전달하여 데이터를 검색할 수 있습니다. 이 규칙의 한 가지 예외는 CFSTR_FILECONTENTS. 데이터 개체는 이 형식의 여러 인스턴스를 포함할 수 있으므로 열거자가 반환하는 FORMATETC 구조는 추출하려는 특정 형식과 일치하지 않을 수 있습니다. cfFormattymed 멤버를 지정하는 것 외에도 lIndex 멤버를 파일의 인덱스 값으로 설정해야 합니다. 자세한 내용은 셸 데이터 전송 시나리오 처리의 파일에서 CFSTR_FILECONTENTS 형식을 사용하여 데이터 추출 섹션을 참조하세요.

데이터 추출 프로세스는 반환된 STGMEDIUM 구조체에 포함된 포인터의 형식에 따라 달라집니다. 구조체에 IStream 또는 IStorage 인터페이스에 대한 포인터가 포함된 경우 인터페이스 메서드를 사용하여 데이터를 추출합니다. 전역 메모리 개체에서 데이터를 추출하는 프로세스는 다음 섹션에서 설명합니다.

데이터 개체에서 전역 메모리 개체 추출

대부분의 Shell 데이터 형식은 전역 메모리 개체 형식입니다. 다음 절차를 사용하여 데이터 개체에서 전역 메모리 개체가 포함된 형식을 추출하고 해당 데이터를 지역 변수에 할당합니다.

  1. FORMATETC 구조를 만듭니다. cfFormat 멤버를 적절한 클립보드 형식 값으로 설정하고 tymed 멤버를 TYMED_HGLOBAL.

  2. STGMEDIUM 구조를 만듭니다.

  3. IDataObject::GetData를 호출하고 FORMATETCSTGMEDIUM 구조체에 포인터를 전달합니다.

    IDataObject::GetData가 반환되면 STGMEDIUM 구조체에는 데이터가 포함된 전역 메모리 개체에 대한 포인터가 포함됩니다.

  4. GlobalLock을 호출하고 STGMEDIUM 구조체의 hGlobal 멤버를 전달하여 데이터를 지역 변수에 할당합니다.

  5. GlobalUnlock을 호출하여 전역 메모리 개체에 대한 잠금을 해제합니다.

  6. ReleaseStgMedium을 호출하여 전역 메모리 개체를 해제합니다.

참고

ReleaseStgMedium을 사용하여 GlobalFree가 아닌 전역 메모리 개체를 해제해야 합니다.

 

다음 예제에서는 데이터 개체에서 전역 메모리 개체로 저장된 DWORD 값을 추출하는 방법을 보여줍니다. pdtobj 매개 변수는 데이터 개체의 IDataObject 인터페이스에 대한 포인터이고 cf는 원하는 데이터를 식별하는 클립보드 형식이며 pdwOut은 데이터 값을 반환하는 데 사용됩니다.

STDAPI DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD *pdwOut)
{    STGMEDIUM medium;
   FORMATETC fmte = {(CLIPFORMAT) cf, NULL, DVASPECT_CONTENT, -1, 
       TYMED_HGLOBAL};
    HRESULT hres = pdtobj->GetData(&fmte, &medium);
    if (SUCCEEDED(hres))
   {
       DWORD *pdw = (DWORD *)GlobalLock(medium.hGlobal);
       if (pdw)
       {
           *pdwOut = *pdw;
           GlobalUnlock(medium.hGlobal);
       }
       else
       {
           hres = E_UNEXPECTED;
       }
       ReleaseStgMedium(&medium);
   }
   return hres;
}

IDropTarget 구현

시스템은 IDropTarget 인터페이스를 사용하여 커서가 대상 창 위에 있는 동안 대상과 통신합니다. 대상의 응답은 IDropSource 인터페이스를 통해 원본으로 전달됩니다. 응답에 따라 원본은 데이터를 나타내는 아이콘을 수정할 수 있습니다. 놓기 대상이 데이터 아이콘을 지정해야 하는 경우 끌어서 놓기 도우미 개체를 만들어서 지정할 수 있습니다.

기존의 끌어서 놓기 작업을 사용하면 대상은 IDropTarget::D roppdwEffect 매개 변수를 적절한 DROPEFFECT 값으로 설정하여 데이터 개체에 작업 결과를 알립니다. Shell 데이터 개체를 사용하면 대상에서 IDataObject::SetData를 호출해야 할 수도 있습니다. 다른 데이터 전송 시나리오에 대해 대상이 어떻게 대응해야 하는지에 대한 자세한 내용은 셸 데이터 전송 시나리오 처리를 참조하세요.

다음 섹션에서는 IDropTarget::D ragEnter, IDropTarget::D ragOverIDropTarget::D rop 메서드를 구현하는 방법을 간략하게 설명합니다. 자세한 내용은 참조 설명서를 참조하세요.

DragEnter 메서드

커서가 대상 창에 들어갈 때 시스템은 IDropTarget::D ragEnter 메서드를 호출합니다. 해당 매개 변수는 대상에 커서 위치, Ctrl 키와 같은 키보드 한정자 키의 상태 및 데이터 개체의 IDataObject 인터페이스에 대한 포인터를 제공합니다. 대상은 해당 인터페이스를 사용하여 데이터 개체에 포함된 형식을 허용할 수 있는지 여부를 결정합니다. 가능한 경우 일반적으로 pdwEffect 값은 변경되지 않습니다. 데이터 개체의 데이터를 수락할 수 없는 경우 pdwEffect 매개 변수를 DROPEFFECT_NONE 설정합니다. 시스템은 이 매개 변수의 값을 데이터 개체의 IDropSource 인터페이스에 전달하여 적절한 끌기 이미지를 표시할 수 있도록 합니다.

대상은 삭제되기 전에 IDataObject::GetData 메서드를 사용하여 셸 데이터를 렌더링하면 안 됩니다. 이러한 각 발생에 대해 개체의 데이터를 완전히 렌더링하면 끌기 커서가 중단될 수 있습니다. 이 문제를 방지하기 위해 일부 Shell 개체는 CFSTR_INDRAGLOOP 형식을 포함합니다. 이 형식을 추출하면 대상은 개체 데이터의 메모리 집약적 렌더링을 피하면서 끌기 루프의 상태 검사 수 있습니다. 형식의 데이터 값은 데이터 개체가 끌기 루프 내에 있는 경우 0이 아닌 값으로 설정된 DWORD 입니다. 데이터가 삭제된 경우 형식의 데이터 값은 0으로 설정됩니다.

대상에서 데이터 개체의 데이터를 수락할 수 있는 경우 grfKeyState 를 검사하여 정상적인 놓기 동작을 수정하기 위해 한정자 키를 눌렀는지 여부를 확인해야 합니다. instance 경우 기본 작업은 일반적으로 이동이지만 Ctrl 키를 눌렀을 때 일반적으로 복사 작업을 나타냅니다.

커서가 대상 창 위에 있는 동안 대상은 끌어서 놓기 도우미 개체 를 사용하여 데이터 개체의 끌기 이미지를 자체 이미지로 바꿀 수 있습니다. 이 경우 IDropTarget::D ragEnterIDropTargetHelper::D ragEnter 를 호출하여 DragEnter 매개 변수에 포함된 정보를 끌어서 놓기 도우미 개체에 전달해야 합니다.

DragOver 메서드

커서가 대상 창 내에서 이동하면 시스템에서 IDropTarget::D ragOver 메서드를 주기적으로 호출합니다. 해당 매개 변수는 대상에 커서의 위치와 Ctrl 키와 같은 키보드 한정자 키의 상태를 제공합니다. IDropTarget::D ragOverIDropTarget::D ragEnter와 거의 동일한 책임을 가지며 구현은 일반적으로 매우 유사합니다.

대상이 끌어서 놓기 도우미 개체를 사용하는 경우 IDropTarget::D ragOverIDropTargetHelper::D ragOver 를 호출하여 DragOver 매개 변수에 포함된 정보를 끌어서 놓기 도우미 개체로 전달해야 합니다.

Drop 메서드

시스템은 IDropTarget::D rop 메서드를 호출하여 일반적으로 마우스 단추를 해제하여 사용자가 데이터를 삭제했음을 대상에 알립니다. IDropTarget::D rop 에는 IDropTarget::D ragEnter와 동일한 매개 변수가 있습니다. 대상은 일반적으로 데이터 개체에서 하나 이상의 형식을 추출하여 응답합니다. 완료되면 대상은 pdwEffect 매개 변수를 작업의 결과를 나타내는 DROPEFFECT 값으로 설정해야 합니다. 일부 유형의 Shell 데이터 전송의 경우 대상은 IDataObject::SetData 를 호출하여 작업 결과에 대한 추가 정보가 포함된 형식을 데이터 개체에 전달해야 합니다. 자세한 내용은 셸 데이터 전송 시나리오 처리를 참조하세요.

대상이 끌어서 놓기 도우미 개체를 사용하는 경우 IDropTarget::D ropIDropTargetHelper::D rop 을 호출하여 IDropTargetHelper::D ragOver 매개 변수에 포함된 정보를 끌어서 놓기 도우미 개체로 전달해야 합니다.

끌어서 놓기 도우미 개체 사용

대상 창 위에 있는 동안 대상에서 끌어서 놓기 이미지를 지정할 수 있도록 Shell에서 끌어서 놓기 도우미 개체(CLSID_DragDropHelper)를 내보냅니다. 끌어서 놓기 도우미 개체를 사용하려면 CLSID_DragDropHelper CLSID(클래스 식별자)를 사용하여 CoCreateInstance 를 호출하여 in-process 서버 개체를 만듭니다. 끌어서 놓기 도우미 개체는 다음과 같은 방식으로 사용되는 두 인터페이스를 노출합니다.

  • IDragSourceHelper 인터페이스를 사용하면 놓기 대상이 데이터 개체를 나타내는 아이콘을 지정할 수 있습니다.
  • IDropTargetHelper 인터페이스를 사용하면 놓기 대상이 커서 위치의 끌어서 놓기 도우미 개체에 알리고 데이터 아이콘을 표시하거나 숨길 수 있습니다.

IDragSourceHelper 인터페이스 사용

IDragSourceHelper 인터페이스는 끌어서 놓기 도우미 개체에 의해 노출되므로 드롭 대상이 커서가 대상 창 위에 있는 동안 표시될 이미지를 제공할 수 있습니다. IDragSourceHelper 는 끌기 이미지로 사용할 비트맵을 지정하는 두 가지 다른 방법을 제공합니다.

  • 창이 있는 놓기 대상은 IDragSourceHelper::InitializeFromWindow를 사용하여 끌어서 놓기 도우미 개체를 초기화하여 DI_GETDRAGIMAGE 창 메시지를 등록할 수 있습니다. 대상이 DI_GETDRAGIMAGE 메시지를 받으면 처리기는 메시지의 lParam 값으로 전달되는 SHDRAGIMAGE 구조체에 끌어서 놓습니다.
  • 창 없는 놓기 대상은 IDragSourceHelper::InitializeFromBitmap을 사용하여 끌어서 놓기 도우미 개체를 초기화할 때 비트맵을 지정합니다.

IDropTargetHelper 인터페이스 사용

이 인터페이스를 사용하면 커서가 대상에 들어오거나 떠날 때 놓기 대상이 끌어서 놓기 도우미 개체에 알릴 수 있습니다. 커서가 대상 창 위에 있는 동안 IDropTargetHelper 를 사용하면 대상에서 끌어서 놓기 도우미 개체에 대상의 IDropTarget 인터페이스를 통해 수신하는 정보를 제공할 수 있습니다.

IDropTargetHelper 메서드 중 네 가지인 IDropTargetHelper::D ragEnter, IDropTargetHelper::D ragLeave, IDropTargetHelper::D ragOverIDropTargetHelper::D rop은 동일한 이름의 IDropTarget 메서드와 연결됩니다. 끌어서 놓기 도우미 개체를 사용하려면 각 IDropTarget 메서드가 해당 IDropTargetHelper 메서드를 호출하여 정보를 끌어서 놓기 도우미 개체로 전달해야 합니다. 다섯 번째 IDropTargetHelper 메서드인 IDropTargetHelper::Show는 끌어서 놓기 도우미 개체에 끌어서 놓기 이미지를 표시하거나 숨기도록 알립니다. 이 메서드는 낮은 색 깊이 비디오 모드에서 대상 창 위로 끌 때 사용됩니다. 그러면 대상에서 창을 그리는 동안 끌기 이미지를 숨길 수 있습니다.