使用Visual C++實現OLE剪貼板
發表于:2007-07-14來源:作者:點擊數:
標簽:
一、概述 ---- 在 Windows操作系統 中存在兩種剪貼板機制:Windows標準剪貼板和OLE剪貼板機 制。 ---- 標準的Windows剪貼板是一個被所有Windows應用程序共享的系統服務,因此它并 沒有自己的句柄或類。但你可以通過CWnd類的成員函數來管理剪貼板。 ---- 自從
一、概述
---- 在
Windows操作系統中存在兩種剪貼板機制:Windows標準剪貼板和OLE剪貼板機
制。
---- 標準的Windows剪貼板是一個被所有Windows應用程序共享的系統服務,因此它并
沒有自己的句柄或類。但你可以通過CWnd類的成員函數來管理剪貼板。
---- 自從OLE(Object Linking and Embedding,對象鏈接和嵌入)誕生之后,
Windows操作系統中便出現了第二種剪貼板機制——OLE剪貼板機制。標準的Windows剪
貼板API(Application Programming Interface,應用程序編程接口)依然可用,但是
他已經被OLE數據傳輸機制來實現了。OLE支持UDT(Uniform Data Transfer,統一數據
傳輸),并可以通過拖放操作實現剪貼板的剪切、復制和粘貼等操作。OLE剪貼板除了
擁有標準Windows剪貼板的
性能外,還支持傳輸用戶自定義的剪貼板格式,并能夠在傳
輸數據時綁定OLE格式(如字體、字號等)。OLE剪貼板機制將成為更為主要的數據傳輸
機制。
---- 本文將簡要敘述標準Windows剪貼板的實現,并將重點放在討論如何通過Visual
C++實現OLE剪貼板上。
---- 二、選擇適當的剪貼板機制
---- 在選擇使用何種剪貼板機制時通常應遵循下面的原則:
---- 如果應用程序在將來又可能具有新的性能(比如現在只需要傳輸純文本,但將來
有可能需要另外傳輸字體等特性),那么使用OLE剪貼板。
---- 如果你正在使用一個OLE應用程序,或者你希望使用任何OLE特性(如拖放等)那
么你應當使用OLE剪貼板機制。
---- 如果你提供了OLE格式(如字體、字號等),那么使用OLE剪貼板機制。
---- 三、使用Windows標準剪貼板
---- 大多數Windows下的應用程序支持剪切或復制數據到Windows剪貼板中以及從剪貼
板粘貼數據至目的地。在這個過程中,剪貼板數據格式在多種應用程序之間發生了變
化。系統構架僅僅通過實現一些有限的類來支持一些有限的剪貼板格式,下表列出了
Windows標準剪貼板支持的格式(第一列“值”將在下面的程序代碼中使用)。
值 含義
CF_BITMAP 一個對應于位圖的句柄(HBITMAP)。
CF_DIB 一個包含BITMAPINFO結構并且
跟著位圖數據的內存對象。
CF_DIF 數據交互格式
CF_DSPBITMAP 有一個私有格式的位圖顯示格式。
CF_DSPENHMETAFILE 有一個私有格式的增強的元文件的顯示格式。
CF_DSPMETAFILEPICT 有一個私有格式的元圖顯示格式。
CF_DSPTEXT 有一個私有格式的文本顯示格式。
CF_ENHMETAFILE 一個增強的元文件(HENHMETAFILE結構)的句柄。
CF_GDIOBJFIRST到 CF_GDIOBJLAST 應用軟件定義
的一系列GDI對象的整型值。
CF_HDROP 一個HDROP類型的句柄,用來標識一列文件。
CF_METAFILEPICT 一個使用METAFILEPICT結構定義的元圖文件的句柄。
CF_OEMTEXT 預定義的字符的文本格式,每一行都綁定
一個CR-LF字符,并且用一個空字符表示數據結尾。
CF_OWNERDISPLAY 剪貼板擁有者的顯示格式,
剪貼板的擁有者必須顯示并且更新剪貼板的觀察器窗口,
并且接收WM_ASKCBFORMATNAME、WM_HSCROLLCLIPBOARD、
WM_PAINTCLIPBOARD、WM_SIZECLIPBOARD以及
WM_VSCROLLCLIPBOARD等消息,hMem參數必需為NULL。
CF_PALETTE 調色板的句柄
CF_PRIVATEFIRST到CF_PRIVATELAST 私有的剪貼板格式的整型值。
CF_RIFF 能夠提交比CF_WAVE標準波表文件格式更為復雜的音頻數據
CF_SYLK 微軟公司的SYLK(Symbolic Link,符號鏈接)格式
CF_TEXT 文本格式
CF_WAVE 使用一種標準波表文件格式如11kHz或22kHz等
PCM(Pulse Code Modulation,脈沖編碼調制器)提交音頻數據。
CF_TIFF TIFF圖形格式
CF_UNICODETEXT Unicode文本格式(
注意:僅適用于Windows NT或Windows 2000操作系統)
---- 表1 常用的標準剪貼板格式
---- 要編寫一個實現剪切和復制命令的函數,就要在你的應用程序中實現選定操作;
要編寫一個實現粘貼命令的函數,就需要請求剪貼板來檢測它是否包含你的應用程序能
夠支持的數據。下面的代碼實現了復制命令,其它實現可仿照進行,在此不再贅言。
---- 程序示例:
void CMyView::OnEditCopy()
{
if ( !OpenClipboard() )
{
AfxMessageBox( "無法打開剪貼板" );
return;
}
// 刪除目前剪貼板的內容
if( !EmptyClipboard() )
{
AfxMessageBox( "無法清除剪貼板" );
return;
}
// 獲取選定的數據
// 檢查是否為剪貼板支持的格式
if ( ::SetClipboardData( CF_??, hData ) == NULL )
// CF_??指定了剪貼板中數據的格式,
//表1列出了標準的剪貼板格式
{
AfxMessageBox( "無法將數據復制到剪貼板當中" );
CloseClipboard();
return;
}
// ...
CloseClipboard();
}
---- 四、使用OLE剪貼板機制
---- 首先舉個例子給你一些關于OLE剪貼板的感性認識,同時說明你需要為OLE剪貼板
做哪些事情:Microsoft Excel為工作表注冊了一個自定義的格式,這個格式能夠比其
它標準格式(如位圖或純文本等)提供更多的信息。當此數據被粘貼到一個支持工作表
的程序(比如Lotus 1-2-3)時,所有的原工作表中的公式和數值將被保留,并且還可
能會根據需要被更新。Excel同樣將數據以OLE格式存放在剪貼板中,這樣它就可以作為
一個OLE對象被嵌入。任何OLE文檔包容器(Container)(比如Microsoft Word)能夠
將該數據作為嵌入對象粘貼進文檔(比如通過“選擇性粘貼”,可以在Word中粘貼進
Excel工作表對象)。這個嵌入對象能夠通過激活Microsoft Excel來進行修改(在Word
中可以通過雙擊對象實現)。該工作表甚至可以被粘貼到一個繪圖程序(比如的畫
筆)。當然,這時你無論如何都沒有辦法將其中的數據像在工作表中一樣修改,因為它
已經是圖片了。
---- 從上例總結一下,我們應當作的事情大致有:注冊自定義的格式、傳輸格式到剪
貼板上以及實現復制、剪切和粘貼。
---- 注冊自定義格式
---- OLE剪貼板中的數據存在于多種格式。當一個用戶選擇從剪貼板粘貼數據時,應用
程序應當能夠選擇使用何種格式粘貼數據。應用程序應當提供大部分格式的信息,除非
用戶指定使用某一種特定格式粘貼(比如只粘貼文字或只粘貼圖片等)。
---- Windows定義了很多能夠通過剪貼板傳輸的標準格式(見表1),OLE也定義了很多
特殊的格式。應用程序可以通過獲取更加詳細的信息來注冊他們自己的剪貼板格式。這
可以通過使用Win32 API函數RegisterClipboardFormat來實現:
---- RegisterClipboardFormat ( lpszFormat );
---- 說明 lpzxFormat是指向一個字符串的指針,用以命名自定義的格式。該函數返回
無符號整數,該數即為格式的ID號
---- 在注冊了自定義的格式之后,便可以使用RegisterClipboardFormat函數的返回值
來標識并使用該格式。
---- 將格式傳輸到剪貼板上
---- 要增加更多的格式到剪貼板上,你必須從COleClientItem或COleServerItem繼承
一個類,并且在該類中重載OnGetClipboardData函數。在這個函數中,你應當做按照下
列步驟完成。
---- 將更多的格式放置在剪貼板上
---- 1. 建立一個COleDataSource對象。
---- 2. 傳遞該數據源到一個函數,用該函數通過訪問
COleDataSource::CacheGlobalData函數來將你的數據格式添加到支持的格式列表。
---- 3. 通過訪問COleDataSource::CacheGlobalData,為每一個你向支持的格式添加
標準格式。
---- 程序示例:
COleDataSource* CMyItem::OnGetClipboardData(
BOOL bIncludeLink,LPPOINT pptOffset, LPSIZE pSize)
{
ASSERT_VALID(this);
if (m_pServerNode == NULL)
return NULL;
COleDataSource* pDataSource =
new COleDataSource;
TRY
{
GetNativeClipboardData(pDataSource);
GetClipboardData(pDataSource, bIncludeLink,
pptOffset, pSize);
}
CATCH_ALL(e)
{
delete pDataSource;
THROW_LAST();
}
END_CATCH_ALL
ASSERT_VALID(pDataSource);
return pDataSource;
}
---- 復制、剪切和粘貼數據
---- 將數據復制或剪切到剪貼板上
---- 1. 確定將要被復制的數據是一個本地數據還是一個嵌入對象或鏈接。
---- 如果數據是一個嵌入對象或鏈接,創建一個指向被選定數據的COleClientItem指
針。
---- 如果數據是
本地化的并且應用程序是一個
服務器,那么從COleServerItem繼承一
個新的類,并創建該對象。否則,為數據建立一個COleDataSource對象。
---- 2. 訪問選定對象的CopyToClipboard成員函數。
---- 3. 如果用戶選擇剪切命令而不是復制,那么從你的應用程序中刪除那些數據。
---- 程序示例:
void CMainView::OnEditCut()
{
ASSERT(m_pSelection != NULL);
TRY
{
m_pSelection- >CopyToClipboard(TRUE);
OnEditClear();
}
CATCH_ALL(e)
{
AfxMessageBox(IDP_CLIPBOARD_CUT_FAILED);
}
END_CATCH_ALL
}
void CMainView::OnEditCopy()
{
ASSERT(m_pSelection != NULL);
TRY
{
m_pSelection- >CopyToClipboard(TRUE);
}
CATCH_ALL(e)
{
AfxMessageBox(IDP_CLIPBOARD_COPY_FAILED);
}
END_CATCH_ALL
}
---- 從剪貼板粘貼數據
---- 粘貼數據比復制更加復雜,因為你需要選擇粘貼的格式。
---- 1. 在你的視中,實現OnEditPaste來處理用戶從編輯菜單選擇粘貼命令的操作。
---- 2. 在OnEditPaste函數中,建立一個COleDataObject對象并且訪問它的
AttachClipboard成員函數來將這個對象綁定到剪貼板。
---- 3. 訪問COleDataObject::IsDataAvailable函數來檢查是否可以使用特殊的格
式。當然,你也可以通過循環使用COleDataObject::BeginEnumFormats來尋找其它格式
直到你找到了最適合的格式。
---- 4. 粘貼數據。
---- 程序示例:
CRectItem* CMainView::DoPasteItem(BOOL bLink,
COleDataObject* pDataObject,CPoint* pPoint,
CLIPFORMAT cfFormat)
{
BeginWaitCursor();
CRectItem* pItem = GetDocument()- >CreateItem();
ASSERT_VALID(pItem);
BOOL bAllowAdjust = (pPoint == NULL) ? TRUE : FALSE;
COleDataObject clipboardData;
if (pDataObject == NULL)
{
clipboardData.AttachClipboard();
pDataObject = &clipboardData;
}
TRY
{
if (cfFormat == CMainDoc::m_cfPrivate)
{
DoPasteNative(pDataObject, pPoint, pItem);
}
else if (!bLink && cfFormat == 0 &&
pDataObject- >IsDataAvailable(CMainDoc::m_cfPrivate))
{
DoPasteNative(pDataObject, pPoint, pItem);
}
else if (bAllowAdjust)
{
CPoint ptDef(10, -10);
DoPasteStandard(bLink, pDataObject,
&ptDef, pItem, cfFormat);
}
else
{
DoPasteStandard(bLink, pDataObject,
pPoint, pItem, cfFormat);
}
if (bAllowAdjust)
{
GetDocument()- >AdjustItemPosition(pItem);
}
}
CATCH_ALL(e)
{
TRACE0("failed to embed/link an OLE object\n");
pItem- >Delete();
pItem = NULL;
}
END_CATCH_ALL
SetSelection(pItem, TRUE);
GetDocument()- >SetModifiedFlag();
GetDocument()- >UpdateAllViews(NULL, 0, pItem);
EndWaitCursor();
return pItem;
}
void CMainView::OnEditPaste()
{
COleDataObject clipboardData;
clipboardData.AttachClipboard();
DoPasteItem(&clipboardData);
UpdateAllViews();
}
---- 說明 將粘貼操作(如OnEditPaste函數)與實現粘貼的函數(如DoPasteItem)分
開的最大優點在于,當數據被拖放到你的應用程序中時,可以使用同樣的粘貼代碼。比
如你可以在OnDrop函數中訪問DoPasteItem函數來重用代碼。另外,程序代碼中的
DoPasteNative和DoPasteStandard函數僅僅說明一個概念,因此不再實現。
原文轉自:http://www.kjueaiud.com