vc++之剪贴板通信实例

来源:互联网 发布:javascript sleep 1 s 编辑:程序博客网 时间:2024/05/21 03:54

 操作系统中实现同一台机器上的不同进程之间的通信是非常重要的。一般来说,进程间的通信方法有三种:剪贴板、邮槽和管道。由于后两种方式需要一定的操作系统基础,此处就不作介绍。本节将详细介绍采用剪贴板进行进程通信的实现。
剪贴板常用函数
读者应该对剪贴板是比较熟悉的,当按下【Ctrl+C】键时,选中的内容就会复制到剪贴板中,然后再按下【Ctrl+V】键,可以将剪贴板上的内容复制到应用程序中。

说明:当要把一个进程上的内容复制到另一个进程上时,最简单的办法就是使用剪贴板。
在读者的印象中,通常认为剪贴板是传输数据的媒介,用户要复制的数据首先保存到剪贴板中。这种想法不能说是正确的。因为实际上要复制的数据并不是真的保存在剪贴板上,而是在一块内存区域中。而剪贴板同这块内存区域相关联。或者说,由剪贴板来管理这块内存区域。例如,这里要将进程A中的内容通过剪贴板复制到进程B中,大致遵循以下步骤。
  在进程A自己的4GB的地址空间中申请一块内存。
  把要复制的数据写到申请的内存块当中;再把内存块交给剪贴板管理器中。
  进程B由剪贴板中取出数据。
下面是与剪贴板操作相关的一些函数。
    OpenClipboard函数:该函数用于打开剪贴板以检查或防止其他应用程序修改剪贴板中的内容。如果在本进程调用此函数来打开剪贴板之前,剪贴板已经被其他窗口打开,那么该函数调用将失败。此时,应该先调用CloseClipboard函数将剪贴板成功关闭之后再调用OpenClipboard打开。
    GlobalAlloc函数:该函数用于在堆上分配一块指定大小的内存区域。
    GlobalLock函数:该函数用于将一个内存块锁住,并返回一个指向内存块中第一个字节的指针变量,引用计数器加1。
    GlobalUnlock函数:该函数用于将被锁住的内存块进行解锁,引用计数器数字减1。
    SetClipboardData函数:该函数用于将内存块以指定的剪贴板的内容格式放到剪贴板管理器中。
    GetClipboardData函数:该函数用于从剪贴板中以指定的剪贴板的内容格式取出内存块。
    CloseClipboard函数:该函数用于关闭剪贴板,释放剪贴板资源。

为了更好地理解以上讲述的函数,下面给出一个实例来详细地介绍如何使用剪贴板来实现进程间的通信。
【范例17-3】剪贴板实现进程通信。
  新建一个MFC的基于对话框的应用程序。单击【File】|【New】菜单项,打开新建对话框。选择建立【MFC AppWizard[exe]】工程,为工程命名为“进程通信”。在AppWizard的第一步中选择【Dialog based】。其他步骤按照默认设置,单击【Finish】按钮完成创建。
  设计对话框。将对话框上的原有控件全部删除。添加两个文本框,一个让用户输入数据,ID号为IDC_EDIT_SEND;另一个是复制数据后用来显示数据的,ID号为IDC_EDIT_RECV。再添加两个按钮控件,一个名为“复制”,ID号为IDC_BTN_COPY;另一个名为“粘贴”,ID号设为IDC_BTN_PASTE。对话框设计结果。
  添加消息响应函数。双击对话框上的两个按钮,分别将两个按钮的OnBtnCopy和OnBtnPaste函数添加到类CMyDlg中。
提示:添加消息响应函数在MFC ClassWizard工具中,选中对应的按钮控件后,添加其COMMAND消息函数即可。
示例代码17-3
01    void CMyDlg::OnBtnCopy()                            //复制按钮
02    {
03        // TODO: Add your control notification handler code here
04        CString str;
05        //定义字符型变量用来保存用户输入的数据
06        GetDlgItemText(IDC_EDIT_SEND,str);
07        HGLOBAL hClip;
08        //定义一个HGLOBAL句柄变量用来指向分配的内存块
09        if (OpenClipboard())
10        {
11            EmptyClipboard();                            //将剪贴板内容清空
12            hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);
13            //在堆上分配可移动的内存块,程序返回一个内存句柄
14            char * buff;                                 //定义指向字符型的指针变量
15            buff=(char*)GlobalLock(hClip);
16            //对分配的内存块进行加锁,将内存块句柄转化成一个指针,并将相应的引用计数器加1
17            strcpy(buff,str);
18            //将用户输入的数据复制到指针变量中,实际上就是复制到分配的内存块中
19            GlobalUnlock(hClip);
20            //数据写入完毕,进行解锁操作,并将引用计数器数字减1
21            SetClipboardData(CF_TEXT,hClip);
22            //将存放有数据的内存块放入剪贴板的资源管理中
23            CloseClipboard();
24            //关闭剪贴板,释放剪贴板资源的占用权
25            MessageBox("已将数据存入剪贴板");
26        }
27    }
28    void CMyDlg::OnBtnPaste()                            //粘贴按钮
29    {
30        // TODO: Add your control notification handler code here
31        CString str;
32        //字符型变量保存由剪贴板复制下来的数据
33        HANDLE hClip;
34        //定义HANDLE句柄型变量用来指向GetClipboardData函数返回的句柄
35        if (OpenClipboard())
36        {
37            hClip=GetClipboardData(CF_TEXT);
38            //从剪贴板中取出一个内存的句柄
39            char* buff;
40            //定义字符型指针变量用来保存内存块中的数据
41            buff=(char*)GlobalLock(hClip);
42            //对内存块进行加锁,将内存句柄值转化为一个指针,并将内存块的引用计数器加一,内存                //中的数据也返回到指针型变量中
43            str=buff;
44            //将数据保存到字符型变量中
45            GlobalUnlock(hClip);
46            //将内存块的引用计数器减一
47            CloseClipboard();
48            //关闭剪贴板,释放剪贴板资源的占用权
49            SetDlgItemText(IDC_EDIT_RECV,str);
50        }
51    }
【运行结果】在Visual C++ 6.0中编译后无错误,使用快捷键【Ctrl+F5】运行该工程。在左边的编辑框中输入字符串“21天学会Visual C++”。单击【复制】按钮,该字符串就存放到剪贴板中了。
说明:上述代码中用到了剪贴板的操作函数,此外,还应用到了字符串赋值函数strcpy(),用于将输入字符串复制到内存中。
在上图中单击【复制】按钮后,单击【粘贴】按钮。将存储在剪贴板中的字符串取出并显示在右边的编辑框中,如图17-18所示。
 
图17-18  【粘贴】按钮运行结果
【代码解析】从以上代码中可以看出,不管是把内存块放到剪贴板资源管理中,还是从剪贴板中取出内存块,都要经过加锁和解锁的过程。这是为了方便句柄型变量和字符型指针变量的转换,实现数据的写入和读取。上述代码中,【复制】按钮和【粘贴】按钮的执行流程如图17-19和图17-20所示。
至此,一个通过剪贴板实现进程通信的实例就完成了。事实上,本例中实现的功能不用剪贴板也一样能够很简单的完成。此处只是为了演示剪贴板的用法。

原创粉丝点击