首頁 >Java >java教程 >如何理解C++ MFC進程間通訊之剪貼簿

如何理解C++ MFC進程間通訊之剪貼簿

坏嘻嘻
坏嘻嘻原創
2018-09-15 10:19:132312瀏覽

這篇文章帶給大家的內容是關於如何理解C MFC進程間通信之剪貼板,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

Windows剪貼簿是比較簡單的進程間通訊機制,同時它的開銷相對較小。它的實作原理很簡單,其實就是由作業系統維護的一塊記憶體區域,
這塊記憶體區域不屬於任何單獨的進程,但是每一個進程又都可以存取這塊記憶體區域,當一個行程將資料放到該記憶體區域中,而另一個進程,則可以從該區塊記憶體區域中取出數據,從而實現通信,其實現過程由兩大部分組成,一個是共享記憶體操作,一個是剪貼簿的操作。
1、剪貼簿操作
(1)HWND GetClipboardOwner();
功能:取得指向剪貼簿的目前擁有者的句柄
如果這個函數執行成功,則傳回擁有剪貼簿的窗口句柄。否則,返回NULL。

(2)BOOL  OpenClipboard(HWND  hWndNewOwner );
第一個參數hWndNewOwner 指向一個與之關聯的視窗句柄,即代表是這個視窗開啟剪貼簿,如果這個參數設定為NULL 的話,則以當前的任務或說是進程來開啟剪貼簿。如果開啟剪貼簿成功,則函數傳回非 0 值,如果其他程式已經開啟了剪貼簿,那麼目前這個程式就無法再開啟剪貼簿了,所以會致使開啟剪貼簿失敗,從而該函數傳回 0 值。其實這也好理解,你想啊,剪貼簿總共才那麼一塊內存區域,你進程A 要往裡面寫數據,你進程B 又要往裡面寫數據,那不亂套去,解決這個亂套的辦法就是,如果我進程A 正在往剪貼簿裡面寫資料(可以理解為進程A 打開剪貼簿了),那麼進程B 就不能往剪貼簿裡頭寫資料了,既然要讓進程B 不能往剪貼簿中寫資料了,那我就讓進程B 打開剪貼簿失敗不就得了。所以如果某個程式已經打開了剪貼板,那麼其他應用程式將不能修改剪貼簿,直到打開了剪貼簿的這個程式呼叫了CloseClipboard 函數,並且只有在呼叫了EmptyClipboard 函數之後,打開剪貼簿的目前視窗才能擁有剪貼簿

(3)BOOL CloseClipboard(void);
如果某個進程開啟了剪貼簿,則在這個進程沒有呼叫CloseClipboard 函式關閉剪貼簿句柄之前,其他進程都是無法開啟剪貼簿的,所以我們每次使用完剪貼簿之後都應該關閉剪貼簿。注意,這裡的關閉剪貼簿並不代表當前打開剪貼簿的這個程式失去了對剪貼簿的所有權,只有在別的程式調用了EmptyClipboard 函數之後,當前的這個程式才會失去對剪貼簿的所有權,而那個呼叫EmptyClipboard 函數的程式才能擁有剪貼簿。

(4)HANDLE  SetClipboardData(UINT uFormat,  HANDLE hMem );  
SetClipboardData 函數來實現在剪貼簿中放置數據,這個函數以指定的剪貼簿格式將資料放在剪貼簿中放置資料。第一個參數 uFormat 用來指定要放到剪貼簿上的資料的格式,例如常見的有 CF_BITMAP ,CF_TEXT ,CF_DIB 等等(其他格式可以參考 MSDN)。第二個參數hMem 用來指定具有指定格式的資料的句柄,該參數可以是NULL ,如果該參數為NULL 則表示直到有程式對剪貼簿中的資料進行請求時,該程式(也就是擁有剪貼簿所有權的進程)才會將數據複製到剪貼簿中,也就是提供指定剪貼簿格式的數據,上面提及的就是延遲提交技術,這個延遲提交技術將會在後面做詳細的介紹。

(5)BOOL  IsClipboardFormatAvailable( UINT format );  
此函數用來判斷剪貼簿上的資料格式是否為 format 指定的格式。

(6)HANDLE  GetClipboardData( UINT uFormat );  
此函數依據 uFormat 指定的格式,傳回以指定格式存在於剪貼簿中的剪貼簿物件的句柄。

