如何與資源管理器互動(dòng)剪切/拷貝/粘貼文件
如何與資源管理器互動(dòng)剪切/拷貝/粘貼文件 2016-06-06
一.本文將向讀者介紹下面兩個(gè)問題的解決方案:
1,用戶在資源管理器(Windows Explorer)中剪切/拷貝(Cut/Copy)文件,然后在自己的應(yīng)用程序中進(jìn)行粘貼(Paste)操作;
2.用戶在自己的應(yīng)用程序中剪切/拷貝文件,在資源管理其中粘貼操作。
二.本文中的代碼編寫工具及測(cè)試環(huán)境:
1,VC6.0, Platform SDK(無須MFC);
2.Windows 2000。
三.概述
我們知道,在Windows中可以通過剪貼板(Clipboard)來共享和傳遞數(shù)據(jù),比如在資源管理器(Windows Explorer)中可以剪切/拷貝/粘貼文件。同樣我們也可以在自己的應(yīng)用程序中通過剪貼板來完成這些工作,從而提高我們自己的應(yīng)用程序與Windows操作系統(tǒng)之間的互操作性。但我們?nèi)绾尾拍芘c資源管理器之類的應(yīng)用程序共享和傳遞數(shù)據(jù)呢?本文提供的方法是:使用Windows本身提供的一些數(shù)據(jù)結(jié)構(gòu)和API,通過剪貼板來實(shí)現(xiàn)數(shù)據(jù)共享和傳遞。
四.實(shí)現(xiàn)方法
首先,Windows在剪切/拷貝文件時(shí)并不是把文件名稱寫入剪貼板,而是在剪貼板中放入了一個(gè)DragAndDrop文件對(duì)象,并寫入了一個(gè)狀態(tài)值來標(biāo)識(shí)操作類型(移動(dòng)/拷貝,剪切其實(shí)就是移動(dòng),如果你剪切之后并沒有粘貼,那么該文件依然存在而不會(huì)被刪除)。依據(jù)這個(gè)知識(shí),我們首先來看看在應(yīng)用程序中如何識(shí)別出Windows 資源管理器的剪切/拷貝動(dòng)作。
在使用剪貼板前,我們首先要打開它:
1
2BOOL
OpenClipboard(
HWND
hWnd);
參數(shù) hWnd 是打開剪貼板的窗口句柄,成功返回TRUE,失敗返回FALSE。
之后,可以用GetClipboardData來得到剪貼板中的數(shù)據(jù):
1HANDLE
GetClipboardData(
UINT
uFormat);
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指針。我們可以通過下面的語句來注冊(cè)一下數(shù)據(jù)類型 :
1UINT
uDropEffect=RegisterClipboardFormat(
"Preferred DropEffect"
);
這里返回的uDropEffect就是我們將要代入GetClipboardData函數(shù)的該數(shù)據(jù)結(jié)構(gòu)的代碼,GetClipboardData函數(shù)返回是一個(gè)句柄,這只是Windows為了統(tǒng)一性而做的工作,我們可以根據(jù)需要來轉(zhuǎn)換成相應(yīng)的數(shù)據(jù)形式,比如我們的uDropEffect就是一個(gè)DWORD指針。
前面我已經(jīng)說過在剪貼板中放的是一個(gè)拖放對(duì)象,因此我們可以通過如下語句得到該對(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 )
因此,我們可以通過
1
2
3
4if
(dwEffect & DROPEFFECT_COPY)
??
CopyFile(....);
else
(dwEffect & DROPEFFECT_MOVE)
??
MoveFile(...);
來完成剪切/拷貝操作。
在我們?nèi)〉胾DropEffect狀態(tài)之后,我們需要得到文件列表,得到拖放對(duì)象中的文件列表可以通過DragQueryFile來實(shí)現(xiàn):
1UINT
DragQueryFile(
HDROP
hDrop,
UINT
iFile,
LPTSTR
lpszFile,
UINT
cch);
第二個(gè)參數(shù)是文件序列號(hào),可以通過將iFile置為-1的方法來得到文件數(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 >
?....
???
UINT
uDropEffect=RegisterClipboardFormat(
"Preferred DropEffect"
);
?????
if
( OpenClipboard( hWnd)) {
????????
HDROP
hDrop =
HDROP
( GetClipboardData( CF_HDROP));
????????
if
( hDrop) {
????????????
DWORD
dwEffect,*dw;
????????????
dw=(
DWORD
*)(GetClipboardData( uDropEffect));
????????????
if
(dw==NULL)
????????????????
dwEffect=DROPEFFECT_COPY;
????????????
else
????????????????
dwEffect=*dw;
????????
?????????????
char
Buf[4096];
????????????
Buf[0] = 0;
????????????
UINT
cFiles = DragQueryFile( hDrop, (
UINT
) -1, NULL, 0);
????????????
POINT Point;
????????????
char
szFile[ 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è)例子中,我并沒有進(jìn)行文件操作,只是簡(jiǎn)單的顯示一個(gè)消息框,實(shí)際應(yīng)用時(shí),需要使用MoveFile和CopyFile函數(shù)來完成,本文不做討論。?
知道如何識(shí)別其他程序的剪切/拷貝 文件的動(dòng)作后,我們對(duì)該操作的數(shù)據(jù)結(jié)構(gòu)已經(jīng)很了解了,要想讓其他程序能識(shí)別我們的剪切/拷貝 文件動(dòng)作其實(shí)就是將以上數(shù)據(jù)結(jié)構(gòu)放入剪貼板的過程。
在我們這個(gè)例子中,往剪貼板中放的數(shù)據(jù)必須是內(nèi)存對(duì)象:HGLOBAL。這個(gè)對(duì)象可以通過GlobalAlloc來生成。然后使用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)在就讓我們來為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
6typedef
struct
_DROPFILES {
????
DWORD
pFiles;
????
POINT pt;
????
BOOL
fNC;
????
BOOL
fWide;
} DROPFILES, FAR * LPDROPFILES;
?pFiles指針是以對(duì)象首地址為參照的文件列表(上圖中的Files List項(xiàng))的offset量。通常該值等于DROPFILES結(jié)構(gòu)的長(zhǎng)度(我還沒見過例外);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