《Windows核心编程》---剪贴板

剪贴板是由系统定义的,并不属于任何一个特定的进程。系统中所有进程都可以访问和设置剪贴板。剪贴板最大的特点就是数据传输没有明确的目标,数据是被动访问的;剪贴板的内容可以被多次访问,直到新的数据写入。剪贴板是一种可供选择的进程间通信方式,但由于系统中任何一个进程都可以都可以无限制地访问剪贴板,因此,它是一种不可靠的通信方式。

1)获取和设置剪贴板数据

涉及到的API有:OpenClipboardEmptyClipboardSetClipboardDataGetClipboardDataCloseClipboard等。

 

OpenClipboard用于打开剪贴板,获得剪贴板的句柄:

BOOL WINAPI OpenClipboard(

  __in_opt  HWND hWndNewOwner //指定的窗口可以收到剪贴板操作所产生的消息

                                               //如果为NULL,则采用当前任务的窗口

);

 

EmptyClipboard用于清空剪贴板中的内容:

BOOL WINAPI EmptyClipboard(void);

 

SetClipboardData用于设置剪贴板的内容:

HANDLE WINAPI SetClipboardData(

  __in      UINT uFormat,       //指定数据格式,可以是标准系统格式,也可以是用户自定义格式

  __in_opt  HANDLE hMem     //需要设置的数据的内存句柄;需使用全局内存管理的函数分配和

                                     //设置,且在分配时需指定GMEM_MOVEABLE标志

);

 

GetClipboardData用于从剪贴板获取数据:

HANDLE WINAPI GetClipboardData(

  __in  UINT uFormat //指定获取的数据的格式,获得的数据使用句柄返回

);

 

2)一般来说利用剪贴板进行数据通信是不具有实时性,所有操作都依赖于用户。除非使用剪贴板查看器Viewer,这样就可以立即知道剪贴板中内容的变化。

系统提供了WM_DRAWCLIPBOARD消息用于监视剪贴板的变化。如果调用SetClipboardViewer函数设置了窗口为剪贴板查看器,那么当剪贴板中内容变化时,所注册的查看器窗口就会收到WM_CHANGECBCHAIN消息和WM_DRAWCLIPBOARD消息。SetClipboardViewer函数原型如下:

HWND WINAPI SetClipboardViewer(

  __in  HWND hWndNewViewer //指定监视窗口

);

剪贴板查看器的代码例子如下:

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消息后显示剪贴板中的数据

            hdc = BeginPaint(hwnd, &ps);

            // Branch depending on the clipboard format.

              //uFormat全局变量,在WM_DRAWCLIPBOARDWM_COMMAND

            //消息处理中,使用SetAutoView设置

            //根据剪贴板中数据的不同格式,使用不同的显示方式

            switch (uFormat)

            {

                case CF_OWNERDISPLAY: //剪贴板的所有者必须显示并刷新Viewer的窗口

                    hwndOwner = GetClipboardOwner();//获得剪贴板的所有者

                            //获取剪贴板的数据

                    hglb = GlobalAlloc(GMEM_MOVEABLE,

                        sizeof(PAINTSTRUCT));

                    lpps = (LPPAINTSTRUCT)GlobalLock(hglb);

                    memcpy(lpps, &ps, sizeof(PAINTSTRUCT));

                    GlobalUnlock(hglb);

                           //向剪贴板所有者发送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); //获取剪贴板的数据

                                      //将位图选择进DC,显示在窗口客户区

                            SelectObject(hdcMem, hbm);

                            GetClientRect(hwnd, &rc);

                            BitBlt(hdc, 0, 0, rc.right, rc.bottom,

                                hdcMem, 0, 0, SRCCOPY);

                            CloseClipboard();//关闭剪贴板

                        }

                        DeleteDC(hdcMem); //释放DC

                    }

                    break;

 

                case CF_TEXT: //文本

                    if (OpenClipboard(hwnd)) //打开剪贴板

                    {

                        hglb = GetClipboardData(uFormat); //获得剪贴板数据

                        lpstr = GlobalLock(hglb);

                               //将文本绘制在窗口客户区

                        GetClientRect(hwnd, &rc);

                        DrawText(hdc, lpstr, -1, &rc, DT_LEFT);

                        GlobalUnlock(hglb);

                        CloseClipboard();//关闭剪贴板

                    }

                    break;

 

                case CF_ENHMETAFILE: //增强格式图元文件

                    if (OpenClipboard(hwnd)) //打开剪贴板

                    {

                        hemf = GetClipboardData(uFormat); //获取剪贴板数据

                                //调用PlayEnhMetaFile在窗口客户区上显示

                        GetClientRect(hwnd, &rc);

                        PlayEnhMetaFile(hdc, hemf, &rc);

                        CloseClipboard();

                    }

                    break;

 

                case 0: //剪贴板为空

                    GetClientRect(hwnd, &rc);

                    //在客户区中央显示

                    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: //当窗口创建时,在剪贴板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: //popup菜单弹出时收到此消息

            if (!HIWORD(lParam)) //根据剪贴板中内容的格式设置菜单

                InitMenu(hwnd, (HMENU) wParam);

            break;

 

        case WM_COMMAND: //处理用户菜单输入

            switch (LOWORD(wParam))

            {

                case IDM_EXIT: //用户点击“退出”菜单项

                    DestroyWindow(hwnd);

                    break;

 

                case IDM_AUTO: //用户点击“Auto”菜单项

                    SetAutoView(hwnd); //设置显示格式为自动

                    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)

