MSDN 2005 -> Win32 和 COM 開發 -> User Interface -> Windows User Experience -> Windows Shell -> Windows Shell -> Shell Programmer's Guide -> Shell Basics -> Transferring Shell Objects with Drag-and-Drop and the Clipboard
很多應用程式可以讓使用者通過滑鼠拖放或者剪貼簿把資料轉送到其他程式中。像檔案和檔案夾這樣的Shell對象是可以傳輸的眾多資料類型之一。Shell資料轉送可以發生在兩個應用程式間,當然也可以在應用程式與案頭或者資源管理員間傳輸資料。
雖然最經常傳輸的Shell對象是檔案,但Shell名字空間中的任何對象都是可以傳輸的。比如說,程式可能需要傳輸檔案到像資源回收筒這樣的虛擬資料夾中,或者從非微軟名字空間擴充處接受對象。如果要實現名字空間擴充,必須使它具有作為拖放源和拖放目標的正確行為。
本文討論如何?用拖放和剪貼簿傳輸Shell對象。
Shell對象是如何被拖放的
應用程式通常要為使用者提供傳輸Shell資料的方法。比如說:
- 從案頭或者資源管理員中拖動檔案放置到應用程式中
- 在資源管理員中複製檔案到剪貼簿,然後粘貼到應用程式中
- 從應用程式中拖動檔案放置到資源回收筒中
關於如何處理這些情況和其他情況的詳細討論,見Handling Shell Data Transfer Scenarios,它討論了Shell資料轉送的一般原理。
Windows為應用程式提供了兩種傳輸Shell資料的標準方法:
- 使用者剪下或者複製Shell資料,比如說一個或者多個檔案,到剪貼簿中,然後其他應用程式從剪貼簿擷取資料。
- 使用者從源應用程式中拖動一個代表資料的表徵圖,放置到屬於目標的視窗中。
在這兩種情況中,要傳輸的資料都包含在資料對象中。資料對象是暴露了IDataObject介面的COM對象。一般來說,所有Shell資料轉送都必須遵循三個必要的步驟:
- 傳輸源建立代表要傳輸的資料的資料對象
- 傳輸目標接收到資料對象的IDataObject介面指標
- 傳輸目標調用IDataObject介面的方法擷取資料
剪貼簿和拖放資料轉送的主要不同在於IDataObject指標如何從源傳遞到目標。
剪貼簿資料轉送
剪貼簿是傳輸Shell資料的最簡單方法。基本的傳輸過程跟標準剪貼簿資料轉送類似。然而,因為傳輸的是資料對象指標,而不是資料本身,所以必須使用OLE剪貼簿API,而不是標準剪貼簿API。下面是使用OLE剪貼簿API傳輸Shell資料的基本過程:
- 傳輸源建立包含資料的資料對象
- 傳輸源調用OleSetClipboard把資料對象的IDataObject指標放到剪貼簿中
- 傳輸目標調用OleGetClipboard擷取資料對象的IDataObject指標
- 傳輸目標調用IDataObject::GetData方法擷取資料
- 對於某些Shell資料轉送,傳輸目標必須調用IDataObject::SetData方法為資料對象提供關於資料轉送結果的反饋。關於這種操作的樣本,見Handling Optimized Move Operations。
拖放資料轉送
雖然比剪貼簿資料轉送實現起來複雜一些,但拖放資料轉送具備下列優點:
- 拖放資料轉送可以通過簡單的滑鼠移動完成,比剪貼簿操作靈活直觀
- 拖放為使用者提供了操作的可視表示。使用者可以跟蹤把表徵圖從源移動到目標的過程
- 拖放會在資料可用的時候通知拖放目標
拖放操作也用資料對象傳輸資料,然而放置源必須提供多於剪貼簿傳輸所需的功能:
- 放置源必須建立暴露IDropSource介面的對象。操作進行過程中系統用IDropSource與拖放源進行通訊。
- 拖放資料對象要負責跟蹤游標移動並且顯示代表資料對象的表徵圖
放置目標也必須提供多於處理剪貼簿傳輸所需的功能:
- 放置目標必須暴露IDropTarget介面。游標位於目標視窗上時,系統使用IDropTarget為目標提供游標位置之類的資訊,並且在放開資料時通知目標。
- 拖放目標必須通過調用RegisterDragDrop向系統註冊。這個函數向系統提供目標視窗控制代碼和到目標應用程式IDropTarget介面的指標。
注意: 對於拖放操作,程式必須用OleInitialize初始化COM,而不是CoInitialize。
下面是典型的用拖放進行Shell資料轉送的必要步驟:
- 拖放目標調用RegisterDragDrop為系統提供到其IDropTarget介面的指標,並且註冊一個視窗為拖放目標。
- 使用者開始拖放操作時,拖放源建立資料對象,並且通過調用DoDragDrop發起一個拖動迴圈。
- 游標位於目標視窗上時,系統通過調用目標的IDropTarget介面方法通知目標。游標進入目標視窗時,系統調用IDropTarget::DragEnter;而游標滑過目標視窗時,系統調用IDropTarget::DragOver。這兩個方法都為放置目標提供游標位置和CTRL、ALT等鍵盤修飾鍵狀態資訊。游標離開目標視窗時,系統通過IDropTarget::DragLeave通知目標。這幾個方法返回後,系統調用IDropSource介面傳遞傳回值給拖放源。
- 使用者釋放滑鼠按鍵,放置資料時,系統調用目標的IDropTarget::Drop方法,其中一個參數是資料對象的IDataObject介面指標。
- 目標調用資料對象的IDataObject::GetData方法取出資料。
- 對於某些類型的Shell資料轉送,目標還應該調用資料對象的IDataObject::SetData方法為傳輸源提供資料轉送的反饋。
- 傳輸目標完成對資料對象的操作後,就從IDropTarget::Drop返回,然後系統從傳輸源中的DoDrogDrop方法返回,通知傳輸源傳送完成。
- 對於某些資料轉送的情況,傳輸源可能需要根據DoDragDrop方法的傳回值,以及傳輸目標傳遞給資料對象的值,而進行額外的動作。比如說,如果進行的是檔案移動操作,拖放源必須檢查這兩個值以確定是否要刪除原檔案。
- 傳輸源釋放資料對象。
上述過程是Shell資料轉送的通用模型,然而Shell資料對象可以包含各種不同類型的資料,應用程式可能需要處理各種不同類型資料轉送的情況。每種資料類型和傳輸情況要求對上述過程中三個關鍵步驟進行一些不同的處理:
- 傳輸源如何構造包含Shell資料的資料對象
- 傳輸目標如何從資料對象中取出Shell資料
- 傳輸源如何完成資料轉送操作
Shell Data Object 提供了對於傳輸源如何構造Shell資料對象的一般討論,它還討論了傳輸目標如何處理資料對象。Handling Shell Data Transfer Scenarios 詳細討論了如何處理各種通用Shell資料轉送。