首页 Java java教程 如何理解C++ MFC进程间通信之剪贴板

如何理解C++ MFC进程间通信之剪贴板

Sep 15, 2018 am 10:19 AM

本篇文章给大家带来的内容是关于如何理解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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java 中的完美数 Java 中的完美数 Aug 30, 2024 pm 04:28 PM

Java 完美数指南。这里我们讨论定义,如何在 Java 中检查完美数?,示例和代码实现。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。这里我们通过示例讨论简介、如何使用weka java、平台类型和优点。

Java 中的史密斯数 Java 中的史密斯数 Aug 30, 2024 pm 04:28 PM

Java 史密斯数指南。这里我们讨论定义,如何在Java中检查史密斯号?带有代码实现的示例。

Java Spring 面试题 Java Spring 面试题 Aug 30, 2024 pm 04:29 PM

在本文中,我们保留了最常被问到的 Java Spring 面试问题及其详细答案。这样你就可以顺利通过面试。

突破或从Java 8流返回? 突破或从Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

Java 中的时间戳至今 Java 中的时间戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的时间戳到日期指南。这里我们还结合示例讨论了介绍以及如何在java中将时间戳转换为日期。

Java程序查找胶囊的体积 Java程序查找胶囊的体积 Feb 07, 2025 am 11:37 AM

胶囊是一种三维几何图形,由一个圆柱体和两端各一个半球体组成。胶囊的体积可以通过将圆柱体的体积和两端半球体的体积相加来计算。本教程将讨论如何使用不同的方法在Java中计算给定胶囊的体积。 胶囊体积公式 胶囊体积的公式如下: 胶囊体积 = 圆柱体体积 两个半球体体积 其中, r: 半球体的半径。 h: 圆柱体的高度(不包括半球体)。 例子 1 输入 半径 = 5 单位 高度 = 10 单位 输出 体积 = 1570.8 立方单位 解释 使用公式计算体积: 体积 = π × r2 × h (4

创造未来:面向零基础的 Java 编程 创造未来:面向零基础的 Java 编程 Oct 13, 2024 pm 01:32 PM

Java是热门编程语言,适合初学者和经验丰富的开发者学习。本教程从基础概念出发,逐步深入讲解高级主题。安装Java开发工具包后,可通过创建简单的“Hello,World!”程序实践编程。理解代码后,使用命令提示符编译并运行程序,控制台上将输出“Hello,World!”。学习Java开启了编程之旅,随着掌握程度加深,可创建更复杂的应用程序。

See all articles