* 获取剪贴板的主要格式,并设置显示方式

**********************************************************/

void WINAPI SetAutoView(HWND hwnd)

{

    static UINT auPriorityList[] = {

        CF_OWNERDISPLAY,

        CF_TEXT,

        CF_ENHMETAFILE,

        CF_BITMAP

    };

//设置剪贴板主要格式,设置显示格式

//uFormat在收到WM_PAINT消息时用到

    uFormat = GetPriorityClipboardFormat(auPriorityList, 4);

    fAuto = TRUE;

 

    InvalidateRect(hwnd, NULL, TRUE);

    UpdateWindow(hwnd);

}

 

/**************************************************************

* 功能:根据剪贴板中内容的格式,设置菜单项供用户选择显示方式

* 参数: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)剪贴板中存在各种数据格式,系统使用一个UINT类型的数据来表示剪贴板中数据类型。在这些格式信息中,有很多是各种应用程序之间通用的,比如文本、位图等。这些数据格式由系统预先定义,称为标准格式;当然应用程序也可自行定义剪贴板的数据格式,这样可以方便地在同一个应用程序的不同实例间进行数据传递而不用对数据格式进行过多的处理(典型的就包括word)。

 

常见标准格式:

CF_BITMAP    //位图句柄(HBITMAP)

CF_DIB             //内存位置包含BITMAPINFO结构和位图数据

CF_ENHMETAFILE         //增强的图元文件句柄(HENHMETAFILE)

CF_OEMTEXT        //OEM字符集的字符串(CR-LF格式换行)

CF_OWNERDISPLAY    //由剪贴板查看器查看的格式

CF_PALETTE  //调色板数据

CF_RIFF  //标准的CF_WAVE波形数据

CF_TEXT          //ANSI字符串(CR-LF格式换行)

CF_WAVE       //PCM波形

CF_TIFF  //Tagged图像文件格式

CF_UNICODETEXT       //Unicode字符串

 

自定义格式:

调用函数RegisterClipboardFormat可以自定义格式:

UINT WINAPI RegisterClipboardFormat(//返回值是系统分配的格式类型值(UINT)

  __in  LPCTSTR lpszFormat //格式名,

);

 

多种格式:

很多情况下,数据的格式不止一种,比如格式化的文本有效的格式不止一种(例如从Word中复制的数据、从网页中复制的数据等),因此可能存在多重格式。

以下几个API函数是用于获取当前剪贴板中的格式信息的:

GetPriorityClipboardFormat的功能是检测剪贴板中是否有paFormatPriorityList参数指定的格式数组中的格式存在,如果有则返回格式数组中的第一个剪贴板当前具有的格式:

int WINAPI GetPriorityClipboardFormat(

  __in  UINT *paFormatPriorityList, //格式数组,存储用于检测的格式信息

  __in  int cFormats    //paFormatPriorityList数组的大小

);

 

CountClipboardFormats函数用于返回当前剪贴板中具有的不同格式的数量:

int WINAPI CountClipboardFormats(void);

 

EnumClipboardFormats函数用于列举当前剪贴板中的所有格式:

UINT WINAPI EnumClipboardFormats(

  __in  UINT format   //指定一个已知的格式,通过函数返回值返回下一个格式

);

 

GetUpdatedClipboardFormats函数用于获取当前剪贴板的所有格式:

BOOL WINAPI GetUpdatedClipboardFormats(

  __out  PUINT lpuiFormats, //指向用于保存返回的格式数组的缓冲区

  __in   UINT cFormats, //lpuiFormats可以容纳的格式信息的数量

  __out  PUINT pcFormatsOut //返回真是的数组大小

);

 

由于剪贴板数据会有多种格式,在调用GetClipboardData函数获取数据时,应该指定格式。一般情况下,指定不同格式,将获得不同的内容。

 

剪贴板数据的格式信息:

每一个剪贴板格式都有一个格式名,格式名是一个字符串,使用GetClipboardFormatName函数可以获得:

int WINAPI GetClipboardFormatName(

  __in   UINT format, //要检索的格式ID

  __out  LPTSTR lpszFormatName, //存储返回的格式名的缓冲区

  __in   int cchMaxCount //拷贝到缓冲区的最大数据长度

);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/268191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker后台守护式启动

docker后台启动 docker run -d 镜像名

浏览器打不开网页,但是还可以聊qq?

电脑网络明明已经连接,但是就是打不开网页?下面介绍下解决方法。 原因:DNS解析导致网页打不开。路由器没有获取到DNS 我们的系统会缓存我们平时用到的一些DNS地址,这个功能主要是加速我们对网络的访问。但是有时候这些缓存的DNS地…

项目重构方案设计

最近接手到一个已经成型的项目,然后我们的任务就是对它进行重构,这个项目是一个功能很齐全的WPF视频播放器(附带很多其他功能),在仔细 研究了项目的背景和架构以后,初步做出了一下的重构方案: 目…

docker top查看容器中运行的进程信息

docker top :查看容器中运行的进程信息,支持 ps 命令参数。 语法 docker top [OPTIONS] CONTAINER [ps OPTIONS] 容器运行时不一定有/bin/bash终端来交互执行top命令,而且容器还不一定有top命令,可以使用docker top来实现查看container中正…

易经给我们的64个人生智慧

《易经》没有那么神秘,它是科学的,它就在我们的身边,我们每天的生活起居,工作事业,健康幸福,都受这64个哲理的左右。我们以科学的态度对待这64个哲理,就形成了64个感悟,64个感悟回答…

华为2018软件岗笔试题解题思路和源代码分享

2017年9月26日,参加了华为技术有限公司的笔试,题目类型是软件题,没有选择填空问答类型,总共是3道编程题目,题目难度适中,在两个小时内完成3道题目的AC,所以分享的代码都是可运行且完全AC的! 和广…

docker镜像加载原理

docker镜像加载原理

设计模式是用来弥补面向对象编程缺陷的方法总结

面向对象和设计模式都是大家耳熟能详的概念。面向对象是以对象为基本元素,对数据与逻辑行为进行封装。实现面向对象过程的方法是使用抽象,同时在使用抽象进行分析设计的时候就产生了类型,并隔离了抽象与实现。这个过程是有很多的优点的&#…

navicat的安装

1.下载 这里使用的是11.1版本。 2.安装到D盘 3.破解 下载 参考:http://www.cnblogs.com/da19951208/p/6403607.html 将PatchNavicat粘贴到安装目录,然后双击 选择navicat、 结果: 4.这个时候可以使用了 转载于:https://www.cnblogs.com/junca…

docker实现宿主机和容器之间映射添加数据卷

docker run -it —privilegedtrue -v /宿主机绝对路径:/容器内目录 镜像名 卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此docker不会在容器删除时删除其挂载的数据卷 在ubuntu容器内 /tmp/docker_data 下新建test.txt文件 在宿主机…

实验四 恶意代码

中国人民公安大学 Chinese people’ public security university 网络对抗技术 实验报告 实验四 恶意代码技术 学生姓名 冷其航 年级 14级 区队 二区队 指导教师 高见老师 信息技术与网络安全学院 2017年10月24日 实验任务总纲 2017—2018 学年 第 一 学期 一、实验…

Linux系统删掉多个文件

rm -f 2010-10-*.log转载于:https://www.cnblogs.com/dpf-learn/p/7752952.html

docker启动容器指定端口和随机分配端口

例子 我要启动tomcat docker run -d -P tomcat 大些-P表示随机分配端口 docker run -d -p 8086:8080 tomcat 小些-p 表示指定端口,主机端口:docker容器端口

华为 思科 配置

华为路由器交换机配置命令:计算机命令 PCAlogin:root;使用root用户 password:linux;口令是linux #shutdown-hnow;关机 #init0;关机 #logout;用户注销 #login;用户登录 #ifconfig;显示…

Windows 7 下IIS 7.5 结合Zend构建PHP集成开发环境

Windows 7 下IIS 7.5 结合Zend构建PHP集成开发环境 作者:宋杨日期:2010年7月4日星期日FeedBack:songyangsongyang.me系统环境:Windows 7 简体中文旗舰版软件环境:1、 IIS 7.5(安装FastCGI)2、 Z…

在docker安装完tomcat后,访问地址出现404错误

在docker安装完tomcat后,访问地址出现404错误 可以看到我们平时访问的文件在webapps文件夹下,而这里的这个文件夹却为空,因为他把文件都放在webapps.dist文件夹下了,所有你只需要把webapps文件夹里面的内容移到webapps里面即可 …

czy的后宫5

题目描述 Description \(czy\) 要召集他的妹子,但是由于条件有限,可能每个妹子不能都去,但每个妹子都有一个美丽值,\(czy\) 希望来的妹子们的美丽值总和最大(虽然……)。\(czy\) 有一个周密的电话通知网络&…

解决Use ‘docker scan‘ to run Snyk tests against images to find vulnerabilities and learn how to fix th

Use docker scan to run Snyk tests against images to find vulnerabilities and learn how to fix them 解决方案 执行如下命令 export DOCKER_SCAN_SUGGESTfalse

上传附件删除、session清空问题

最近因为项目的需要,将客户端附件上传至服务器,附件上传的位置是IIS目录下的文件夹,经过处理之后。必须将该附件删除。 程序发布之后,使用该功能,结果项目无法运行。必须要重新启动IIS才可以重新运行整个项目。因为项目中的Sessio…

浅谈Junit4和TestNG中的参数化测试

最近在看Junit4的相关知识,由于本身做的是自动化方面的测试,所以工作上着重于应用TestNG。恰好遇到了一个将case进行参数化的需求,故在此记录Junit4和TestNG在参数化方面的区别。 一、Junit4和TestNG的注释支持 特点JUnit 4TestNG测试注释Tes…