进程间通信——剪切板
要點總結:
1、剪切板是操作系統維護的一塊內存區域,本機所有進程都可以訪問。 2、剪切板內存從哪里來?不是一開機就分配的,是程序要將數據放入剪切板時分配內存的。 3、但:malloc和 new內存是在當前進程的私有地址空間中分配內存,并不能被所有進程共享。 4、所有:用GlobalAlloc分配內存,此內存不為任一進程私有,而是由操作系統管理。 5、特點:只能用于本地進程間通信。引子
由于在啟動一個進程后,操作系統會給這個進程分配 4GB 的私有地址空間,至于為何有 4GB 這么大,
那得考慮進程的私有地址空間和實際物理內存地址空間之間的映射以及頁交換等等細節問題了,這里不予討論,
從名字就可以知道,既然操作系統給每一個進程分配的是私有地址空間,
自然,這段地址空間也只有這個進程自己才能訪問了,不然還稱為私有干嗎呢?
既然這段私有地址空間只能由進程本身訪問,那也就說明別的進程是不能夠隨意的訪問這個進程的地址空間的,
而本篇博文介紹的是進程間的通信,而上面又說任意兩個進程之間是并能夠互相訪問對方的私有地址空間的,
都不能訪問了,那還通信個屁啊 ?
自然上面的訪問對方進程的私有地址空間是行不通了,那應該還有其他辦法的 !!!
解決方法:
如果我在物理內存中劃分出一塊內存,這一塊內存不為任何的進程所私有,但是任何的進程又都可以訪問這塊內存,
那么?進程 A?就可以往這塊內存中存放數據?Data?,然后?進程 B?也是可以訪問這塊內存的,從而?進程 B?就可以訪問到數據?Data?了,
這樣不就實現了?進程 A?和?進程 B?之間的通信了 !!!
而上面的這種思路就是剪貼板了。
當然解決進程間通信還有好幾種思路,這將會在后續博文中介紹,本篇博文暫只介紹利用剪貼板來實現進程間的通信。
????????????
????????????
剪貼板定義
剪貼板是由操作系統維護的一塊內存區域,這塊內存區域不屬于任何單獨的進程,但是每一個進程又都可以訪問這塊內存區域,
而實質上當在一個進程中復制數據時,就是將數據放到該內存區域中,
而當在另一個進程中粘貼數據時,則是從該塊內存區域中取出數據。 ? ? ? ? ??? ? ? ? ? ?
剪貼板操作
其實在剪貼板中也就那么幾個 API 在使用,所以在這里的還是本著 API 介紹為主,
不管三七二十一,先列出常用的 API 再說(到后面結合 Demo 的使用即可)。? ? ? ? ? ? ? ??
剪貼板的打開 – OpenClipboard
要想把數據放置到剪貼板中,則必須先打開剪貼板,而這是通過?OpenClipboard?成員函數實現:
BOOL? OpenClipboard(HWND??hWndNewOwner?);
第一個參數?hWndNewOwner?指向一個與之關聯的窗口句柄,即代表是這個窗口打開剪貼板,
如果這個參數設置為?NULL?的話,則以當前的任務或者說是進程來打開剪貼板。
如果打開剪貼板成功,則該函數返回非?0?值,如果其他程序已經打開了剪貼板,
那么當前這個程序就無法再打開剪貼板了,所以會致使打開剪貼板失敗,從而該函數返回?0?值。
其實這也好理解,你想啊,剪貼板總共才那么一塊內存區域,你?進程 A?要往里面寫數據,你?進程 B?又要往里面寫數據,那不亂套去,
解決這個亂套的辦法就是,如果我?進程 A?正在往剪貼板里面寫數據(可以理解為?進程 A?打開剪貼板了),那么?進程 B?就不能往剪貼板里頭寫數據了,
既然要讓?進程 B?不能往剪貼板中寫數據了,那我就讓?進程 B?打開剪貼板失敗不就得了。
所以如果某個程序已經打開了剪貼板,那么其他應用程序將不能修改剪貼板,
直到打開了剪貼板的這個程序調用了?CloseClipboard?函數,
并且只有在調用了?EmptyClipboard?函數之后,打開剪貼板的當前窗口才能擁有剪貼板,
注意是必須要在調用了?EmptyClipboard?函數之后才能擁有剪貼板。?? ? ? ? ? ? ? ? ??
剪貼板的清空 - EmptyClipboard
這個函數將清空剪貼板,并釋放剪貼板中數據的句柄,然后將剪貼板的所有權分配給當前打開剪貼板的窗口,
因為剪貼板是所有進程都可以訪問的,
所以應用程序在使用這個剪貼板時,有可能已經有其他的應用程序把數據放置到了剪貼板上,
因此該進程打開剪貼板之后,就需要調用?EmptyClipboard?函數來清空剪貼板,
釋放剪貼板中存放的數據的句柄,并將剪貼板的所有權分配給當前的進程,
這樣做之后當前打開這個剪貼板的程序就擁有了剪貼板的所有權,因此這個程序就可以往剪貼板上放置數據了。
BOOL?EmptyClipboard(void);
??????????????????????????????
剪貼板的關閉 - CloseClipboard
如果某個進程打開了剪貼板,則在這個進程沒有調用?CloseClipboard?函數關閉剪貼板句柄之前,
其他進程都是無法打開剪貼板的,所以我們每次使用完剪貼板之后都應該關閉剪貼板。
注意,這里的關閉剪貼板并不代表當前打開剪貼板的這個程序失去了對剪貼板的所有權,
只有在別的程序調用了?EmptyClipboard?函數之后,當前的這個程序才會失去對剪貼板的所有權,
而那個調用?EmptyClipboard?函數的程序才能擁有剪貼板。
BOOL?CloseClipboard(void);
???????????????????????????
數據發送到剪貼板 - SetClipboardData
可以通過?SetClipboardData?函數來實現往剪貼板中放置數據,這個函數以指定的剪貼板格式向剪貼板中放置數據。
HANDLE? SetClipboardData(UINT uFormat,? HANDLE hMem );第一個參數?uFormat?用來指定要放到剪貼板上的數據的格式,
比如常見的有?CF_BITMAP?,CF_TEXT?,CF_DIB?等等(其他格式可以參考?MSDN)。
第二個參數?hMem?用來指定具有指定格式的數據的句柄,該參數可以是?NULL?,
如果該參數為?NULL?則表明直到有程序對剪貼板中的數據進行請求時,
該程序(也就是擁有剪貼板所有權的進程)才會將數據復制到剪貼板中,也就是提供指定剪貼板格式的數據,
上面提及的就是延遲提交技術,這個延遲提交技術將會在后面做詳細的介紹。
??????????????
剪貼板中數據格式判斷 – IsClipboardFormatAvaliable
BOOL? IsClipboardFormatAvailable( UINT format );該函數用來判斷剪貼板上的數據格式是否為?format?指定的格式。
?????????????
剪貼板中數據接收 - GetClipboardData
HANDLE? GetClipboardData( UINT uFormat );該函數根據?uFormat?指定的格式,返回一個以指定格式存在于剪貼板中的剪貼板對象的句柄。
?????????????
?????????????
全局內存分配 – HGLOBAL
剪貼板中的內存從何而來
從上面的介紹中可以知道剪貼板其實就是一塊內存,那么這塊內存是什么時候分配的呢?
難不成說一開機,操作系統就給剪貼板分配個幾?M?的內存的吧?
這種方式也太遜色了,你想啊,我的程序要往剪貼板中放置的數據,我事先又不曉得數據長度,
所以,一開機操作系統究竟要給剪貼板分配多少內存呢?很明顯,太不動態了,不可取。
要想動態的話,那有一種方案,就是當我的程序要往剪貼板中放置數據的時候來確定要分配給剪貼板的內存的大小,
很明顯,既然我都知道要往剪貼板中放置那些數據了,自然我也就知道了這些數據的長度,
那么我就可以以這個數據長度來給剪貼板分配內存了,這是很動態的了吧,所以這種方案是可取的,
但關鍵是,當我們以前在程序中分配內存的時候,都是使用的標準?C?運行庫中的?malloc?或者是?C++?中的?new?關鍵字,
(當然分配內存還有很多其他的函數,比如就有內核中的執行體中就有很多分配內存的函數,這里不討論),
而使用?malloc?或者?new?有一個問題,那就是,用這個兩個東西來分配的內存空間都是在當前進程的私有地址空間上分配內存,
也就是它們兩個東東所分配的內存空間為進程私有地址空間所有,并不為所有進程所共享,
上面提到了,任何進程之間都是不能訪問對方的私有地址空間的,你把剪貼板中的內存分配到了你當前進程的私有地址空間上,
而其他進程又不能訪問你這個進程的私有地址空間,那怎么能夠訪問剪貼板呢?
很明顯,不能使用?malloc?和?new?關鍵字來分配內存給剪貼板。
我們應該要使用另外一個特殊一點的函數來分配內存給剪貼板,
這個特殊函數所分配的內存不能夠是在進程的私有地址空間上分配,而是要在全局地址空間上分配內存,
這樣這個函數所分配的內存才能夠被所有的進程所共享,這樣,剪貼板中的數據就可以被其他的進程所訪問了。
?????????????????????
GlobalAlloc 函數
GlobalAlloc?函數是從堆上分配指定數目的字節,
與其他的內存管理函數相比,全局內存函數的運行速度會稍微慢一些(等下會解釋為什么會慢),
但是全局函數支持動態數據交換,同時,其分配的內存也不為任何一個進程所私有,而是由操作系統來管理這塊內存,
所以用在給剪貼板分配內存空間是很適合的。
這里有讀者可能會問:
為什么我們在自己的應用程序中不使用?GlobalAlloc?函數來分配內存,而是要使用?malloc?或者?new??來實現?
其實,這個也只用稍微想想就知道了,你想啊,使用?malloc?或者?new?分配的內存是在進程的私有地址空間上分配的,
這片私有地址空間都是歸這個進程所擁有,所管理的,自然,在以后對這塊內存的讀寫會快很多的,
而全局內存不屬于這個進程,你下次要去訪問全局內存的時候,還得通過映射轉換,這樣肯定是運行效率低下一些了,
簡單點就可以這樣理解,你使用?malloc?或者?new?分配的內存和你的進程隔得很近,程序要過去拿數據 - 得,很近吧,
而是用?GlobalAlloc?函數分配的內存和你的進程隔得很遠,程序要過去拿數據 - 太遠了,耗時。
應用程序在調用了?SetClipboardData?函數之后,
系統就擁有了?hMem?參數所標識的數據對象,該應用程序可以讀取這個數據對象,
但是在應用程序調用?CloseClipboard?函數之前,它都是不能釋放該對象的句柄的,或者鎖定這個句柄,
如果?hMem?標識一個內存對象,那么這個對象必須是利用?GMEM_MOVEABLE?標識調用?GlobalAlloc?函數為其分配內存的。
HGLOBAL? WINAPI? GlobalAlloc( UINT? uFlags,?? SIZE_T? dwBytes );第一個參數?uFlags?用來指定分配內存的方式。其取值如下列表所示
(但是在剪貼板的使用中,由于要實現動態數據交換,所以必須得使用?GHND?或者?GMEM_MOVEABLE):
| 值 | 描述 |
| GHND | 即?GMEM_MOVEABLE?和?GMEM_ZEROINIT?的組合。 |
| GMEM_FIXED | 分配一塊固定內存,返回值是一個指針。 |
| GMEM_MOVEABLE | 分配一塊可移動內存。 |
| GMEM_ZEROINIT | 初始化內存的內容為 0 |
| GPTR | 即?GMEM_FIXED?和?GMEM_ZEROINIT?的組合。 |
第二個參數?dwBytes?用來指定分配的字節數。
???????????????????
GlobalReAlloc 函數
HGLOBAL? WINAPI? GlobalReAlloc(HGLOBAL hMem,? SIZE_T dwBytes,? UINT uFlags);該函數為再分配函數,即在原有的數據對象?hMem?上,為其擴大內存空間。
第一個參數?hMem?代表由?GlobalAlloc?函數返回的數據對象句柄。
第二個參數?dwBytes?指定需要重新分配的內存的大小。
第三個參數?uFlags?指定分配的方式(可以參考?GlobalAlloc?函數)。
???????????????????
GlobalSize 函數
SIZE_T? WINAPI? GlobalSize( HGLOBAL? hMem );該函數用來返回內存塊的大小。
第一個參數?hMem?代表由?GlobalAlloc?函數返回的數據對象句柄。
???????????????
GlobalLock 函數
LPVOID? WINAPI? GlobalLock( HGLOBAL? hMem );該函數的作用是對全局內存對象加鎖,然后返回該對象內存塊第一個字節的指針。
第一個參數?hMem?代表由?GlobalAlloc?函數返回的數據對象句柄。
???????????
GlobalUnLock 函數
BOOL? WINAPI? GlobalUnlock( HGLOBAL? hMem );你通過上面的?GlobalLock?函數可以獲得這塊全局內存的訪問權,
加鎖的意思就是你已經在使用這塊全局內存了,別的程序就不能再使用這塊全局內存了,
而如果你一直不解鎖,那也不是個事啊,別的程序將會一直都使用不了這塊全局內存,
那還叫全局內存干嗎啊?所以這個函數就是用來對全局內存對象解鎖。
第一個參數?hMem?代表由?GlobalAlloc?函數返回的數據對象句柄。
?????????????????
GlobalFree 函數
HGLOBAL? WINAPI? GlobalFree( HGLOBAL? hMem );該函數釋放全局內存塊。
第一個參數?hMem?代表由?GlobalAlloc?函數返回的數據對象句柄。
???????????????
?????????????
Demo1 – ConsoleClipboard(剪貼板常用手法)
整個項目結構很簡單:
ConsoleClipboard.h
#ifndef CONSOLE_CLIP_BOARD_H #define CONSOLE_CLIP_BOARD_H ? #include <Windows.h> #include <iostream> ? using namespace std; ? const char * pStrData = "Zachary"; ? void SetClipBoardData(); ? void GetClipBoardData(); ? ? #endif ConsoleClipboard.cpp #include "ConsoleClipboard.h" ? int main(int argc, char * argv) { SetClipBoardData(); GetClipBoardData(); ? system("pause"); } ? void SetClipBoardData() { //將 OpenClipboard 函數的參數指定為 NULL,表明為當前進程打開剪貼板 if(OpenClipboard(NULL)) { char * pDataBuf; ? //全局內存對象 HGLOBAL hGlobalClip; ? //給全局內存對象分配全局內存 hGlobalClip = GlobalAlloc(GHND, strlen(pStrData) + 1); //通過給全局內存對象加鎖獲得對全局內存塊的引用 pDataBuf = (char *)GlobalLock(hGlobalClip); strcpy(pDataBuf, pStrData); //使用完全局內存塊后需要對全局內存塊解鎖 GlobalUnlock(hGlobalClip); ? //清空剪貼板 EmptyClipboard(); //設置剪貼板數據,這里直接將數據放到了剪貼板中,而沒有使用延遲提交技術 SetClipboardData(CF_TEXT, hGlobalClip); //關閉剪貼板 CloseClipboard(); ? cout<<"設置剪貼板為: "<<pStrData<<endl<<endl; } } ? void GetClipBoardData() { if(OpenClipboard(NULL)) { //判斷剪貼板中的數據格式是否為 CF_TEXT if(IsClipboardFormatAvailable(CF_TEXT)) { char * pDataBuf; HGLOBAL hGlobalClip; ? //從剪貼板中獲取格式為 CF_TEXT 的數據 hGlobalClip = GetClipboardData(CF_TEXT); pDataBuf = (char *)GlobalLock(hGlobalClip); GlobalUnlock(hGlobalClip); ? cout<<"從剪貼板中獲取到數據: "<<pDataBuf<<endl<<endl; } CloseClipboard(); } }效果展示:
程序運行效果:
打開記事本進行粘貼操作:
???????????
????????????
延遲提交技術
什么是延遲提交技術?
當把數據放入剪貼板中時,一般來說要制作一份數據的副本,
也就是要分配全局內存,然后將數據再復制一份,然后再將包含這份副本的內存塊句柄傳遞給剪貼板,
對于小數據量來說,這個沒什么,但是對于大數據量的話,就有問題了,
你一使用剪貼板,就往里面復制個什么幾百?MB?的數據,
那這個數據在剪貼板中的數據被其他數據取代之前都是存放在內存中的啊,
這個方法也太齷齪了,你想啊,要是我就復制了一個?500MB?的數據,然后我一直不再復制其他的東西,
那么這個?500MB?的數據就會一直駐留在內存中,咦 . . . 太可怕了 !!!太浪費內存的使用效率了 !!!
為了解決上面這個問題,就需要通過使用延遲提交技術來避免內存的浪費,
當使用延遲提交技術時,實際上,直到另一個程序需要數據時,程序才會提供這份數據,
也就是,其實我一開始?程序 A?并不往剪貼板中存放真實的數據,
而只是告訴剪貼板,我往里面放了數據(其實數據還沒有放進去),
而后,如果有其他的?程序 B?訪問了剪貼板中的數據,也就是執行了“粘貼”操作,
那么此時操作系統就會去檢查數據是不是真正的存放在了剪貼板中,
如果剪貼板中存放了數據,那么直接把數據送出去就可以了(這就沒有使用延遲提交技術了),
而如果剪貼板中沒有數據,那么?Windows?就會給上次往剪貼板中存放數據(盡管沒有存放實際的數據)的程序,
也就是?程序 A發送消息,
而后,我們的?程序 A?就可以再次調用?SetClipboardData?來將真實的數據放入到剪貼板中了,這樣就是延遲提交技術了。
要實現延遲提交技術,則在?程序?A?中不應該將數據句柄傳送給?Windows?,
而是在?SetClipboardData?調用中使用?NULL。
然后當另外一個?程序?B?調用?GetClipboardData?函數時,
Windows?就會檢查這種格式的數據在剪貼板中的句柄是否為?NULL?,
如果為?NULL?,則?Windows?會給程序?A發送一個消息,從而請求到數據的實際句柄,
這個數據的實際句柄是?程序?A?在響應消息的處理函數中重新調用?SetClipboardData?來提供的。
??????????????
延遲提交技術中涉及的三個消息:
下面提及的 程序 A 代表剪貼板當前擁有者,也就是 程序 A 負責往剪貼板中寫入數據,
而 程序 B 則代表從剪貼板中讀取出數據,其沒有對剪貼板的所有權。
????????????
WM_RENDERFORMAT?:
當?程序?B?調用?GetClipboardData?時,Windows?將會給?程序?A?的窗口過程發送這個消息,
其中?wParam?參數的值是所要求的格式。
在處理這個消息時,程序 A?就不再需要打開或者清空剪貼板了,
也就是不需要再次調用?OpenClipboard?和?EmptyClipboard?函數了,
為什么不需要再次調用這兩個函數?
這是因為,我們一開始的時候已經調用了這兩個函數(如果一開始沒有調用的話,窗口根本就不會接受到這個消息),
而此舉已經告訴操作系統剪貼板已經歸我所有了,而且里面的數據已經被清空了,
剪貼板所有權都歸我了,那還去打開個鬼啊,不是浪費嘛?
在處理這個消息時,應該為?wParam?所指定的格式創建一個全局內存塊,
然后再把數據傳遞到這個全局內存塊中,并要正確的格式和數據句柄再一次調用?SetClipboardData?函數。
也就是需要將數據真實的復制到剪貼板中了。
WM_RENDERALLFORAMTS?:
如果?程序?A?在它自己仍然是剪貼板所有者的時候就要終止運行,
并且剪貼板上仍然包含著該?程序?A?用?SetClipboardData?所設置的?NULL?數據句柄(延遲提交技術),
也就是?程序 A?當前還是剪貼板的所有者,但是用戶又單擊了關閉窗口,
而剪貼板中還沒有真實的數據存在(因為使用了延遲提交技術),
即數據還沒有被提交給剪貼板,程序 A?就要死了,則此時?程 序?A?的窗口過程將接收到這個消息,
這個消息的一般處理為打開剪貼板,并且清空剪貼板,然后把數據加載到內存中,
并為每種格式調用?SetClipboardData?,然后再關閉剪貼板即可。
WM_DESTROYCLIPBOARD?:
當在?程序?B?中調用?EmptyClipboard?時,Windows?將會給?程序?A?的窗口過程發送這個消息。
即通知?程序?A?其已不再是剪貼板的擁有者了。
???????????????
?????????????
Demo2 – MFCClipboard(延遲提交技術的使用)
整個項目結構很簡單:
主界面:
添加 3 個消息處理:
消息映射函數聲明: protected: HICON m_hIcon; ? // 生成的消息映射函數 virtual BOOL OnInitDialog(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnDestroyClipboard(); afx_msg void OnRenderAllFormats(); afx_msg void OnRenderFormat(UINT nFormat); afx_msg void OnBnClickedBtnWrite(); afx_msg void OnBnClickedBtnRead(); CString m_CStrWrite; CString m_CStrRead; };消息映射實現:
void CMFCClipboardDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT_WRITE, m_CStrWrite); DDX_Text(pDX, IDC_EDIT_READ, m_CStrRead); } ? BEGIN_MESSAGE_MAP(CMFCClipboardDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_DESTROYCLIPBOARD() ON_WM_RENDERALLFORMATS() ON_WM_RENDERFORMAT() ON_BN_CLICKED(ID_BTN_WRITE, &CMFCClipboardDlg::OnBnClickedBtnWrite) ON_BN_CLICKED(ID_BTN_READ, &CMFCClipboardDlg::OnBnClickedBtnRead) END_MESSAGE_MAP()消息映射函數實現
? //WM_DESTROYCLIPBOARD 消息處理函數 void CMFCClipboardDlg::OnDestroyClipboard() { //當有另外的程序調用 EmptyClipboard 時, //Windows 將向當前窗口過程發送 WM_DESTROYCLIPBOARD 消息 MessageBox(TEXT("很抱歉 , 您已失去對剪貼板的擁有權 ..."), TEXT("提示"), MB_ICONINFORMATION); ? CDialogEx::OnDestroyClipboard(); } ? ? //WM_RENDERALLFORMATS 消息處理函數 void CMFCClipboardDlg::OnRenderAllFormats() { //當剪貼板中的數據句柄為當前程序所擁有,而當前程序又將被退出時, //Windows 給該程序窗口發送 WM_RENDERALLFORMATS 消息 ? OpenClipboard(); EmptyClipboard(); CloseClipboard(); ? CDialogEx::OnRenderAllFormats(); } ? //WM_RENDERFORMAT 消息處理函數 void CMFCClipboardDlg::OnRenderFormat(UINT nFormat) { //當有另外的程序訪問剪貼板時 //Windows 給該程序窗口過程發送 WM_RENDERFORMAT 消息 int dataNum; int dataIndex; char * pDataBuf; HGLOBAL hGlobalClip; ? dataNum = this->m_CStrWrite.GetLength(); ? hGlobalClip = GlobalAlloc(GHND, dataNum + 1); pDataBuf = (char *)GlobalLock(hGlobalClip); for(dataIndex=0;dataIndex<dataNum;dataIndex++) { pDataBuf[dataIndex] = this->m_CStrWrite.GetAt(dataIndex); } GlobalUnlock(hGlobalClip); ? //此時需要將有效數據寫入到剪貼板中 SetClipboardData(CF_TEXT, hGlobalClip); ? CDialogEx::OnRenderFormat(nFormat); } ? ? void CMFCClipboardDlg::OnBnClickedBtnWrite() { UpdateData(); if(this->m_CStrWrite.GetLength() > 0) { if(OpenClipboard()) { EmptyClipboard(); SetClipboardData(CF_TEXT, NULL); CloseClipboard(); MessageBox(TEXT(" 恭喜您 , 設置剪貼板成功 ..."), TEXT("提示"), MB_ICONINFORMATION); } } } ? ? void CMFCClipboardDlg::OnBnClickedBtnRead() { if(OpenClipboard()) { //判斷剪貼板中的數據格式是否為 CF_TEXT if(IsClipboardFormatAvailable(CF_TEXT)) { char * pDataBuf; HGLOBAL hGlobalClip; ? //從剪貼板中獲取到指定格式的數據 hGlobalClip = GetClipboardData(CF_TEXT); pDataBuf = (char *)GlobalLock(hGlobalClip); this->m_CStrRead = pDataBuf; GlobalUnlock(hGlobalClip); ? UpdateData(FALSE); } CloseClipboard(); } }效果展示:
設置剪貼板中數據:
當前程序讀取剪貼板中數據:
記事本程序讀取剪貼板中數據:
測試當前進程失去剪貼板所有權:
首先單擊當前程序設置好剪貼板中的數據,
然后打開一個記事本文件,在在其中輸入一些數據,然后選擇這部分數據,按下復制:
????????????
?????????????
結束語
對于剪貼板的使用呢,也就是那么幾個?API?在使用而已,熟悉一下就可以了,
關鍵是延遲提交技術的使用,同時還有對于全局內存對象的理解還是有點難度的,
不過,我相信我解釋的還是比較明白了,大家可以通過我的解釋再對照?Demo?來理解,
這樣理解起來容易快速一些。
上面介紹的是通過剪貼板來實現進程之間的通信,其實這還是有問題的,
因為我們的剪貼板是位于本地機器上,所以,利用剪貼板還是無法實現本地進程與遠程進程通信,
當然要想實現本地進程和遠程進程的通信,那也還是有辦法的,這會在后續博文中引出的。
然后的話,今天圣誕節嘛,祝諸位節日快樂,也不是我崇洋媚外,說個節日快樂還是可以的。
總結
以上是生活随笔為你收集整理的进程间通信——剪切板的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SysFader iexplore.ex
- 下一篇: DM3730 x-loader 分析 一