作者:blueelf
一.本文将向读者介绍下面两个问题的解决方案:
1,用户在资源管理器(Windows Explorer)中剪切/拷贝(Cut/Copy)文件,然后在自己的应用程序中进行粘贴(Paste)操作;
2.用户在自己的应用程序中剪切/拷贝文件,在资源管理其中粘贴操作。
二.本文中的代码编写工具及测试环境:
1,VC6.0, Platform SDK(无须MFC);
2.Windows 2000。
三.概述
我们知道,在Windows中可以通过剪贴板(Clipboard)来共享和传递数据,比如在资源管理器(Windows Explorer)中可以剪切/拷贝/粘贴文件。同样我们也可以在自己的应用程序中通过剪贴板来完成这些工作,从而提高我们自己的应用程序与Windows操作系统之间的互操作性。但我们如何才能与资源管理器之类的应用程序共享和传递数据呢?本文提供的方法是:使用Windows本身提供的一些数据结构和API,通过剪贴板来实现数据共享和传递。
四.实现方法
首先,Windows在剪切/拷贝文件时并不是把文件名称写入剪贴板,而是在剪贴板中放入了一个DragAndDrop文件对象,并写入了一个状态值来标识操作类型(移动/拷贝,剪切其实就是移动,如果你剪切之后并没有粘贴,那么该文件依然存在而不会被删除)。依据这个知识,我们首先来看看在应用程序中如何识别出Windows 资源管理器的剪切/拷贝动作。
在使用剪贴板前,我们首先要打开它:
1
2BOOL OpenClipboard(HWND hWnd); 参数 hWnd 是打开剪贴板的窗口句柄,成功返回TRUE,失败返回FALSE。
1HANDLE GetClipboardData(UINT uFormat);
1UINT uDropEffect=RegisterClipboardFormat("Preferred DropEffect");
GetClipboardData函数返回是一个句柄,这只是Windows为了统一性而做的工作,我们可以根据需要来转换成相应的数据形式,比如我们的uDropEffect就 是一个DWORD指针。
前面我已经说过在剪贴板中放的是一个拖放对象,因此我们可以通过如下语句得到该对象:
1HDROP hDrop = HDROP( GetClipboardData( CF_HDROP));
1DWORD dwEffect=*((DWORD*)(GetClipboardData( uDropEffcet)));
1#define DROPEFFECT_COPY ( 1 )
1
2#define DROPEFFECT_MOVE ( 2 )
1if(dwEffect & DROPEFFECT_COPY)
1
2CopyFile(....);
1
2else (dwEffect & DROPEFFECT_MOVE)
1
2MoveFile(...);
在我们取得uDropEffect状态之后,我们需要得到文件列表,得到拖放对象中的文件列表可以通过DragQueryFile来实现:
1UINT DragQueryFile(HDROP hDrop, UINT iFile,LPTSTR lpszFile,UINT cch);
最后我们给出完整的例子:
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94#include < Shellapi.h >
#include < oleidl.h >
....
UINT uDropEffect = RegisterClipboardFormat( " Preferred DropEffect " );
if ( OpenClipboard( hWnd)) { //hWnd是某一句柄,也可以为NULL
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, " " );
}
if (dwEffect & DROPEFFECT_MOVE) {
MessageBox(NULL,Buf, " Move Files " ,MB_OK);
} else if (dwEffect & DROPEFFECT_COPY) {
MessageBox(NULL,Buf, " Copy Files " ,MB_OK);
}
CloseClipboard();
}
}
知道如何识别其他程序的剪切/拷贝 文件的动作后,我们对该操作的数据结构已经很了解了,要想让其他程序能识别我们的剪切/拷贝 文件动作其实就是将以上数据结构放入剪贴板的过程。
在我们这个例子中,往剪贴板中放的数据必须是内存对象:HGLOBAL。这个对象可以通过GlobalAlloc来生成。然后使用GlobalLock就可以得到该对象的内存地址,继而往里面写 数据。实际上在Win32中由于进程拥有独立的内存空间,因而常规的内存分配已经不需要GlobalLock了,看看MSDN就知道该函数主要就是为DDE和剪贴板服务的。
根据前面的知识,要想让其他程序识别出我们的剪切/拷贝动作我们必须往剪贴板中放两项数据,现在就让我们来为DropEffect准备数据吧,同样我们需要先注册该数据格式:
1uDropEffect=RegisterClipboardFormat("Preferred DropEffect");
1hGblEffect=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,sizeof(DWORD));
1
2dwDropEffect=(DWORD*)GlobalLock(hGblEffect);
1if(COPY)
1
2*dwDropEffect=DROPEFFECT_COPY;
1
2else
1
2*dwDropEffect=DROPEFFECT_MOVE;
1
2GlobalUnlock(hGblEffect);
1
2
3
4
5
6
7+----------------------------+ | DROPFILES | Files List | +----------------------------+
1typedef struct _DROPFILES {
1
2DWORD pFiles;
1
2POINT pt;
1
2BOOL fNC;
1
2BOOL fWide;
1
2} DROPFILES, FAR * LPDROPFILES;
我们可以通过MultiByteToWideChar函数将常规的字符串转换成宽字符串。下面就是生成拖放对象的代码:
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60uDropFilesLen = sizeof (DROPFILES);
dropFiles.pFiles = uDropFilesLen;
dropFiles.pt.x = 0 ;
dropFiles.pt.y = 0 ;
dropFiles.fNC = FALSE;
dropFiles.fWide = TRUE;
uGblLen = uDropFilesLen + uBufLen << 1 + 8 ;
// uBufLen是文件名字符传组的长度,由于要转换成宽字符,因此长度要乘2
hGblFiles = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, uGblLen);
szData = ( char * )GlobalLock(hGblFiles);
memcpy(szData,(LPVOID)( & dropFiles),uDropFilesLen);
// 将DROPFILES copy到头部
szFileList = szData + uDropFilesLen;
// 得到存放文件列表的首地址
MultiByteToWideChar(CP_ACP,MB_COMPOSITE,
lpBuffer,uBufLen,(WCHAR * )szFileList,uBufLen);
GlobalUnlock(hGblFiles);
1VOID CutOrCopyFiles(char * lpBuffer,UINT uBufLen,BOOL bCopy)
1
2char szFiles[]="c://1.txt/0c://2.txt/0"; //这里只能用 字符数组
1CutOrCopyFiles(szFiles,sizeof(szFiles),FALSE);
1CutOrCopyFiles(szFiles,sizeof(szFiles),TRUE);
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104#include < Shellapi.h >
#include < Shlobj.h >
#include < oleidl.h > ......
VOID CutOrCopyFiles( char * lpBuffer,UINT uBufLen,BOOL bCopy)
{
UINT uDropEffect;
DROPFILES dropFiles;
UINT uGblLen,uDropFilesLen;
HGLOBAL hGblFiles,hGblEffect;
char * szData, * szFileList;
DWORD * dwDropEffect;
uDropEffect = RegisterClipboardFormat( " Preferred DropEffect " );
hGblEffect = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, sizeof (DWORD));
dwDropEffect = (DWORD * )GlobalLock(hGblEffect);
if (bCopy)
* dwDropEffect = DROPEFFECT_COPY;
else
* dwDropEffect = DROPEFFECT_MOVE;
GlobalUnlock(hGblEffect);
uDropFilesLen = sizeof (DROPFILES);
dropFiles.pFiles = uDropFilesLen;
dropFiles.pt.x = 0 ;
dropFiles.pt.y = 0 ;
dropFiles.fNC = FALSE;
dropFiles.fWide = TRUE;
uGblLen = uDropFilesLen + uBufLen * 2 + 8 ;
hGblFiles = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, uGblLen);
szData = ( char * )GlobalLock(hGblFiles);
memcpy(szData,(LPVOID)( & dropFiles),uDropFilesLen);
szFileList = szData + uDropFilesLen;
MultiByteToWideChar(CP_ACP,MB_COMPOSITE,
lpBuffer,uBufLen,(WCHAR * )szFileList,uBufLen);
GlobalUnlock(hGblFiles);
if ( OpenClipboard(NULL) )
{
EmptyClipboard();
SetClipboardData( CF_HDROP, hGblFiles );
SetClipboardData(uDropEffect,hGblEffect);
CloseClipboard();
}
}
本文附上一个Demo工程,编译后生成CutCopy.exe程序,该程序的使用方法如下:
启动程序后,可使用Windows 资源管理器等程序剪切/拷贝文件,然后点程序中的[CheckClipboard],Demo程序将分析剪贴板中的内容,并弹出消息框告知是Copy Files还是Cut Files,并给出文件列表.用户点[OK]关闭消息框后,文件列表 将被放入文本框中,此时用户可以通过[Cut]/[Copy]按钮来改变剪贴板中的属性。
同时,用户可以通过[Browser]来选择若干文件到文本框中,然后点[Cut]/[Copy]进行操作,之后,用户既可以通过[CheckClipboard]检查剪贴板中的内容也可以通过在Windows 资源管理器等程序中进行粘贴(Paste)来检查其是否正确。
最后
以上就是野性跳跳糖最近收集整理的关于如何与资源管理器互动剪切/拷贝/粘贴文件[VC++]的全部内容,更多相关如何与资源管理器互动剪切/拷贝/粘贴文件[VC++]内容请搜索靠谱客的其他文章。
发表评论 取消回复