如何與資源管理器互動(dòng)剪切/拷貝/粘貼文件
如何與資源管理器互動(dòng)剪切/拷貝/粘貼文件 2016-06-06
一.本文將向讀者介紹下面兩個(gè)問(wèn)題的解決方案:
1,用戶在資源管理器(Windows Explorer)中剪切/拷貝(Cut/Copy)文件,然后在自己的應(yīng)用程序中進(jìn)行粘貼(Paste)操作;
2.用戶在自己的應(yīng)用程序中剪切/拷貝文件,在資源管理其中粘貼操作。
二.本文中的代碼編寫工具及測(cè)試環(huán)境:
1,VC6.0, Platform SDK(無(wú)須MFC);
2.Windows 2000。
三.概述
我們知道,在Windows中可以通過(guò)剪貼板(Clipboard)來(lái)共享和傳遞數(shù)據(jù),比如在資源管理器(Windows Explorer)中可以剪切/拷貝/粘貼文件。同樣我們也可以在自己的應(yīng)用程序中通過(guò)剪貼板來(lái)完成這些工作,從而提高我們自己的應(yīng)用程序與Windows操作系統(tǒng)之間的互操作性。但我們?nèi)绾尾拍芘c資源管理器之類的應(yīng)用程序共享和傳遞數(shù)據(jù)呢?本文提供的方法是:使用Windows本身提供的一些數(shù)據(jù)結(jié)構(gòu)和API,通過(guò)剪貼板來(lái)實(shí)現(xiàn)數(shù)據(jù)共享和傳遞。
四.實(shí)現(xiàn)方法
首先,Windows在剪切/拷貝文件時(shí)并不是把文件名稱寫入剪貼板,而是在剪貼板中放入了一個(gè)DragAndDrop文件對(duì)象,并寫入了一個(gè)狀態(tài)值來(lái)標(biāo)識(shí)操作類型(移動(dòng)/拷貝,剪切其實(shí)就是移動(dòng),如果你剪切之后并沒(méi)有粘貼,那么該文件依然存在而不會(huì)被刪除)。依據(jù)這個(gè)知識(shí),我們首先來(lái)看看在應(yīng)用程序中如何識(shí)別出Windows 資源管理器的剪切/拷貝動(dòng)作。
在使用剪貼板前,我們首先要打開它:
1
2BOOL OpenClipboard(HWND hWnd);參數(shù) hWnd 是打開剪貼板的窗口句柄,成功返回TRUE,失敗返回FALSE。
之后,可以用GetClipboardData來(lái)得到剪貼板中的數(shù)據(jù):
1HANDLEGetClipboardData(UINTuFormat);
uFormat是所需要數(shù)據(jù)的格式,例如本文拖放對(duì)象的格式為CF_HDROP。而表明該拖放對(duì)象類型(Move/Copy)的數(shù)據(jù)格式并不是Windows標(biāo)準(zhǔn)的剪貼板數(shù)據(jù)結(jié)構(gòu),而是一個(gè)簡(jiǎn)單的DWORD指針。我們可以通過(guò)下面的語(yǔ)句來(lái)注冊(cè)一下數(shù)據(jù)類型 :
1UINT uDropEffect=RegisterClipboardFormat("Preferred DropEffect");
這里返回的uDropEffect就是我們將要代入GetClipboardData函數(shù)的該數(shù)據(jù)結(jié)構(gòu)的代碼,GetClipboardData函數(shù)返回是一個(gè)句柄,這只是Windows為了統(tǒng)一性而做的工作,我們可以根據(jù)需要來(lái)轉(zhuǎn)換成相應(yīng)的數(shù)據(jù)形式,比如我們的uDropEffect就是一個(gè)DWORD指針。
前面我已經(jīng)說(shuō)過(guò)在剪貼板中放的是一個(gè)拖放對(duì)象,因此我們可以通過(guò)如下語(yǔ)句得到該對(duì)象:
1HDROP hDrop = HDROP( GetClipboardData( CF_HDROP));
如果確實(shí)存在一個(gè)hDrop對(duì)象,我們應(yīng)該取得uDropEffect的數(shù)據(jù),以便我們處理后面的文件:
1DWORD dwEffect=*((DWORD*)(GetClipboardData( uDropEffcet)));
關(guān)于這個(gè)值的含義,我們只要包含一下"OLEIDL.H"頭文件即可,在該頭文件中5種狀態(tài)的定義而本文只關(guān)注:
1
2#define DROPEFFECT_COPY ( 1 )#define DROPEFFECT_MOVE ( 2 )
因此,我們可以通過(guò)
1
2
3
4if(dwEffect & DROPEFFECT_COPY)??CopyFile(....);else (dwEffect & DROPEFFECT_MOVE)??MoveFile(...);
來(lái)完成剪切/拷貝操作。
在我們?nèi)〉胾DropEffect狀態(tài)之后,我們需要得到文件列表,得到拖放對(duì)象中的文件列表可以通過(guò)DragQueryFile來(lái)實(shí)現(xiàn):
1UINT DragQueryFile(HDROP hDrop, UINT iFile,LPTSTRlpszFile,UINTcch);
第二個(gè)參數(shù)是文件序列號(hào),可以通過(guò)將iFile置為-1的方法來(lái)得到文件數(shù)量。
最后我們給出完整的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#include < Shellapi.h >#include < oleidl.h >?....???UINTuDropEffect=RegisterClipboardFormat("Preferred DropEffect");?????if( OpenClipboard( hWnd)) {????????HDROPhDrop = HDROP( GetClipboardData( CF_HDROP));????????if( hDrop) {????????????DWORDdwEffect,*dw;????????????dw=(DWORD*)(GetClipboardData( uDropEffect));????????????if(dw==NULL)????????????????dwEffect=DROPEFFECT_COPY;????????????else????????????????dwEffect=*dw;?????????????????????charBuf[4096];????????????Buf[0] = 0;????????????UINTcFiles = DragQueryFile( hDrop, (UINT) -1, NULL, 0);????????????POINT Point;????????????charszFile[ MAX_PATH];????????????for(UINT count = 0; count < cFiles; count++ ) {????????????????DragQueryFile( hDrop, count, szFile,sizeof( szFile));????????????????lstrcat(Buf,szFile);????????????????lstrcat(Buf,"n");????????????}?????????????????if(dwEffect & DROPEFFECT_MOVE) {????????????????MessageBox(NULL,Buf,"Move Files",MB_OK);????????????}else? if(dwEffect & DROPEFFECT_COPY) {????????????????????MessageBox(NULL,Buf,"Copy Files",MB_OK);????????????}?????????????CloseClipboard();????????}????}
在這個(gè)例子中,我并沒(méi)有進(jìn)行文件操作,只是簡(jiǎn)單的顯示一個(gè)消息框,實(shí)際應(yīng)用時(shí),需要使用MoveFile和CopyFile函數(shù)來(lái)完成,本文不做討論。?
知道如何識(shí)別其他程序的剪切/拷貝 文件的動(dòng)作后,我們對(duì)該操作的數(shù)據(jù)結(jié)構(gòu)已經(jīng)很了解了,要想讓其他程序能識(shí)別我們的剪切/拷貝 文件動(dòng)作其實(shí)就是將以上數(shù)據(jù)結(jié)構(gòu)放入剪貼板的過(guò)程。
在我們這個(gè)例子中,往剪貼板中放的數(shù)據(jù)必須是內(nèi)存對(duì)象:HGLOBAL。這個(gè)對(duì)象可以通過(guò)GlobalAlloc來(lái)生成。然后使用GlobalLock就可以得到該對(duì)象的內(nèi)存地址,繼而往里面寫 數(shù)據(jù)。實(shí)際上在Win32中由于進(jìn)程擁有獨(dú)立的內(nèi)存空間,因而常規(guī)的內(nèi)存分配已經(jīng)不需要GlobalLock了,看看MSDN就知道該函數(shù)主要就是為DDE和剪貼板服務(wù)的。?
根據(jù)前面的知識(shí),要想讓其他程序識(shí)別出我們的剪切/拷貝動(dòng)作我們必須往剪貼板中放兩項(xiàng)數(shù)據(jù),現(xiàn)在就讓我們來(lái)為DropEffect準(zhǔn)備數(shù)據(jù)吧,同樣我們需要先注冊(cè)該數(shù)據(jù)格式:
1uDropEffect=RegisterClipboardFormat("Preferred DropEffect");
然后分配內(nèi)存對(duì)象并得到指針:
1
2hGblEffect=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,sizeof(DWORD));dwDropEffect=(DWORD*)GlobalLock(hGblEffect);
注意往剪貼板中放的數(shù)據(jù)必須使用GMEM_MOVEABLE標(biāo)志,最后我們?cè)O(shè)置數(shù)據(jù)并解除鎖定:
1
2
3
4
5if(COPY)??*dwDropEffect=DROPEFFECT_COPY;else?*dwDropEffect=DROPEFFECT_MOVE;GlobalUnlock(hGblEffect);
這樣我就為DropEffect準(zhǔn)備還數(shù)據(jù)了,等一會(huì)兒我們連同文件拖放對(duì)象一起放入剪貼板。建立文件拖放對(duì)象的方法與DropEffect基本相同,只是文件拖放對(duì)象有特殊的數(shù)據(jù)結(jié)構(gòu) 而不象DropEffect那樣簡(jiǎn)單,該對(duì)象數(shù)據(jù)結(jié)構(gòu)如下:
1
2
3+----------------------------+|? DROPFILES? |? Files List? |+----------------------------+
DROPFILES是拖放對(duì)象的頭數(shù)據(jù),該結(jié)構(gòu)在shlobj.h中定義:
1
2
3
4
5
6typedefstruct _DROPFILES {????DWORDpFiles; ????POINT pt;????BOOLfNC; ????BOOLfWide; } DROPFILES, FAR * LPDROPFILES;
?pFiles指針是以對(duì)象首地址為參照的文件列表(上圖中的Files List項(xiàng))的offset量。通常該值等于DROPFILES結(jié)構(gòu)的長(zhǎng)度(我還沒(méi)見過(guò)例外);pt表明文件拖放的位置坐標(biāo),在這個(gè)例子里我們忽略為0; fNC表明pt值是否為客戶區(qū)坐標(biāo)(FALSE表明是屏幕坐標(biāo));fWide表明Files List是否包含unicode,作為中國(guó)人,我們當(dāng)然要設(shè)其為TRUE。DROPFILES結(jié)構(gòu)之后緊跟Files List,F(xiàn)iles List是一組寬字符串,之間以0相隔,比如:"文件1
