`
hcmfys
  • 浏览: 356324 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

OLE剪贴板学习心得

 
阅读更多

OLE剪贴板学习心得

MFC对OLE剪贴板的支持主要集中在两个类上,分别是
COleDataSource,COleDataObject。
其中,COleDataSource作为操作者,而COleDataObject作为消费者,换句话说,用户需要使用COleDataSource把数据放到OLE剪贴板上,而使用COleDataObject把它取回。


将保存在全局内存中的项目放置在OLE剪贴板上,需要进行如下步骤:
1.在堆上(而不是在堆栈上)创建COleDataSource对象。
2.调用COleDataSource::CacheGlobalData将HGLOBAL递交给COleDataSource对象。
3.调用COleDataSource::SetClipboard将对象放置在
OLE剪贴板上。

下列使用COleDataSource在OLE剪贴板上提供了ANSI文本字符串.

char szText[]="Hello,world";
HANDLE hData=::GlobalAlloc(CMEM_MOVEABLB,::lstrlen(szText)+1);
::lstrcpy(pData,szText);
::GlobalUnlock(hData);

COleDataSource * pods=new COleDataSource;
pods->CacheGlobalData(CF_TEXT,hData);
pods->SetClipboard();


MFC的COleDataObject提供了从OLE剪贴板获取项目的机制。
1.创建COleDataObject对象。
2.调用COleDataObject::AttachClipboard将 COleDataObject连接到OLE剪贴板。
3.使用COleDataObject::GetGlobalData获取项目。
4.释放由GetGlobalData返回的全局内存块。

以下为例:
char szTect[];
COleDataObject pdo;
pdo.AttachClipboard();
HANDLE hData=pdo.GetGlobalData(CF_TEXT);

if(hData!=NULL)
LPCSTR pData=(LPCSTR)::Globallock(hData);
if(::lstrlen(pData<BUFLEN))
::lstrcpy(szText,pData);
::GlobalUnlock(hData);
::GlobalFree(hData);

注意,我们以上讨论的OLE剪贴板储存媒介都是内存,下面我们将要讨论储存媒介为非内存的情况。


COleDataSource::CacheGlobalData和COleDataObject::GetGlobalData与全局内存密不可分。但是您可以使用更一般的COleDataSource::CacheData和COleDataObject::GetData函数在其他数据类型的媒介中传送数据。

下面例子说明如何使用文件作为传送媒体,通过前贴板来传送文本字符串。字符串首先复制到临时文件中。然后用描述文件的信息和文件包含的数据初始化FORMATETC和STGMEDIUM结构。最后信息被传送给COleDataSource::CacheData,并用COleDataSource::SetClipboar将数据对象放置在剪贴板上。

char szText[]="Hello,world"
TCHAR szPath[Max_path],szFileName[Max_path];
::GetTempPath(sizeof(szPath)/sizeof(TCHAR),szPath);
::GetTempFileName(szPath,_T("tmp"),0,szFileName);//分配临时文件名称。

CFile file;
if(file.Open(szFileName,CFile::modeCreate|CFile::modeWrite))
{
file.Write(szText,::lstrlen(szText)+1);
file.Close();

LPWSTR pwszFileName=(LPWSTR)::CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
#ifdef UNICODE
::lstrcpy(pwszFileName,szFileName);
#else
::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,szFileName,-1,pwszFileName,MAX_PATE);
#endif
FORMATETC fe={CF_TEXT,NULL,DVASPECT_CONTENT,-1,TYMED_FILE};

STGMEDIUM stgm;
stgm.tymed=TYMED_FILE;
stgm.lpszFileName=pwszFileName;
stgm.pUnkForRelease=NULL;

COleDataSource * pods=new COleDataSource;
pods->CacheData(CF_TEXT,&stgm,&fe);
pods->setClipboard();
}


在消费者端,您可以使用COleDataObject::GetData从剪贴板获取字符串
char szText[BUFLEN];
STGMEDIUM stgm;
FORMATETC fe={CF_TEXT,NULL,DVASPECT_CONTENT,-1,TYMED_FILE;}
COleDataObject pdo;
pdo.AttachClipboard();
if(pdo.GetData(CF_TEXT,&stgm,&fe)&&stgm.tymed==TYMED_FILE)
{TCHAR szFileName|Max_Path;}

#ifdef UNICODE
::lstrcpy(szFileName,stgm,lpszFileName);
#else
::WideCharToMultiByte(CP_ACP,0,stgm,lpszf|leName,_T,szFileName,sizeof(szFileName)/sizeof(TCHAR),NULL,NULL);
#endif
CFile file;
if(file.Open(szFileName,CFile::modeRead))|DWORD dwSize=file.GetLength();
if(dwSize<BUFLEN)
file.Read(szText,(UNIT)dwSize);
file.Close();
}
::ReleaseStgMedium(&stgm);
}

在读取OLE剪贴板内容是,用户可以直接使用COleDataObject::GetFileData取代GetData函数。

__________________________________________

一)ChangeClipboardChain
将剪贴的连接从一个句柄转到下一个句柄。
BOOL ChangeClipboardChain(
HWND hWndRemove, // handle to window to remove
HWND hWndNewNext // handle to next window
);
(1)hWndRemove表示第一个窗口的句柄(断开)。
(2)hWndNewNext表示第二个窗口的句柄(连接)。
注意,在使用之前应该使用SetClipboardViewer事先进行窗口句柄的连接。
(二)CloseClipboard
关闭剪贴板。
BOOL CloseClipboard(VOID)//VOID意思是空白。
本函数没有参数,事先应该用OpenClipboard函数打开过剪贴板。
(三)CountClipboardFormats
不管剪贴板是什么格式,全部转化为数据格式。
int CountClipboardFormats(VOID)
本函数没有参数。
(四)EmptyClipboard
清空剪贴板。
BOOL EmptyClipboard(VOID)
本函数没有参数。
(五)EnumClipboardFormats
使剪贴板内的格式转变成指定格式。
UINT EnumClipboardFormats(
UINT format // specifies a known available clipboard format
);
其中format表示的是将要转化成的格式。该参数的意义可参照后面。
(六)GetClipboardData
获取剪贴板内的数据。
HANDLE GetClipboardData(
UINT uFormat // clipboard format
);
其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
(七)GetClipboardFormatName
获取剪贴板内数据格式的名称。
int GetClipboardFormatName(
UINT format, // clipboard format to retrieve
LPTSTR lpszFormatName, // address of buffer for name
int cchMaxCount // length of name string in characters
);
(1)format表示的意义同前,应该是不事先规定格式;
(2)lpszFormatName表示的是格式名称地址;
(3)cchMaxCount剪贴板内数据的长度。
(八)GetClipboardOwner
获取当前剪贴板是属于哪一个窗口的句柄。
HWND GetClipboardOwner(VOID)
返回那个窗口的句柄。
(九)GetClipboardSequenceNumber
返回剪贴板序号。
DWORD GetClipboardSequenceNumber(VOID)
(十)GetClipboardViewer
返回剪贴板属于窗口的句柄。
HWND GetClipboardViewer(VOID)
(十一)GetOpenClipboardWindow
返回打开剪贴板的那个窗口句柄。
HWND GetOpenClipboardWindow(VOID)
(十二)GetPriorityClipboardFormat
int GetPriorityClipboardFormat(
UINT *paFormatPriorityList, // address of priority list
int cFormats // number of entries in list
);
(十三)IsClipboardFormatAvailable
判断剪贴板的格式。
BOOL IsClipboardFormatAvailable(
UINT format // clipboard format
);
其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
(十四)OpenClipboard
打开剪贴板。
BOOL OpenClipboard(
HWND hWndNewOwner // handle to window opening clipboard
);
返回剪贴板的句柄。
(十五)RegisterClipboardFormat
注册新的剪贴板格式。
UINT RegisterClipboardFormat(
LPCTSTR lpszFormat // address of name string
);
lpszFormat新的剪贴板格式名称。
(十六)SetClipboardData
设置剪贴板内的数据。
HANDLE SetClipboardData(
UINT uFormat, // clipboard format
HANDLE hMem // data handle
);
uFormat表示的是要放进剪贴板数据的格式;
hMem表示数据的地址指针。
(十七)SetClipboardViewer
将剪贴板内容连接到窗口。
HWND SetClipboardViewer(
HWND hWndNewViewer // handle to clipboard viewer window
);
hWndNewViewer表示要连接到的那个窗口句柄。
上文中剪贴板格式Format的可选参数如下:
CF_BITMAP位图格式;
CF_DIB
CF_DIBV5
CF_DIF
CF_DSPBITMAP
CF_DSPENHMETAFILE
CF_DSPMETAFILEPICT
CF_DSPTEXT
CF_ENHMETAFILE
CF_GDIOBJFIRST
CF_GDIOBJLAST
CF_HDROP
CF_LOCALE
CF_METAFILEPICT
CF_OEMTEXT
CF_OWNERDISPLAY
CF_PALETTE
CF_PENDATA
CF_PRIVATEFIRST
CF_PRIVATELAST
CF_RIFF
CF_SYLK
CF_TEXT文本格式;
CF_WAVE音乐格式;
CF_TIFF
CF_UNICODETEXT


Windows剪贴板

   Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制。Windows系统支持剪贴板IPC的基本机制是由系统预留的一块全局共享内存,用来暂存在各进程间进行交换的数据:提供数据的进程创建一个全局内存块,并将要传送的数据移到或复制到该内存块;接受数据的进程(也可以是提供数据的进程本身)获取此内存块的句柄,并完成对该内存块数据的读取。

  为使剪贴板的这种IPC机制更加完善和便于使用,需要解决好如下三个问题:提供数据的进程在结束时 Windows系统将删除其创建的全局内存块,而接受数据的进程则希望在其退出后剪贴板中的数据仍然存在,可以继续为其他进程所获取;能方便地管理和传送剪贴板数据句柄;能方便设置和确定剪贴板数据格式。为完善上述功能,Windows提供了存在于USER32.dll中的一组API函数、消息和预定义数据格式等,并通过对这些函数、消息的使用来管理在进程间进行的剪贴板数据交换。

  Windows系统为剪贴板提供了一组API函数和多种消息,基本可以满足编程的需要。而且Windows还为剪贴板预定义了多种数据格式。通过这些预定义的格式,可以使接收方正确再现数据提供方放置于剪贴板中的数据内容。

  文本剪贴板和位图剪贴板的使用

  这两种剪贴板是比较常用的。其中,文本剪贴板是包含具有格式CF_TEXT的字符串的剪贴板,是最经常使用的剪贴板之一。在文本剪贴板中传递的数据是不带任何格式信息的ASCII字符。若要将文本传送到剪贴板,可以先分配一个可移动全局内存块,然后将要复制的文本内容写入到此内存区域。最后调用剪贴板函数将数据放置到剪贴板:

注意:
下面代码中:
1、HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1);
分配内存长度必须是dwLength + 1,否则在调用SetClipboardData时会出错;可以通过调用 int i2 = ::GlobalSize(hGlobalMemory );来查看分配的长度。

2、hGlobalMemory不能释放,即不能调用::GlobalFree(hGlobalMemory),因为如果在一个程序中还要粘贴的话就必须不能释放,否则在同一程序中粘贴时获得的指针为NULL,但如果只在别的程序中粘贴则可以释放。

以上两条是在编制HsfBrowserCtl(HOOPS三维浏览控件)时总结出来的。可参看原码中的复制、粘贴部分。
  DWORD dwLength = 100; // 要复制的字串长度
HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存
LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存
for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
 *lpGlobalMemory++ = '*';
 GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
 HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
 ::OpenClipboard(hWnd); // 打开剪贴板
 ::EmptyClipboard(); // 清空剪贴板
 ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
 ::CloseClipboard(); // 关闭剪贴板



  这里以OpenClipboard()打开剪贴板,并在调用了EmptyClipboard()后使hWnd指向的窗口成为剪贴板的拥有者,一直持续到 CloseClipboard()函数的调用。在此期间,剪贴板为拥有者所独占,其他进程将无法对剪贴板内容进行修改。

  从剪贴板获取文本的过程与之类似,首先打开剪贴板并获取剪贴板的数据句柄,如果数据存在就拷贝其数据到程序变量。由于GetClipboardData()获取的数据句柄是属于剪贴板的,因此用户程序必须在调用CloseClipboard()函数之前使用它:



  HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
HANDLE hClipMemory = ::GetClipboardData(CF_TEXT);// 获取剪贴板数据句柄
DWORD dwLength = GlobalSize(hClipMemory); // 返回指定内存区域的当前大小
LPBYTE lpClipMemory = (LPBYTE)GlobalLock(hClipMemory); // 锁定内存
m_sMessage = CString(lpClipMemory); // 保存得到的文本数据
GlobalUnlock(hClipMemory); // 内存解锁
::CloseClipboard(); // 关闭剪贴板



  大多数应用程序对图形数据采取的是位图的剪贴板数据格式。位图剪贴板的使用与文本剪贴板的使用是类似的,只是数据格式要指明为CF_BITMAP,而且在使用SetClipboardData()或GetClipboardData()函数时交给剪贴板或从剪贴板返回的是设备相关位图句柄。下面这段示例代码将把存在于剪贴板中的位图数据显示到程序的客户区:



  HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
HANDLE hBitmap = ::GetClipboardData(CF_BITMAP); // 获取剪贴板数据句柄
HDC hDC = ::GetDC(hWnd); // 获取设备环境句柄
HDC hdcMem = CreateCompatibleDC(hDC); // 创建与设备相关的内存环境
SelectObject(hdcMem, hBitmap); // 选择对象
SetMapMode(hdcMem, GetMapMode(hDC)); // 设置映射模式
BITMAP bm; // 得到位图对象
GetObject(hBitmap, sizeof(BITMAP), &bm);
BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); //位图复制
::ReleaseDC(hWnd, hDC); // 释放设备环境句柄
DeleteDC(hdcMem); // 删除内存环境
::CloseClipboard(); // 关闭剪贴板





多数据项和延迟提交技术

  要把数据放入剪贴板,在打开剪贴板后一定要调用EmptyClipboard()函数清除当前剪贴板中的内容,而不可以在原有数据项基础上追加新的数据项。但是,可以在EmptyClipboard()和CloseClipboard()调用之间多次调用SetClipboardData()函数来放置多个不同格式的数据项。例如:



  OpenClipboard(hWnd);
EmptyClipboardData();
SetClipboardData(CF_TEXT, hGMemText);
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();



  这时如果用CF_TEXT或CF_BITMAP等格式标记去调用IsClipboardFormatAvailable()都将返回TRUE,表明这几种格式的数据同时存在于剪贴板中。以不同的格式标记去调用GetClipboardData()函数可以得到相应的数据句柄。

  对于多数据项的剪贴板数据,还可以用CountClipboardFormats()和EnumClipboardFormats()函数得到当前剪贴板中存在的数据格式数目和具体的数据格式。EnumClipboardFormats()的函数原型为:



  UINT EnumClipboardFormats(UINT format);



  参数format指定了剪贴板的数据格式。如果成功执行将返回format指定的格式的下一个数据格式值,如果format为最后的数据格式值,那么将返回0。由此不难写出处理剪贴板中所有格式数据项的程序段代码:



  UINT format = 0; // 从第一种格式值开始枚举
OpenClipboard(hWnd);
while(format = EnumClipboardFormats(format))
{
…… // 对相关格式数据的处理
}
CloseClipboard();



  在数据提供进程创建了剪贴板数据后,一直到有其他进程获取剪贴板数据前,这些数据都要占据内存空间。如在剪贴板放置的数据量过大,就会浪费内存空间,降低对资源的利用率。为避免这种浪费,可以采取延迟提交(Delayed rendering)技术,即由数据提供进程先创建一个指定数据格式的空(NULL)剪贴板数据块,直到有其他进程需要数据或自身进程要终止运行时才真正提交数据。

  延迟提交的实现并不复杂,只需剪贴板拥有者进程在调用SetClipboardData()将数据句柄参数设置为NULL 即可。延迟提交的拥有者进程需要做的主要工作是对WM_RENDERFORMAT、WM_DESTORYCLIPBOARD和 WM_RENDERALLFORMATS等剪贴板延迟提交消息的处理。

  当另一个进程调用GetClipboardData()函数时,系统将会向延迟提交数据的剪贴板拥有者进程发送WM_RENDERFORMAT消息。剪贴板拥有者进程在此消息的响应函数中应使用相应的格式和实际的数据句柄来调用SetClipboardData()函数,但不必再调用OpenClipboard()和EmptyClipboard()去打开和清空剪贴板了。在设置完数据有也无须调用CloseClipboard()关闭剪贴板。如果其他进程打开了剪贴板并且调用EmptyClipboard()函数去清空剪贴板的内容,接管剪贴板的拥有权时,系统将向延迟提交的剪贴板拥有者进程发送WM_DESTROYCLIPBOARD消息,以通知该进程对剪贴板拥有权的丧失。而失去剪贴板拥有权的进程在收到该消息后则不会再向剪贴板提交数据。另外,在延迟提交进程在提交完所有要提交的数据后也会收到此消息。如果延迟提交剪贴板拥有者进程将要终止,系统将会为其发送一条WM_RENDERALLFORMATS消息,通知其打开并清除剪贴板内容。在调用 SetClipboardData()设置各数据句柄后关闭剪贴板。

  下面这段代码将完成对数据的延迟提交,WM_RENDERFORMAT消息响应函数OnRenderFormat()并不会立即执行,当有进程调用GetClipboardData()函数从剪贴板读取数据时才会发出该消息。在消息处理函数中完成对数据的提交:

  进行延迟提交:



  HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
::EmptyClipboard(); // 清空剪贴板
::SetClipboardData(CF_TEXT, NULL); // 进行剪贴板数据的延迟提交
::CloseClipboard(); // 关闭剪贴板



  在WM_RENDERFORMAT消息的响应函数中:



  DWORD dwLength = 100; // 要复制的字串长度
HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存块
LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存块
for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
*lpGlobalMemory++ = '*';
GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
DSP和自定义数据格式的使用

   Windows系统预定义了三个带“DSP”前缀的数据格式:CF_DSPTEXT、CF_DSPBITMAP和 CF_DSPMETAFILEPICT。这是一些伪标准格式,用于表示在程序中定义的私有剪贴板数据格式。对于不同的程序,这些格式的规定是不同的,因此这些格式只针对某一具体程序的不同实例才有意义。

  为使用DSP数据格式,必须确保进程本身与剪贴板拥有者进程同属一个程序。可以调用GetClipboardOwner()函数来获取剪贴板拥有者窗口句柄,并调用GetClassName()来获取窗口类名:

HWND hClipOwner = GetClipboardOwner();
GetClassName(hClipOwner, &ClassName, 255);

  如果剪贴板拥有者窗口类名同本进程的窗口类名一致,就可以使用带有DSP前缀的剪贴板数据格式了。
除了使用Windows预定义的剪贴板数据格式外,也可以在程序中使用自定义的数据格式。对于自定义的数据格式lpszFormat,可以调用RegisterClipboardFormat()函数来登记,并获取其返回的格式标识值:

UINT format = RegisterClipboardFormat(lpszFormat);

  对此返回的格式标识值的使用与系统预定义的格式标识是一样的。可以通过GetClipboardFormatName()函数来获取自定义格式的ASCII名。

  小结

  本文主要对Windows编程中的剪贴板机制作了较为深入的讨论,对其中常用的文本、位图、DSP和自定义数据格式的使用方法以及多数据项和延迟提交等重要技术一并做了阐述。并给出了具体的程序示例代码,使读者能够更好的掌握剪贴板机制的使用。


功能实现:复制位图到剪切阪。

今日看了下COleDataSource的原码和网上的文章。

COleDataSource用内嵌类实现了IDataObject接口
//COPY HBITMAP To CilpBoard
void CMyView::OnEditCopy()
{

COLORREF BACKGROUND_COLOR = #ffffff;
tagSTGMEDIUM * data;
CBitmap * junk;
COleDataSource* pData = new COleDataSource;
data = new tagSTGMEDIUM;
junk = new CBitmap();
CClientDC cdc(this);
CDC dc;
dc.CreateCompatibleDC(&cdc);
CRect client;
//replace this with something that calculates
//the proper rectangle size
GetClientRect(client);
junk->CreateCompatibleBitmap(&cdc,client.Width(),client.Height());
dc.SelectObject(junk);
CBrush fill(BACKGROUND_COLOR);
dc.FillRect(client,&fill);
//replace this with something that draws to a CDC
OnDraw(&dc);
data->tymed = TYMED_GDI;
data->hBitmap = HBITMAP(*junk);
pData->CacheData( CF_BITMAP, data );
pData->SetClipboard();
delete data;
delete junk;
//delete pData;
}

另转载一篇文章,讲的不怎样,但可参看一下

利用MFC实现对象拖放

  对象拖放是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口
之间、同一应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)
等操作的技术。
  利用对象拖放,可以为用户提供方便、直观的操作界面。
实现对象拖放技术,需要了解、使用MFC的CView、COleDataSource和COleDropTarget
等类,并利用这些类协同工作。
本文讨论了对象拖放技术,并研究了如何利用MFC实现该技术。
利用MFC实现对象拖放,编程比较容易,代码可读性好。
修改稿
利用MFC实现对象拖放
1.对象拖放概念
  对象拖放是指对某一指定的对象,利用鼠标拖动的方法,在不同应用的窗口
之间、同一应用的不同窗口之间或同一应用的同一窗口内进行移动、复制(粘贴)
等操作的技术。
  对象拖放是在操作系统的帮助下完成的。 要开始一次拖动, 首先需要指定
或生成被拖动的对象,然后指定整个拖放操作过程所使用的数据格式,并按指定
的数据格式提供数据,最后启动对象拖放操作;当对象在某一窗口内落下时,拖
放过程结束,接收拖放对象的窗口按指定的数据格式提取有关数据,并根据提取
的数据生成对象。
2.MFC中用于对象拖放的类
MFC(Microsoft Foundation ClassLibrary)为实现对象拖放提供了如下三个类。
为便于后边的
讨论我们先来熟悉一下这些类。
2.1.COleDataSource。用于启动一次拖放操作,并向系统提供拖放对象的数据。
类中的成员
函数有如下三种:
a.设定提供数据的方式和使用的数据格式。提供数据的方式有两种,一种是即时
方式,另一种是延迟方式;即时方式需要在拖动开始之前提供数据;延迟方式不
需要立即提供数据,当系统请求有关数据时,由OnRenderData()等虚函数提供所
需的数据。
可以用CacheGlobalData()等函数指定使用即时方式提供数据,也可以用
DelayRenderData()等函数指定使用延时方式提供数据。
b.响应请求,提供数据。应当重载OnRenderFileData()或其他相应的虚函数,以
提供有关数据(后边将详细讨论)。
c.实施拖放操作。调用函数DoDragDrop(),开始实施拖放操作。
2.2.OleDataTarget。用于准备接收拖放对象的目标窗口;一个窗口要想能够接收
拖放对象,必须包含一个COleDataTarget对象,并注册该对象。类中主要成员函数:
a.注册。函数Register()注册该对象,以便使窗口能够接收拖放对象。
b.响应拖放过程中的动作(虚成员函数) 当鼠标首次进入窗口时系统将调用
OnDragEnter(),当鼠标移出窗口时系统将调用OnDragLeave(), 当鼠标在窗口内移动,
系统将重复调用调用OnDragOver(),当对象在窗口内落下调用OnDrop()。
2.3.OleDataObject.用于接收拖放对象,类中主要成员函数有两种:
a.确定可以使用的数据格式。IsDataAvailable()等函数确定指定数据格式是否可用;
b.获取数据。GetData()、GetFileData()等函数用于按指定数据格式获得数据。
3.利用MFC实现对象拖放
   要实现一次对象拖放,需要做三方面的工作:对象所在的窗口准备拖放对象并启拖动操作,
接受对象的窗口响应有关拖放消息并接受落下的对象,以及拖放完成时的后期处理。
以下分别予以介绍。
3.1. 拖动操作的启动。拖放操作一般是从单击鼠标左键开始。在消息WM_LBUTTONDOWN的响应
函数OnLButtonDown(...)中,首先要判定是否选定了某一对象,如果未选定或选定多个,则不能进
行拖放操作;如果选定了一个对象,则可以进行拖放操作。
要启动一次拖放操作,需要先准备一个COleDataSource对象。注意到类COleClientIten和类
COleServerItem都是从类COleDataSource上派生的,如果选定的是COleClientItem对象或者是
COleServerItem对象,则可以直接使用;否则,需要生成一个COleDataSource对象,值得注意的
是:需要象上文中所说的,应该指定使用的数据格式,并按指定格式提供对象的有关数据。
下面给出准备数据源的例子:
class myDataSource: public COleDataSource
public:
COLORREF color;
CString str;
protected:
virtual BOOL OnRenderFileData(LPFORMATETC,CFile*);
//......
};
BOOL myDataSource::OnRenderFileData(LPFORMATETC lpFormatEtc,CFile* pFile)
if(lpFormatEtc->cfFormat==CF_TEXT)
pFile.Write("Test DragDrop",13); //Magic String
pFile.Write(&color,sizeof(COLORREF));
int len= str.GetLength();
pFile.Write(&len,sizeof(int));
pFile.Write(str,len);
return TRUE;
COleDataSource::OnRenderFileData(lpFormatEtc,pFile);
return FALSE;
  有了以上数据源之后,就可以在消息WM_LBUTTON的响应函数OnLButtonDown()中,按如下方式,指定使用的数据格式:
myDataSource* pItemDragDrop=new myDataSource;
pItemDragDrop->str="This string will dragdrop to another place";
pItemDragDrop->DelayRenderFileData(CF_TEXT,NULL);
  指定好使用的数据格式之后,调用此对象的成员函数DoDragDrop(...),启动对象拖放操作。
需要注意的是,函数DoDragDrop(...)并不立即返回,而是要等到鼠标按钮弹起之后。
3.2. 拖放对象的接收。缺省情况下,一般的窗口是不能接收拖放对象的;要使窗口可以接收拖
放对象,需要在窗口类定义中加入成员对象COleDropTarget,并在生成窗口时调用函数
COleDataTarget::Register()。例如:
Class myView : public CScrollView
private:
COleDropTarget oleTarget;
protected:
virtual int OnCreate(LPCREATESTRUCT);
//......
int myView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  //......
  dropTarget.Register(this);
  return 0;
为实现拖放对象的接收,还应重载CView或COleDropTarget的虚函数:COnDragMove()、
OnDragEnter()和OnDrop()等。函数OnDragEnter()、OnDragMove()应根据鼠标在窗口中的位置,
返回以下数值:
DROPEFFECT_MOVE---表明可以把对象复制到现在的窗口、现在的位置;
DROPEFFECT_COPY---表明可以把对象从原来的窗口、原来的位置移到现在的窗口、现在的位置;
DROPEFFECT_NONE---表明不能在该窗口的该位置放下。
下例只允许移动对象,而不允许复制对象:
DROPEFFECT myView::OnDragEnter(......)
  return DROPEFFECT_MOVE;
DROPEFFECT myView::OnDragOver(......)
return DROPEFFECT_MOVE;
函数OnDrop()应处理拖动对象放下后的工作。该函数的参数pDataObjec指向一个
COleDataObject对象,利用指针,可以获取有关数据。该函数的一般实现是:
a.检查对象的数据格式: 利用函数COleDataObject::IsDataAvailable();
b.按指定的格式获取数据:利用COleDataObject::GetFileData()等函数;
c.建立对象(可能与原对象相同,也可能不建立对象仅使用对象中的数据):利用以上步骤
得到的数据建立对象。例如:
char magic_string[13];
COLORREF color;
CString str;
int len;
myDataSource* pMyData;
if(IsDataAvailable(CF_TEXT))
CFile file=GetFileData(CF_TEXT);
file.Read(magic_string,13);
if(strncmp(magic_string,"Test DragDrop",13)==0)
file.Read(&color,sizeof(COLORREF));
file.Read(&len,sizeof(int));
file.Read(str,len);
CClientDC dc(this);
dc.SetTextColor(color);
dc.SetBkMode(TRANSPARENT);
dc.TextOut(100,50,str,len);
pMyData=new myDataSource;
pMyData->color=color;
pMyData->str=str;
对于COleClientItem或COleServerItem对象,可以按以下方法很容易地重建对象:
COleClient* pItem=GetDocument()->CreateNewItem();
pItem->CreateFrom(pDataObject);
3.3. 拖放操作的结束函数DoDragDrop()返回时,拖放过程结束。函数DoDragDrop()的返回值,
表明了对象的拖放结果。
DROPEFFECT_MOVE:对象被放到他处,需删除原对象
DROPEFFECT_COPY:对象被复制到他处,不删除原对象
DROPEFFECT_NONE:未能实现拖放,无需删除原对象
例如:
int DragEffect=pItemTracking->DoDragDrop(......);
switch(DragEffect)
case DROPEFFECT_MOVE:
delete pItemTracking;
GetDocument()->UpdateAllItems(NULL);
GetDocument()->UpdateAllViews(NULL);
break;
case DROPEFFECT_COPY:
case DROPEFFECT_NONE:
default:
break;
*********************
想构建一个自己的粘贴版
需要Hook的函数
写粘贴板
EmptyClipboardData();//清空自己的粘贴板
SetClipboardData(CF_TEXT, hGMemText);
SetClipboardData(CF_BITMAP, hBitmap);

读粘贴版
GetClipboardData(CF_TEXT,);
GetClipboardData(CF_BITMAP);

分享到:
评论

相关推荐

    windows剪切板操作例程(MFC)

    总的来说,"windows剪切板操作例程(MFC)"是一个涵盖Windows API基础剪切板操作和MFC中高级OLE剪切板功能的综合主题。通过研究提供的文件,开发者可以学习如何在Windows环境中实现更复杂的数据交换功能,提高软件的...

    delphi获取处理剪贴板中Excel中的数据,封装成自定义的数据集

    `OpenClipboard`函数用于打开剪贴板,`EmptyClipboard`清空剪贴板,`SetClipboardData`设置剪贴板数据,而`CloseClipboard`则关闭剪贴板。当从Excel复制数据时,剪贴板上通常包含多种数据格式,如CF_TEXT、CF_...

    监视剪切板的Excel表格数据

    工程只提取了监视功能, 使用windows 对应剪切板API。 使用方法: 1、初始化 使用 SetClipboardViewer ,把本窗口句柄传入,并且保存返回的下个窗口句柄。 2、在消息响应函数中 WindowProc中 处理WM_CHANGECBCHAIN,...

    inside ole

    OLE规范包括了一系列的技术、特性和服务,涵盖了类型信息、可连接对象、自定义组件、本地/远程透明性、结构化存储、持久化对象、命名和绑定、统一数据传输、可视对象和数据缓存、OLE剪贴板、OLE拖放等方面。...

    C语言头文件 OLE2 C语言头文件 OLE2

    C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言头文件 OLE2C语言...

    LINGO 学习心得 数学建模软件

    【 LingO 学习心得与数学建模应用】 LingO 是一款强大的数学建模软件,主要用于解决线性、非线性、整数优化问题。它以其数学化的语言和直观的建模方式著称,使得复杂的数学模型能够简洁地表达。在学习 LingO 的过程...

    OLEDB驱动程序大全 MySQL-OleDB-Provider

    OLEDB(Object Linking and Embedding, Database)是微软提出的一种数据访问接口,它允许应用程序通过统一的方式访问各种数据源,...通过深入学习和实践,开发者可以充分利用OLEDB的特性,提高应用程序的数据处理能力。

    C语言头文件 OLE2VER

    C语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言头文件 OLE2VERC语言...

    ole的介绍OLE DB(OLEDB)

    ### OLE DB(OLEDB)介绍 #### 一、OLE技术概述 OLE(Object Linking and Embedding),即对象链接与嵌入,是一项由微软公司开发的重要技术标准,旨在为不同应用程序之间提供一种通用的数据交互方式。这项技术的...

    Go-go-ole-golang的Win32OLE实现

    【标题】"Go-go-ole-golang的Win32OLE实现"主要涉及到的是在Go语言中如何使用`go-ole`库来实现Windows操作系统上的...通过深入学习和掌握`go-ole`,可以扩展Go的应用场景,特别是在处理Windows系统特有的服务和应用时。

    OLEDB驱动程序大全 PostgreSQL-OleDB-Provider

    OLEDB(Object Linking and Embedding, Database)驱动程序是一种数据访问接口,它允许应用程序以统一的方式访问多种数据源,包括数据库、文件系统、Web服务等。在本话题中,我们将深入探讨“OLEDB驱动程序大全”中...

    Inside OLE 2nd edition.doc

    - 第12-13章:涉及OLE剪贴板和拖放操作。 - 第17-23章:深入讨论了OLE文档的各种元素。 - 第3、14和15章:涵盖了OLE自动化,包括类型信息、连接对象(连接点)和调度。 - 第6章:介绍了本地/远程透明传输。 - 第9章...

    vb中OLE之WORD

    如果要插入文件的部分内容,可以在目标文件中选定内容,复制到剪贴板,然后在VB的OLE控件上右键选择“特殊粘贴”,在“选择性粘贴”对话框中选择嵌入或链接方式,进行内容插入。 图13.35展示了嵌入和链接的区别,当...

    sap_abap_ole文档

    ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。ABAP_OLE相关文档。...

    OLE DB 教程

    **OLE DB 教程** OLE DB(Object Linking and ...学习OLE DB和ODBC对于理解底层数据库访问机制,以及在不同场景下选择合适的数据访问方式非常重要。开发者应深入掌握这两种技术,以便在实际项目中做出最佳选择。

    Delphi剪切板应用程序,查看复制的内容.rar

    本项目“Delphi剪切板应用程序”就是这样一个实例,它能够查看剪贴板中的内容,类似于Microsoft Word中的剪切板功能,但提供了更深入的定制和扩展可能性。 首先,我们要理解剪贴板(Clipboard)是操作系统提供的一...

    将数据复制或剪切到剪贴板上 .rar_C++ 对象 复制_COleDataSource_Export2Excel.zip_ole

    ---- 将数据复制或剪切到剪贴板上 ---- 1. 确定将要被复制的数据是一个本地数据还是一个嵌入对象或链接。 ---- 如果数据是一个嵌入对象或链接,创建一个指向被选定数据的COleClientItem指针。 ---- 如果数据是...

    易语言取剪贴板非文本数据.zip易语言项目例子源码下载

    《易语言取剪贴板非文本数据:深入解析与应用》 易语言,作为一款国内自主研发的编程语言,以其简洁的语法和贴近自然语言的特点,深受广大编程爱好者和初学者的青睐。本压缩包“易语言取剪贴板非文本数据.zip”提供...

    vb中ole用法

    在VB(Visual Basic)编程环境中,OLE(Object Linking and Embedding)技术允许开发者将不同应用程序的对象嵌入到另一个程序中,实现数据和功能的共享。OLE的主要目的是提供一种方式来整合不同应用软件中的数据,...

    ABAP OLE颜色代码

    ABAP OLE 颜色代码 ABAP OLE 颜色代码是指在 ABAP 编程语言中使用的颜色代码。这些代码用于在用户界面中显示不同的颜色,例如背景颜色、文字颜色、按钮颜色等。 在 ABAP 中,颜色代码通常以 šestnaestkovo ...

Global site tag (gtag.js) - Google Analytics