2、共享記憶體分配
(1)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 用來指定指派的位元組數。

(2)HGLOBAL  WINAPI  GlobalReAlloc(HGLOBAL hMem,  SIZE_T dwBytes,  UINT uFlags);
此函數為再分配函數,即在原有的資料物件 hMem 上,為其擴大記憶體空間。
第一個參數 hMem 代表由 GlobalAlloc 函數傳回的資料物件句柄。
第二個參數 dwBytes 指定需要重新分配的記憶體的大小。
第三個參數 uFlags 指定分配的方式(可以參考 GlobalAlloc 函數)。

(3)SIZE_T  WINAPI  GlobalSize( HGLOBAL  hMem );
此函數用來傳回記憶體區塊的大小。
第一個參數 hMem 代表由 GlobalAlloc 函數傳回的資料物件句柄。

(4)LPVOID  WINAPI  GlobalLock( HGLOBAL  hMem );
此函數的作用是將全域記憶體物件加鎖,然後傳回該物件記憶體區塊第一位元組的指標。
第一個參數 hMem 代表由 GlobalAlloc 函數傳回的資料物件句柄。

(5)BOOL  WINAPI  GlobalUnlock( HGLOBAL  hMem );
你透過上面的GlobalLock 函數可以獲得這塊全域記憶體的存取權,
加鎖的意思就是你已經在使用這塊全域內存了,別的程式就不能再使用這塊全域內存了,而如果你一直不解鎖,那也不是個事啊,別的程式將會一直都使用不了這塊全局內存,那還叫全局內存幹嗎啊?所以這個函數就是用來對全域記憶體物件解鎖。
第一個參數 hMem 代表由 GlobalAlloc 函數傳回的資料物件句柄。

(6)HGLOBAL  WINAPI  GlobalFree( HGLOBAL  hMem );
此函數釋放全域記憶體區塊。
第一個參數 hMem 代表由 GlobalAlloc 函數傳回的資料物件句柄。

以下為範例程式碼,讀者也可以透過自己自電腦上進行Ctrl C(拷貝資料到剪貼簿) Ctrl V(從剪貼簿上拷貝資料) 進行某一項測試:

// Ctrl+C.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>  #include <process.h>  #include <windows.h>  using namespace std;int main()
{
    HWND hWnd = GetClipboardOwner();//获取当前剪贴板所属的窗口句柄
    DWORD Len = 32;
    HGLOBAL pClipData;
    pClipData = GlobalAlloc(GHND,Len+1);//分配共享内存

    char* pData;
    pData = (char*)GlobalLock(pClipData);//内存控制句柄加锁,其他进程不能再访问

    for(int i = 0;i < Len;i++)
    {
        pData[i] = &#39;a&#39;+i;                //在全局内存中赋值
    }

   GlobalUnlock(pClipData);//内存控制句柄解锁,其他进程可以访问

   if(!OpenClipboard(hWnd))//打开剪贴板
   {       cout<<"OPen fail!"<<endl;       return 0; 
   }

   EmptyClipboard();//清空剪贴板,这一步才真正拥有剪贴板
   SetClipboardData(CF_TEXT,pClipData);//将共享内存里的数据放入剪贴板
   CloseClipboard();//关闭剪贴板

   cout<<"剪贴完成"<<endl;   return 0;
}
//Ctrl+V.cpp#include "stdafx.h"#include <iostream>  #include <process.h>  #include <windows.h>  using namespace std;int main()
{
    HWND hWnd = GetClipboardOwner();//获取当前剪贴板所属的窗口句柄

    if(!OpenClipboard(hWnd))//打开剪贴板
    {        cout<<"OPen fail!"<<endl;        return 0; 
    }    if(IsClipboardFormatAvailable(CF_TEXT))
    {
         HANDLE hCilpData = GetClipboardData(CF_TEXT);
         DWORD Len = GlobalSize(hCilpData);          char* pData;
          pData = (char*)GlobalLock(hCilpData);//内存控制句柄加锁,其他进程不能再访问
          cout<<"剪贴板内容是:"<<pData<<endl;
          GlobalUnlock(hCilpData);//内存控制句柄解锁,其他进程可以访问
    }

   EmptyClipboard();//清空剪贴板,这一步才真正拥有剪贴板

   CloseClipboard();//关闭剪贴板

   cin.get();   return 0;
}

以上是如何理解C++ MFC進程間通訊之剪貼簿的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn