《Windows核心编程》---剪贴板
剪貼板是由系統(tǒng)定義的,并不屬于任何一個特定的進程。系統(tǒng)中所有進程都可以訪問和設(shè)置剪貼板。剪貼板最大的特點就是數(shù)據(jù)傳輸沒有明確的目標(biāo),數(shù)據(jù)是被動訪問的;剪貼板的內(nèi)容可以被多次訪問,直到新的數(shù)據(jù)寫入。剪貼板是一種可供選擇的進程間通信方式,但由于系統(tǒng)中任何一個進程都可以都可以無限制地訪問剪貼板,因此,它是一種不可靠的通信方式。
1)獲取和設(shè)置剪貼板數(shù)據(jù)
涉及到的API有:OpenClipboard、EmptyClipboard、SetClipboardData、GetClipboardData、CloseClipboard等。
?
OpenClipboard用于打開剪貼板,獲得剪貼板的句柄:
BOOL WINAPI OpenClipboard(
??__in_opt? HWND hWndNewOwner //指定的窗口可以收到剪貼板操作所產(chǎn)生的消息
?????????????????????????????????????????????? //如果為NULL,則采用當(dāng)前任務(wù)的窗口
);
?
EmptyClipboard用于清空剪貼板中的內(nèi)容:
BOOL WINAPI EmptyClipboard(void);
?
SetClipboardData用于設(shè)置剪貼板的內(nèi)容:
HANDLE WINAPI SetClipboardData(
? __in????? UINT uFormat,?????? //指定數(shù)據(jù)格式,可以是標(biāo)準系統(tǒng)格式,也可以是用戶自定義格式
? __in_opt? HANDLE hMem???? //需要設(shè)置的數(shù)據(jù)的內(nèi)存句柄;需使用全局內(nèi)存管理的函數(shù)分配和
???????????????????????????????????? //設(shè)置,且在分配時需指定GMEM_MOVEABLE標(biāo)志
);
?
GetClipboardData用于從剪貼板獲取數(shù)據(jù):
HANDLE WINAPI GetClipboardData(
? __in? UINT uFormat //指定獲取的數(shù)據(jù)的格式,獲得的數(shù)據(jù)使用句柄返回
);
?
2)一般來說利用剪貼板進行數(shù)據(jù)通信是不具有實時性,所有操作都依賴于用戶。除非使用剪貼板查看器Viewer,這樣就可以立即知道剪貼板中內(nèi)容的變化。
系統(tǒng)提供了WM_DRAWCLIPBOARD消息用于監(jiān)視剪貼板的變化。如果調(diào)用SetClipboardViewer函數(shù)設(shè)置了窗口為剪貼板查看器,那么當(dāng)剪貼板中內(nèi)容變化時,所注冊的查看器窗口就會收到WM_CHANGECBCHAIN消息和WM_DRAWCLIPBOARD消息。SetClipboardViewer函數(shù)原型如下:
HWND WINAPI SetClipboardViewer(
? __in? HWND hWndNewViewer //指定監(jiān)視窗口
);
剪貼板查看器的代碼例子如下:
HINSTANCE hinst;
UINT uFormat = (UINT)(-1);
BOOL fAuto = TRUE;
?
LRESULT CALLBACK MainWndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
??? static HWND hwndNextViewer;
?
??? HDC hdc;
??? HDC hdcMem;
??? PAINTSTRUCT ps;
??? LPPAINTSTRUCT lpps;
??? RECT rc;
??? LPRECT lprc;
??? HGLOBAL hglb;
??? LPSTR lpstr;
??? HBITMAP hbm;
??? HENHMETAFILE hemf;
??? HWND hwndOwner;
?
??? switch (uMsg)
??? {
??????? case WM_PAINT: //收到WM_PAINT消息后顯示剪貼板中的數(shù)據(jù)
??????????? hdc = BeginPaint(hwnd, &ps);
??????????? // Branch depending on the clipboard format.
???????? ??? ?//uFormat全局變量,在WM_DRAWCLIPBOARD和WM_COMMAND
???????? ???//消息處理中,使用SetAutoView設(shè)置
???????? ???//根據(jù)剪貼板中數(shù)據(jù)的不同格式,使用不同的顯示方式
??????????? switch (uFormat)
??????????? {
??????????????? case CF_OWNERDISPLAY: //剪貼板的所有者必須顯示并刷新Viewer的窗口
???????? ???????????hwndOwner = GetClipboardOwner();//獲得剪貼板的所有者
??????????????????????????? //獲取剪貼板的數(shù)據(jù)
??????????????????? hglb = GlobalAlloc(GMEM_MOVEABLE,
??????????????????????? sizeof(PAINTSTRUCT));
??????????????????? lpps = (LPPAINTSTRUCT)GlobalLock(hglb);
??????????????????? memcpy(lpps, &ps, sizeof(PAINTSTRUCT));
??????????????????? GlobalUnlock(hglb);
?????????????????????????? //向剪貼板所有者發(fā)送WM_PAINTCLIPBOARD消息
???? ???????????????SendMessage(hwndOwner, WM_PAINTCLIPBOARD,
??????????????????????? (WPARAM) hwnd, (LPARAM) hglb);
??????????????????? GlobalFree(hglb);
??????????????????? break;
?
??????????????? case CF_BITMAP: //位圖
??????????????????? hdcMem = CreateCompatibleDC(hdc);
??????????????????? if (hdcMem != NULL)
??????????????????? {
??????????????????????? if (OpenClipboard(hwnd)) //打開剪貼板
??????????????????????? {
??????????????????????????? hbm = (HBITMAP)
??????????????????????????????? GetClipboardData(uFormat); //獲取剪貼板的數(shù)據(jù)
???????????????????????????????????? ?//將位圖選擇進DC,顯示在窗口客戶區(qū)
??????????????????????????? SelectObject(hdcMem, hbm);
??????????????????????????? GetClientRect(hwnd, &rc);
??????????????????????????? BitBlt(hdc, 0, 0, rc.right, rc.bottom,
??????????????????????????????? hdcMem, 0, 0, SRCCOPY);
??????????????????????????? CloseClipboard();//關(guān)閉剪貼板
??????????????????????? }
??????????????????????? DeleteDC(hdcMem); //釋放DC
??????????????????? }
??????????????????? break;
?
??????????????? case CF_TEXT: //文本
??????????????????? if (OpenClipboard(hwnd)) //打開剪貼板
???????? ???????????{
??????????????????????? hglb = GetClipboardData(uFormat); //獲得剪貼板數(shù)據(jù)
??????????????????????? lpstr = GlobalLock(hglb);
?????????????????????????? ??? //將文本繪制在窗口客戶區(qū)
??????????????????????? GetClientRect(hwnd, &rc);
??????????????????????? DrawText(hdc, lpstr, -1, &rc, DT_LEFT);
??????????? ????????????GlobalUnlock(hglb);
??????????????????????? CloseClipboard();//關(guān)閉剪貼板
??????????????????? }
??????????????????? break;
?
??????????????? case CF_ENHMETAFILE: //增強格式圖元文件
??????????????????? if (OpenClipboard(hwnd)) //打開剪貼板
??????????????????? {
??????????????????? ????hemf = GetClipboardData(uFormat); //獲取剪貼板數(shù)據(jù)
??????????????????????????? ??? //調(diào)用PlayEnhMetaFile在窗口客戶區(qū)上顯示
??????????????????????? GetClientRect(hwnd, &rc);
??????????????????????? PlayEnhMetaFile(hdc, hemf, &rc);
??????????????????????? CloseClipboard();
??????????????????? }
??????????????????? break;
?
??????????????? case 0: //剪貼板為空
??????????????????? GetClientRect(hwnd, &rc);
??????????????????? //在客戶區(qū)中央顯示
??????????????????? DrawText(hdc, "The clipboard is empty.", -1,
??????????????????????? &rc, DT_CENTER | DT_SINGLELINE |
??????????????????????? DT_VCENTER);
??????????????????? break;
?
??????????????? default: //不支持的其他格式
??????????????????? GetClientRect(hwnd, &rc);
??????????????????? DrawText(hdc, "Unable to display format.", -1,
??????????????????????? &rc, DT_CENTER | DT_SINGLELINE |
??????????????????????? DT_VCENTER);
?????????? ?}
??????????? EndPaint(hwnd, &ps);
??????????? break;
?
??????? case WM_SIZE: //如果窗口大小改變,通知剪貼板所有者窗口
??????????? if (uFormat == CF_OWNERDISPLAY)
??????????? {
??????????????? hwndOwner = GetClipboardOwner();//獲取剪貼板所有者
??????????????? hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(RECT));
??????????????? lprc = GlobalLock(hglb);
??????????????? GetClientRect(hwnd, lprc);
??????????????? GlobalUnlock(hglb);
?
??????????????? SendMessage(hwndOwner, WM_SIZECLIPBOARD,
??????????????????? (WPARAM) hwnd, (LPARAM) hglb);
?
??????????????? GlobalFree(hglb);
??????????? }
??????????? break;
?
??????? case WM_CREATE: //當(dāng)窗口創(chuàng)建時,在剪貼板Viewer鏈中增加一個
??????????? hwndNextViewer = SetClipboardViewer(hwnd);
??????????? break;
?
??????? case WM_CHANGECBCHAIN:
??????????? // If the next window is closing, repair the chain.
??????????? if ((HWND) wParam == hwndNextViewer)
??????????????? hwndNextViewer = (HWND) lParam;
??????????? // Otherwise, pass the message to the next link.
? ??????????else if (hwndNextViewer != NULL)
??????????????? SendMessage(hwndNextViewer, uMsg, wParam, lParam);
??????????? break;
?
??????? case WM_DESTROY:
???????? ???? //窗口hwnd銷毀時,從剪貼板查看器鏈中移除
??????????? ChangeClipboardChain(hwnd, hwndNextViewer);
??????????? PostQuitMessage(0);
??????????? break;
?
??????? case WM_DRAWCLIPBOARD:? // clipboard contents changed.
??????????? // Update the window by using Auto clipboard format.
??????????? SetAutoView(hwnd);
??????????? // Pass the message to the next window in clipboard
??????????? // viewer chain.
??????????? SendMessage(hwndNextViewer, uMsg, wParam, lParam);
??????????? break;
?
??????? case WM_INITMENUPOPUP: //當(dāng)popup菜單彈出時收到此消息
??????????? if (!HIWORD(lParam)) //根據(jù)剪貼板中內(nèi)容的格式設(shè)置菜單
??????????????? InitMenu(hwnd, (HMENU) wParam);
??????????? break;
?
? ??????case WM_COMMAND: //處理用戶菜單輸入
??????????? switch (LOWORD(wParam))
??????????? {
??????????????? case IDM_EXIT: //用戶點擊“退出”菜單項
??????????????????? DestroyWindow(hwnd);
??????????????????? break;
?
??????????????? case IDM_AUTO: //用戶點擊“Auto”菜單項
??????????????????? SetAutoView(hwnd); //設(shè)置顯示格式為自動
??????????????????? break;
?
??????????????? default:
??????????????????? fAuto = FALSE;
??????????????????? uFormat = LOWORD(wParam);
??????????????????? InvalidateRect(hwnd, NULL, TRUE);
??????????? }
??????????? break;
?
??????? default: //其他消息
?????? ?????return DefWindowProc(hwnd, uMsg, wParam, lParam);
??? }
??? return (LRESULT) NULL;
}
?
/**********************************************************
* void WINAPI SetAutoView(HWND hwnd)
* 獲取剪貼板的主要格式,并設(shè)置顯示方式
**********************************************************/
void WINAPI SetAutoView(HWND hwnd)
{
??? static UINT auPriorityList[] = {
??????? CF_OWNERDISPLAY,
??????? CF_TEXT,
??????? CF_ENHMETAFILE,
??????? CF_BITMAP
??? };
//設(shè)置剪貼板主要格式,設(shè)置顯示格式
//uFormat在收到WM_PAINT消息時用到
??? uFormat = GetPriorityClipboardFormat(auPriorityList, 4);
??? fAuto = TRUE;
?
??? InvalidateRect(hwnd, NULL, TRUE);
??? UpdateWindow(hwnd);
}
?
/**************************************************************
* 功能:根據(jù)剪貼板中內(nèi)容的格式,設(shè)置菜單項供用戶選擇顯示方式
* 參數(shù):hwnd--窗口句柄
*?????? hmenu--菜單句柄
**************************************************************/
void WINAPI InitMenu(HWND hwnd, HMENU hmenu)
{
??? UINT uFormat;
??? char szFormatName[80];
??? LPCSTR lpFormatName;
??? UINT fuFlags;
??? UINT idMenuItem;
?
??? // If a menu is not the display menu, no initialization is necessary.
??? if (GetMenuItemID(hmenu, 0) != IDM_AUTO)
??????? return;
??? // Delete all menu items except the first.
??? while (GetMenuItemCount(hmenu) > 1)
??????? DeleteMenu(hmenu, 1, MF_BYPOSITION);
?
??? // Check or uncheck the Auto menu item.
??? fuFlags = fAuto ? MF_BYCOMMAND | MF_CHECKED :
??????? MF_BYCOMMAND | MF_UNCHECKED;
??? CheckMenuItem(hmenu, IDM_AUTO, fuFlags);
?
??? // If there are no clipboard formats, return.
??? if (CountClipboardFormats() == 0)
??????? return;
?
??? // Open the clipboard.
??? if (!OpenClipboard(hwnd))
??????? return;
?
??? // Add a separator and then a menu item for each format.
??? AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
??? uFormat = EnumClipboardFormats(0);
??? while (uFormat)
??? {
??????? // Call an application-defined function to get the name
??????? // of the clipboard format.
??????? lpFormatName = GetPredefinedClipboardFormatName(uFormat);
??????? // For registered formats, get the registered name.
??????? if (lpFormatName == NULL)
??????? {
?????????????????? // Note that, if the format name is larger than the
?????????????????? // buffer, it is truncated.
??????????? if (GetClipboardFormatName(uFormat, szFormatName,
??????????????????? sizeof(szFormatName)))
??????????????? lpFormatName = szFormatName;
??????????? else
? ??????????????lpFormatName = "(unknown)";
??????? }
?
??????? // Add a menu item for the format. For displayable
??????? // formats, use the format ID for the menu ID.
??????? if (IsDisplayableFormat(uFormat))
??????? {
??????????? fuFlags = MF_STRING;
??????????? idMenuItem = uFormat;
??????? }
??????? else
??????? {
??????????? fuFlags = MF_STRING | MF_GRAYED;
??????????? idMenuItem = 0;
??????? }
??????? AppendMenu(hmenu, fuFlags, idMenuItem, lpFormatName);
??????? uFormat = EnumClipboardFormats(uFormat);
??? }
??? CloseClipboard();
}
?
BOOL WINAPI IsDisplayableFormat(UINT uFormat)
{
??? switch (uFormat)
??? {
??????? case CF_OWNERDISPLAY:
??????? case CF_TEXT:
??????? case CF_ENHMETAFILE:
??????? case CF_BITMAP:
??????????? return TRUE;
??? }
??? return FALSE;
}
?
3)剪貼板中存在各種數(shù)據(jù)格式,系統(tǒng)使用一個UINT類型的數(shù)據(jù)來表示剪貼板中數(shù)據(jù)類型。在這些格式信息中,有很多是各種應(yīng)用程序之間通用的,比如文本、位圖等。這些數(shù)據(jù)格式由系統(tǒng)預(yù)先定義,稱為標(biāo)準格式;當(dāng)然應(yīng)用程序也可自行定義剪貼板的數(shù)據(jù)格式,這樣可以方便地在同一個應(yīng)用程序的不同實例間進行數(shù)據(jù)傳遞而不用對數(shù)據(jù)格式進行過多的處理(典型的就包括word)。
?
常見標(biāo)準格式:
CF_BITMAP??? //位圖句柄(HBITMAP)
CF_DIB???????????? //內(nèi)存位置包含BITMAPINFO結(jié)構(gòu)和位圖數(shù)據(jù)
CF_ENHMETAFILE???????? //增強的圖元文件句柄(HENHMETAFILE)
CF_OEMTEXT??????? //OEM字符集的字符串(以CR-LF格式換行)
CF_OWNERDISPLAY??? //由剪貼板查看器查看的格式
CF_PALETTE? //調(diào)色板數(shù)據(jù)
CF_RIFF? //標(biāo)準的CF_WAVE波形數(shù)據(jù)
CF_TEXT????????? //ANSI字符串(以CR-LF格式換行)
CF_WAVE?????? //PCM波形
CF_TIFF? //Tagged圖像文件格式
CF_UNICODETEXT?????? //Unicode字符串
?
自定義格式:
調(diào)用函數(shù)RegisterClipboardFormat可以自定義格式:
UINT WINAPI RegisterClipboardFormat(//返回值是系統(tǒng)分配的格式類型值(UINT)
? __in? LPCTSTR lpszFormat //格式名,
);
?
多種格式:
很多情況下,數(shù)據(jù)的格式不止一種,比如格式化的文本有效的格式不止一種(例如從Word中復(fù)制的數(shù)據(jù)、從網(wǎng)頁中復(fù)制的數(shù)據(jù)等),因此可能存在多重格式。
以下幾個API函數(shù)是用于獲取當(dāng)前剪貼板中的格式信息的:
GetPriorityClipboardFormat的功能是檢測剪貼板中是否有paFormatPriorityList參數(shù)指定的格式數(shù)組中的格式存在,如果有則返回格式數(shù)組中的第一個剪貼板當(dāng)前具有的格式:
int WINAPI GetPriorityClipboardFormat(
? __in? UINT *paFormatPriorityList, //格式數(shù)組,存儲用于檢測的格式信息
? __in? int cFormats??? //paFormatPriorityList數(shù)組的大小
);
?
CountClipboardFormats函數(shù)用于返回當(dāng)前剪貼板中具有的不同格式的數(shù)量:
int WINAPI CountClipboardFormats(void);
?
EnumClipboardFormats函數(shù)用于列舉當(dāng)前剪貼板中的所有格式:
UINT WINAPI EnumClipboardFormats(
? __in? UINT format?? //指定一個已知的格式,通過函數(shù)返回值返回下一個格式
);
?
GetUpdatedClipboardFormats函數(shù)用于獲取當(dāng)前剪貼板的所有格式:
BOOL WINAPI GetUpdatedClipboardFormats(
? __out? PUINT lpuiFormats, //指向用于保存返回的格式數(shù)組的緩沖區(qū)
? __in?? UINT cFormats, //lpuiFormats可以容納的格式信息的數(shù)量
? __out? PUINT pcFormatsOut //返回真是的數(shù)組大小
);
?
由于剪貼板數(shù)據(jù)會有多種格式,在調(diào)用GetClipboardData函數(shù)獲取數(shù)據(jù)時,應(yīng)該指定格式。一般情況下,指定不同格式,將獲得不同的內(nèi)容。
?
剪貼板數(shù)據(jù)的格式信息:
每一個剪貼板格式都有一個格式名,格式名是一個字符串,使用GetClipboardFormatName函數(shù)可以獲得:
int WINAPI GetClipboardFormatName(
? __in?? UINT format, //要檢索的格式ID
? __out? LPTSTR lpszFormatName, //存儲返回的格式名的緩沖區(qū)
? __in?? int cchMaxCount //拷貝到緩沖區(qū)的最大數(shù)據(jù)長度
);
總結(jié)
以上是生活随笔為你收集整理的《Windows核心编程》---剪贴板的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ViewGroup之getScrollX
- 下一篇: 魔百盒服务器响应超时,hitool烧写f