分类:
2008-10-13 16:48:52
如何与资源管理器互动剪切/拷贝/粘贴文件
作者:
一.本文将向读者介绍下面两个问题的解决方案:
BOOL OpenClipboard(HWND hWnd); 参数 hWnd 是打开剪贴板的窗口句柄,成功返回TRUE,失败返回FALSE。之后,可以用GetClipboardData来得到剪贴板中的数据:
HANDLE GetClipboardData(UINT uFormat);uFormat是所需要数据的格式,例如本文拖放对象的格式为CF_HDROP。而表明该拖放对象类型(Move/Copy)的数据格式并不是Windows标准的剪贴板数据结构,而是一个简单的DWORD指针。我们可以通过下面的语句来注册一下数据类型 :
UINT uDropEffect=RegisterClipboardFormat("Preferred DropEffect");这里返回的uDropEffect就是我们将要代入GetClipboardData函数的该数据结构的代码,
HDROP hDrop = HDROP( GetClipboardData( CF_HDROP));如果确实存在一个hDrop对象,我们应该取得uDropEffect的数据,以便我们处理后面的文件:
DWORD dwEffect=*((DWORD*)(GetClipboardData( uDropEffcet)));关于这个值的含义,我们只要包含一下"OLEIDL.H"头文件即可,在该头文件中5种状态的定义而本文只关注:
#define DROPEFFECT_COPY ( 1 ) #define DROPEFFECT_MOVE ( 2 )因此,我们可以通过
if(dwEffect & DROPEFFECT_COPY) CopyFile(....); else (dwEffect & DROPEFFECT_MOVE) MoveFile(...);来完成剪切/拷贝操作。
UINT DragQueryFile(HDROP hDrop, UINT iFile,LPTSTR lpszFile,UINT cch);第二个参数是文件序列号,可以通过将iFile置为-1的方法来得到文件数量。
#include在这个例子中,我并没有进行文件操作,只是简单的显示一个消息框,实际应用时,需要使用MoveFile和CopyFile函数来完成,本文不做讨论。#include .... 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(); } }
uDropEffect=RegisterClipboardFormat("Preferred DropEffect");然后分配内存对象并得到指针:
hGblEffect=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,sizeof(DWORD)); dwDropEffect=(DWORD*)GlobalLock(hGblEffect);注意往剪贴板中放的数据必须使用GMEM_MOVEABLE标志,最后我们设置数据并解除锁定:
if(COPY) *dwDropEffect=DROPEFFECT_COPY; else *dwDropEffect=DROPEFFECT_MOVE; GlobalUnlock(hGblEffect);这样我就为DropEffect准备还数据了,等一会儿我们连同文件拖放对象一起放入剪贴板。建立文件拖放对象的方法与DropEffect基本相同,只是文件拖放对象有特殊的数据结构 而不象DropEffect那样简单,该对象数据结构如下:
+----------------------------+ | DROPFILES | Files List | +----------------------------+DROPFILES是拖放对象的头数据,该结构在shlobj.h中定义:
typedef struct _DROPFILES { DWORD pFiles; POINT pt; BOOL fNC; BOOL fWide; } DROPFILES, FAR * LPDROPFILES;pFiles指针是以对象首地址为参照的文件列表(上图中的Files List项)的offset量。通常该值等于DROPFILES结构的长度(我还没见过例外);pt表明文件拖放的位置坐标,在这个例子里我们忽略为0; fNC表明pt值是否为客户区坐标(FALSE表明是屏幕坐标);fWide表明Files List是否包含unicode,作为中国人,我们当然要设其为TRUE。DROPFILES结构之后紧跟Files List,Files List是一组宽字符串,之间以0相隔,比如:"文件1\0文件2\0..."
uDropFilesLen=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);现在我们就可以将上面两组数据放入剪贴板中了,注意在写数据前应先清空剪贴板。为了方便大家使用,下面我给出实现此功能的独立的函数:
VOID CutOrCopyFiles(char * lpBuffer,UINT uBufLen,BOOL bCopy)lpBuffer是包括所有准备剪切/拷贝的文件名称的缓冲区;uBufLen是lpBuffer的长度;bCopy决定该操作是Copy还是Cut,TRUE为Copy,FALSE为Cut。例如我们可以这样调用该函数:
char szFiles[]="c:\\1.txt\0c:\\2.txt\0"; CutOrCopyFiles(szFiles,sizeof(szFiles),FALSE);来剪切文件,或者使用:
CutOrCopyFiles(szFiles,sizeof(szFiles),TRUE);来拷贝文件。
#include#include #include
...... 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(); } }希望以上内容对你有所帮助。