命令介面資料物件
資料物件是所有 Shell 資料傳輸的核心。 它主要是用來保存已傳輸資料的容器。 不過,目標也可以與資料物件通訊,以協助一些特殊類型的 Shell 資料傳輸,例如優化的移動。 本主題提供 Shell 資料物件運作方式、來源建構方式,以及目標如何處理它們的一般討論。 如需如何使用資料物件來傳輸不同類型的 Shell 資料的詳細討論,請參閱 處理殼層資料傳輸案例。
資料物件的運作方式
資料物件是元件物件模型 (COM) 物件,由資料來源建立,以將資料傳送至目標。 它們通常會包含一個以上的資料項目。 此做法有兩個原因:
- 雖然幾乎任何類型的資料都可以與資料物件一起傳輸,但來源通常不知道目標可接受的資料類型。 例如,資料可能是格式化文字檔的一部分。 雖然目標可能能夠處理複雜的格式資訊,但也可以只接受 ANSI 文字。 因此,資料物件通常會以數種不同的格式包含相同的資料。 然後,目標可以擷取其可處理的格式來擷取資料。
- 資料物件也可以包含不是來源資料版本的輔助資料項目。 這種類型的資料項目通常會提供資料傳輸作業的其他資訊。 例如,Shell 會使用輔助資料項目來指出要複製或移動檔案。
剪貼簿格式
資料物件中的每個資料項目目都有相關聯的格式,通常稱為 剪貼簿格式。 Winuser.h 中宣告了許多標準剪貼簿格式,這些格式會對應至常用的資料類型。 剪貼簿格式是整數,但通常以其對等名稱來參考,其格式為 CF_XXX。 例如,ANSI 文字的剪貼簿格式CF_TEXT。
應用程式可以藉由定義私用格式來擴充可用的剪貼簿格式範圍。 若要定義私用格式,應用程式會使用識別格式的字串呼叫 RegisterClipboardFormat 。 函式傳回的不帶正負號整數是有效的格式值,可與標準剪貼簿格式一樣使用。 不過,來源和目標都必須註冊格式,才能使用它。 除了CF_HDROP之外,用來傳輸 Shell 資料的剪貼簿格式會定義為私用格式。 它們必須先由來源和目標注冊,才能使用它們。 如需可用殼層剪貼簿格式的描述,請參閱 Shell 剪貼簿格式。
雖然有一些例外狀況,但資料物件通常只包含其支援之每個剪貼簿格式的資料項目目。 格式和資料之間的這個一對一相互關聯,可讓格式值當做相關聯資料項目的識別碼使用。 事實上,在討論資料物件的內容時,特定資料項目通常稱為「格式」,並以其格式名稱來參考。 例如,「擷取CF_TEXT格式...」等片語通常會在討論資料物件的 ANSI 文字資料項目時使用。
當置放目標收到資料物件的指標時,置放目標會列舉可用的格式,以判斷可用的資料類型。 然後它會要求一或多個可用的格式,並擷取資料。 目標從資料物件擷取 Shell 資料的特定方式會因格式而異;這會在 目標如何處理資料物件中詳細討論。
透過簡單的剪貼簿資料傳輸,資料會放在全域記憶體物件中。 該物件的位址會放在剪貼簿上,以及其格式。 剪貼簿格式會告知目標它會在相關聯的位址找到何種資料。 雖然簡單的剪貼簿傳輸很容易實作:
- 資料物件提供更有彈性的方式來傳輸資料。
- 資料物件更適合傳輸大量資料。
- 資料物件必須使用拖放作業來傳輸資料。
基於這些原因,所有 Shell 資料傳輸都會使用資料物件。 使用資料物件時,不會直接使用剪貼簿格式。 相反地,資料項目會以剪貼簿格式的一般化來識別,這是 FORMATETC 結構。
FORMATETC 結構
FORMATETC結構是剪貼簿格式的擴充版本。 如同用於殼層資料傳輸, FORMATETC 結構具有下列特性:
資料項目仍會以其剪貼簿格式來識別,格式為 cfFormat 成員。
資料傳輸不限於全域記憶體物件。 tymed成員可用來指出相關聯STGMEDIUM結構中包含的資料傳輸機制。 它會設定為其中一個 TYMED_XXX 值。
Shell 會使用 lIndex 成員及其 CFSTR_FILECONTENTS 格式,允許資料物件包含每個格式一個以上的資料項目。 如需如何使用此格式的討論,請參閱處理殼層資料傳輸案例的使用CFSTR_FILECONTENTS格式從檔案擷取資料一節。
dwAspect成員通常會設定為 DVASPECT_CONTENT。 不過,Shlobj.h 中定義了三個值,可用於 Shell 資料傳輸。
值 描述 DVASPECT_COPY 用來指出格式代表資料的複本。 DVASPECT_LINK 用來指出格式代表資料的快捷方式。 DVASPECT_SHORTNAME 與 CF_HDROP 格式搭配使用,以要求名稱縮短為 8.3 格式的檔案路徑。 ptd成員不會用於殼層資料傳輸,而且通常會設定為Null。
STGMEDIUM 結構
STGMEDIUM結構可讓您存取正在傳輸的資料。 Shell 資料支援三種資料傳輸機制:
STGMEDIUM結構的tymed成員是識別資料傳輸機制TYMED_XXX值。 第二個成員是目標用來擷取資料的指標。 指標可以是各種類型之一,視 tymed 值而定。 下表摘要說明用於 Shell 資料傳輸的三個 樣式 值及其對應的 STGMEDIUM 成員名稱。
tymed 值 | 成員名稱 | 說明 |
---|---|---|
TYMED_HGLOBAL | hGlobal | 全域記憶體物件的指標。 此指標類型通常用於傳輸少量的資料。 例如,Shell 會使用全域記憶體物件來傳輸簡短文字字串,例如檔案名或 URL。 |
TYMED_ISTREAM | pstm | IStream介面的指標。 相較于TYMED_HGLOBAL,此指標類型最適合用於大部分的 Shell 資料傳輸。 此外,TYMED_ISTREAM資料傳輸機制不需要來源以任何特定方式儲存其資料。 |
TYMED_ISTORAGE | pstg | IStorage介面的指標。 目標會呼叫 介面方法來擷取資料。 如同TYMED_ISTREAM,此指標類型需要相對較少的記憶體。 不過,因為TYMED_ISTORAGE的彈性比TYMED_ISTREAM低,所以不如常用的。 |
來源如何建立資料物件
當使用者起始 Shell 資料傳輸時,來源會負責建立資料物件並載入資料。 下列程式摘要說明程式:
- 呼叫 RegisterClipboardFormat ,以取得資料物件中將包含之每個 Shell 格式的有效剪貼簿格式值。 請記住 ,CF_HDROP 已經是有效的剪貼簿格式,不需要註冊。
- 若要傳輸每個格式,請將相關聯的資料放入全域記憶體物件,或建立物件,以透過 IStream 或 IStorage 介面存取該資料。 IStream和IStorage介面是使用標準 COM 技術所建立。 如需如何處理全域記憶體物件的討論,請參閱 如何將全域記憶體物件新增至資料物件。
- 為每個格式建立 FORMATETC 和 STGMEDIUM 結構。
- 具現化資料物件。
- 針對每個支援的格式呼叫 IDataObject::SetData 方法,並傳入格式的 FORMATETC 和 STGMEDIUM 結構,將資料載入資料物件。
- 透過剪貼簿資料傳輸,呼叫 OleSetClipboard 將指標放在剪貼簿上資料物件的 IDataObject 介面。 針對拖放傳輸,請呼叫DoDragDrop來起始拖曳迴圈。 卸載資料時, IDataObject 指標會傳遞至置放目標,結束拖曳迴圈。
資料物件現在已準備好傳送至目標。 對於剪貼簿資料傳輸,物件只會保留到目標呼叫 OleGetClipboard來要求它為止。 對於拖放資料傳輸,資料物件負責建立圖示來代表資料,並在使用者移動游標時移動它。 當物件位於拖曳迴圈中時,來源會透過其 IDropSource 介面接收狀態資訊。 如需進一步的討論,請參閱 實作 IDropSource。
如果目標從剪貼簿擷取資料物件,來源就不會收到任何通知。 當物件由拖放作業在目標上卸載時,呼叫以起始拖曳迴圈的 DoDragDrop 函式將會傳回。
如何將全域記憶體物件新增至資料物件
許多 Shell 資料格式都是全域記憶體物件的形式。 使用下列程式建立包含全域記憶體物件的格式,並將它載入資料物件:
- 建立 FORMATETC 結構。 將 cfFormat 成員設定為適當的剪貼簿格式值,並將 tymed 成員設定為 TYMED_HGLOBAL。
- 建立 STGMEDIUM 結構。 將 tymed 成員設定為 TYMED_HGLOBAL。
- 呼叫 GlobalAlloc 以配置適當大小的記憶體區塊,以建立全域記憶體物件。
- 指派要傳送至 GlobalAlloc所傳回位址的資料區塊。
- 將全域記憶體物件的位址指派給STGMEDIUM結構的hGlobal成員。
- 呼叫 IDataObject::SetData 並傳入在先前步驟中建立 的 FORMATETC 和 STGMEDIUM 結構,以將格式載入資料物件。
下列範例函式會建立包含 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、 EnumFormatEtc和 GetData實作三個最重要的方法。 如需其他方法的討論,請參閱 IDataObject 參考。
SetData 方法
IDataObject::SetData方法的主要功能是允許來源將資料載入資料物件。 針對要包含的每個格式,來源會建立 FORMATETC 結構來識別格式和 STGMEDIUM 結構,以保存資料的指標。 然後,來源會呼叫物件的 IDataObject::SetData 方法,並傳入格式的 FORMATETC 和 STGMEDIUM 結構。 方法必須儲存這項資訊,以便在目標呼叫 IDataObject::GetData 以從物件擷取資料時可供使用。
不過,傳輸檔案時,Shell 通常會將每個檔案的資訊放入個別 的CFSTR_FILECONTENTS 格式。 為了區分不同的檔案,每個檔案FORMATETC結構的lIndex成員會設定為可識別特定檔案的索引值。 您的 IDataObject::SetData 實作 必須能夠儲存多個只與其 lIndex 成員不同的CFSTR_FILECONTENTS格式。
當游標位於目標視窗上方時,目標可以使用 拖放協助程式物件 來指定拖曳影像。 拖放協助程式物件會呼叫 IDataObject::SetData ,將私用格式載入到用於跨進程支援的資料物件中。 若要支援拖放協助程式物件,您的 IDataObject::SetData 實作必須能夠接受並儲存任意的私人格式。
卸載資料之後,某些類型的 Shell 資料傳輸需要目標呼叫 IDataObject::SetData ,以提供資料物件與卸載作業結果的相關資訊。 例如,使用優化移動作業移動檔案時,目標通常會刪除原始檔案,但不需要這麼做。 目標會透過呼叫具有CFSTR_LOGICALPERFORMEDDROPEFFECT格式的IDataObject::SetData,通知資料物件是否刪除檔案。 目標也會使用數個其他 Shell 剪貼簿格式 ,將資訊傳遞至資料物件。 您的 IDataObject::SetData 實作 必須能夠辨識這些格式並適當地回應。 如需進一步的討論,請參閱 處理殼層資料傳輸案例。
EnumFormatEtc 方法
當目標收到資料物件時,通常會呼叫 FORMATETC 來判斷物件包含的格式。 方法會建立 OLE 列舉物件,並傳回物件的 IEnumFORMATETC 介面指標。 然後,目標會使用 介面來列舉可用的格式。
列舉物件應該一律依品質順序列舉可用的格式,從最佳開始。 格式的相對品質是由置放來源所定義。 一般而言,最高品質的格式包含最豐富且最完整的資料。 例如,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 結構。 例如, tymed 通常會設定為 TYMED_HGLOBAL |TYMED_ISTREAM |TYMED_ISTORAGE要求三個殼層資料傳輸機制中的任何一種。
注意
因為可以有多個CFSTR_FILECONTENTS格式,所以 FORMATETC結構的cfFormat和tymed成員不足以指出應該傳回哪些STGMEDIUM結構IDataObject::GetData。 針對CFSTR_FILECONTENTS格式, IDataObject::GetData 也必須檢查 FORMATETC 結構的 lIndex 成員,才能傳回正確的 STGMEDIUM 結構。
CFSTR_INDRAGLOOP格式會放在資料物件中,以允許目標檢查拖放迴圈的狀態,同時避免大量轉譯物件的資料。 格式的資料是 DWORD 值,如果資料物件位於拖曳迴圈內,則會設定為非零值。 如果資料已卸載,格式的資料值會設定為零。 如果目標要求此格式且來源尚未載入, IDataObject::GetData 應該會回應,就像來源已載入值為零的格式一樣。
當游標位於目標視窗上方時,目標可以使用 拖放協助程式物件 來指定拖曳影像。 拖放協助程式物件會呼叫 IDataObject::SetData ,將私用格式載入到用於跨進程支援的資料物件中。 稍後它會呼叫 IDataObject::GetData 來擷取它們。 若要支援拖放協助程式物件,您的 Shell 資料物件實作必須在要求時傳回任意私用格式。
實作 IDropSource
來源必須建立公開 IDropSource 介面的物件。 此介面可讓來源更新指出游標目前位置的 拖曳影像 ,並提供意見反應給系統如何終止拖放作業。 IDropSource 有兩種方法: GiveFeedback 和 QueryContinueDrag。
GiveFeedback 方法
在拖曳迴圈中,置放來源負責追蹤游標位置並顯示適當的拖曳影像。 不過,在某些情況下,您可能會想要變更拖曳影像在置放目標視窗上方的外觀。
當游標進入或離開目標視窗,並在移動目標視窗時,系統會定期呼叫目標的 IDropTarget 介面。 目標會以 DROPEFFECT 值回應,這個值會透過 GiveFeedback 方法轉送至來源。 如果適當,來源可以根據 DROPEFFECT 值修改資料指標的外觀。 如需詳細資訊,請參閱 GiveFeedback 和 DoDragDrop 參考。
QueryContinueDrag 方法
如果在拖曳迴圈中的資料物件時,滑鼠按鍵或鍵盤狀態變更,就會呼叫這個方法。 它會通知來源是否按下 ESC 鍵,並提供鍵盤修飾詞按鍵的目前狀態,例如 CTRL 或 SHIFT。 QueryContinueDrag方法的傳回值會指定下列三個動作之一:
- S_OK。 繼續拖曳作業
- DRAGDROP_S_DROP。 卸載資料。 然後,系統會呼叫目標的 IDropTarget::D rop 方法。
- DRAGDROP_S_CANCEL。 終止拖曳迴圈而不卸載資料。 如果按下 ESCAPE 鍵,通常會傳回這個值。
如需進一步的討論,請參閱 QueryContinueDrag 和 DoDragDrop 參考。
目標如何處理資料物件
當目標從剪貼簿擷取資料物件或使用者將其卸載至目標視窗時,目標就會接收資料物件。 然後,目標可以從資料物件擷取資料。 如有必要,目標也可以通知資料物件作業的結果。 在 Shell 資料傳輸之前,卸載目標必須自行準備作業:
- 目標必須呼叫 RegisterClipboardFormat ,以取得資料物件中可能包含之所有 Shell 格式的有效剪貼簿格式值,而非 CF_HDROP。 CF_HDROP已經是有效的剪貼簿格式,不需要註冊。
- 若要支援拖放作業,目標必須實作 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 結構可能不會對應至您想要擷取的特定格式。 除了指定 cfFormat 和 tymed 成員之外,您也必須將 lIndex 成員設定為檔案的索引值。 如需進一步的討論,請參閱處理殼層資料傳輸案例的使用CFSTR_FILECONTENTS格式從檔案擷取資料一節
資料擷取程式取決於傳回 STGMEDIUM 結構所包含的指標類型。 如果結構包含 IStream 或 IStorage 介面的指標,請使用 介面方法來擷取資料。 下一節將討論從全域記憶體物件擷取資料的程式。
從資料物件擷取全域記憶體物件
許多 Shell 資料格式都是全域記憶體物件的形式。 使用下列程式,從資料物件擷取包含全域記憶體物件的格式,並將其資料指派給區域變數:
建立 FORMATETC 結構。 將 cfFormat 成員設定為適當的剪貼簿格式值,並將 tymed 成員設定為 TYMED_HGLOBAL。
建立空 的 STGMEDIUM 結構。
呼叫 IDataObject::GetData,並傳入 FORMATETC 和 STGMEDIUM 結構的指標。
當 IDataObject::GetData傳回時,STGMEDIUM結構會包含包含資料的全域記憶體物件指標。
藉由呼叫GlobalLock並傳入STGMEDIUM結構的hGlobal成員,將資料指派給區域變數。
呼叫 GlobalUnlock 以釋放全域記憶體物件的鎖定。
呼叫 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 rop的參數設定為適當的DROPEFFECT值,以通知資料物件作業的結果。 使用 Shell 資料物件時,目標可能也需要呼叫 IDataObject::SetData。 如需目標應如何回應不同資料傳輸案例的討論,請參閱 處理殼層資料傳輸案例。
下列各節簡短討論如何實作 IDropTarget::D ragEnter、 IDropTarget::D ragOver和 IDropTarget::D rop 方法。 如需詳細資訊,請參閱參考檔。
DragEnter 方法
當游標進入目標視窗時,系統會呼叫 IDropTarget::D ragEnter 方法。 其參數會提供目標資料指標的位置、鍵盤修飾詞鍵的狀態,例如 CTRL 鍵,以及資料物件的 IDataObject 介面指標。 目標負責使用該介面來判斷它是否可以接受資料物件所包含的任何格式。 如果可以,它通常會讓 pdwEffect 的值保持不變。 如果無法接受資料物件中的任何資料,則會將 pdwEffect 參數設定為 DROPEFFECT_NONE。 系統會將此參數的值傳遞至資料物件的 IDropSource 介面,以允許它顯示適當的拖曳影像。
目標不應該使用 IDataObject::GetData 方法來轉譯 Shell 資料,然後再卸載。 完整呈現每個這類專案的物件資料,可能會導致拖曳游標停止。 為了避免這個問題,某些 Shell 物件包含 CFSTR_INDRAGLOOP 格式。 藉由擷取此格式,目標可以檢查拖曳迴圈的狀態,同時避免物件資料的記憶體密集轉譯。 格式的資料值是 DWORD ,如果資料物件位於拖曳迴圈內,則會設定為非零值。 如果資料已卸載,格式的資料值會設定為零。
如果目標可以接受來自資料物件的資料,它應該檢查 grfKeyState ,以判斷是否已按下任何修飾詞鍵來修改一般置放行為。 例如,預設作業通常是移動,但按住 CTRL 鍵通常表示複製作業。
當游標位於目標視窗上方時,目標可以使用 拖放協助程式物件 ,以自己的拖曳影像取代資料物件的拖曳影像。 如果是, IDropTarget::D ragEnter 應該呼叫 IDropTargetHelper::D ragEnter ,將 DragEnter 參數中包含的資訊傳遞至拖放協助程式物件。
DragOver 方法
當游標在目標視窗中移動時,系統會定期呼叫 IDropTarget::D ragOver 方法。 其參數會提供目標,其中包含游標的位置,以及鍵盤修飾詞鍵的狀態,例如 CTRL 鍵。 IDropTarget::D ragOver 與 IDropTarget::D ragEnter具有相同的責任,而且實作通常非常類似。
如果目標使用拖放協助程式物件, IDropTarget::D ragOver 應該呼叫 IDropTargetHelper::D ragOver ,將 DragOver 參數中包含的資訊轉送至拖放協助程式物件。
Drop 方法
系統會呼叫 IDropTarget::D rop 方法來通知目標使用者已卸載資料,通常是藉由釋放滑鼠按鍵。 IDropTarget::D rop 具有與 IDropTarget::D ragEnter相同的參數。 目標通常會藉由從資料物件擷取一或多個格式來回應。 完成時,目標應將 pdwEffect 參數設定為 DROPEFFECT 值,指出作業的結果。 對於某些類型的 Shell 資料傳輸,目標也必須呼叫 IDataObject::SetData ,以將作業結果的其他資訊傳遞給資料物件的格式。 如需詳細討論,請參閱 處理殼層資料傳輸案例。
如果目標使用拖放協助程式物件, IDropTarget::D rop 應該呼叫 IDropTargetHelper::D rop ,將 IDropTargetHelper::D ragOver 參數中包含的資訊轉送至拖放協助程式物件。
使用拖放協助程式物件
Shell 會匯出拖放協助程式物件 (CLSID_DragDropHelper) ,以允許目標在目標視窗上方時指定拖曳影像。 若要使用拖放協助程式物件,請呼叫 CoCreateInstance 與 clSID) 的類別識別碼 (CLSID_DragDropHelper CLSID) ,以建立同進程伺服器物件。 拖放協助程式物件會公開兩個介面,這些介面會以下列方式使用:
- 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 ragOver和 IDropTargetHelper::D rop— 與相同名稱的 IDropTarget 方法相關聯。 若要使用拖放協助程式物件,每個 IDropTarget 方法都應該呼叫對應的IDropTargetHelper方法,以將資訊轉送至拖放協助程式物件。 第五個 IDropTargetHelper 方法 IDropTargetHelper::Show會通知拖放協助程式物件以顯示或隱藏拖曳影像。 在低色彩深度視訊模式中拖曳到目標視窗上方時,會使用這個方法。 它可讓目標在繪製視窗時隱藏拖曳影像。