【Windows编程】系列第九篇:剪贴板使用
上一篇我们学习了常见的通用对话框,本篇来了解剪贴板的使用,它常用于复制粘贴功能。
剪贴板是Windows最早就加入的功能,由于该功能非常实用,我们几乎每天都会使用到。通过剪贴板,我们就可以将数据从一个应用程序传递到另一个应用程序,是一种简单的进程间通信。
许多文档处理软件都有复制、剪切、粘贴功能,这些都是用Windows剪贴板实现的,当然我们也可以在我们的程序中实现自己的剪贴板功能,本篇我们就来实现自己的剪贴板。使用剪贴板时,都是先把源数据先传到剪贴板上,再在需要的时候从剪贴板传输到目的处,所以看起来我们就是直接从源直接搬到目的处。
Windows的控件比如EditBox,已经在控件内部实现了复制、剪切和粘贴功能,所以我们能直接使用。但我们很多控件是没有这个功能的,比如静态文本控件,自己创建的窗口等,我们就没有办法直接拷贝粘贴,这些都是需要我们自己实现的。还是老规矩,下面我们先介绍剪贴板常用函数,然后用实例来演示基本用法。
- 剪贴板常用函数
 
不管是复制还是粘贴,使用剪贴板首先要打开它,打开剪贴板API函数如下:
BOOL OpenClipboard(HWND hWndNewOwner);
唯一参数hWndNewOwner是和剪贴板关联的窗口句柄,如果该参数为NULL,则关联到当前任务。
在从源设置数据到剪贴板之前,必须先清空剪贴板,同时得到剪贴板的占有权。API函数如下:
Bool EmptyClipboard(void)
该函数没有参数。
向剪贴板设置数据,也就是拷贝操作:
HANDLE SetClipboardData(UINT uFormat, HANDLE hMem);
参数uFormat表示要设置传输到剪贴板上的数据格式,预定义的格式有十几种,我们这里列出几个最常用的,其他请参考MSDN:
CF_TEXT:表示要设置的格式为以NULL结尾的ANSI字符串,及标C的字符串。这是最简单的剪贴簿数据格式。
CF_UNICODETEXT:格式为包含Unicode字符集的字符串。
CF_BITMAP:格式为设备相关的位图。
参数hMem:设置数据的句柄,一般为GlobalAlloc函数返回的句柄。
设置完数据或者从剪贴板获取数据之后,需要关闭剪贴板,否则其他应用程序无法再打开剪贴板。API函数为:
Bool CloseClipboard(void);
该函数没有参数。
从剪贴板获取数据,也就是粘贴操作,API函数为:
HANDLE GetClipboardData(UINT uFormat);
参数uFormat就是想要获取的数据格式。
查询剪贴板中是否有指定格式的数据:
BOOL IsClipboardFormatAvailable(UINT format);
参数format就是想要查询的数据格式,该函数不需要打开剪贴板。
- 剪贴板实例
 
以上几个就是最主要的剪贴板相关函数:
下面我们用这些函数来完成基本的文本复制粘贴和图像复制粘贴功能,为了演示,我们设定了一幅图和一行文本作为数据源,同时创建两个按钮“copy image”和“copy text”分别用于复制图像和文本,当点击时复制对于的数据。
为了程序简洁,我用了鼠标左键来抬起作为粘贴触发,粘贴的位置就是抬起鼠标时的鼠标位置,您可以在不同的地方多次点击后抬起鼠标来重复粘贴,具体代码如下:
#include <windows.h>
#include <tchar.h> #define IDC_LABEL 1000
#define IDC_COPY_IMG 1001
#define IDC_COPY_TXT 1002 static TCHAR szAppName[] = TEXT("Clipboard Demo");
static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass))
{
MessageBox (NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
} hWnd = CreateWindow(szAppName, // window class name
szAppName, // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
400, // initial x size
300, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} static int DrawBmp(HDC hDC, int xDst, int yDst, int width, int height, int BytesPerPixel, unsigned char *pPixels)
{
int ret = -1;
HDC hdcMem;
BITMAPINFO bmi;
BYTE *pBits = NULL; memset(&bmi, 0x00, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = BytesPerPixel*8;
bmi.bmiHeader.biCompression = BI_RGB; hdcMem = CreateCompatibleDC(hDC);
if (hdcMem)
{
HBITMAP hBitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
if (hBitmap)
{
HGDIOBJ hOldBmp = SelectObject(hdcMem, hBitmap);
memcpy(pBits, pPixels, width * height * BytesPerPixel);
BitBlt(hDC, xDst, yDst, width, height, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hOldBmp);
DeleteObject(hBitmap);
ret = 0;
}
DeleteDC(hdcMem);
} return ret;
} static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
static HBITMAP hBmp;
static BITMAP bm; switch (message)
{
case WM_CREATE:
CreateWindow(TEXT("STATIC"), TEXT("你好,World!"), WS_CHILD|WS_VISIBLE, 10, 160, 100, 20, hWnd, (HMENU)IDC_LABEL, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("copy image"), WS_CHILD|WS_VISIBLE, 10, 190, 100, 20, hWnd, (HMENU)IDC_COPY_IMG, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("copy text"), WS_CHILD|WS_VISIBLE, 10, 220, 100, 20, hWnd, (HMENU)IDC_COPY_TXT, NULL, NULL);
hBmp = (HBITMAP)LoadImage(NULL, TEXT("start.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
GetObject(hBmp, sizeof(BITMAP), &bm);
return 0; case WM_PAINT:
{
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd, &ps);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBmp);
BitBlt(hDC, 10, 10, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
DeleteDC(hMemDC);
EndPaint(hWnd, &ps);
}
return 0; case WM_COMMAND:
{
int id = LOWORD(wParam);
switch (id)
{
case IDC_COPY_IMG:
{
BOOL ret;
BYTE *pData = NULL;
BITMAPINFO bmpInfo; bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = bm.bmWidth;
bmpInfo.bmiHeader.biHeight = bm.bmHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB; HDC hClientDC = GetDC(hWnd);
HDC hMemDC = CreateCompatibleDC(hClientDC);
HBITMAP hBitmap = CreateDIBSection(hMemDC, &bmpInfo, DIB_RGB_COLORS, (void **)&pData, NULL, 0);
SelectObject(hMemDC, hBitmap);
ret = BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hClientDC, 10, 10, SRCCOPY);
DeleteDC(hMemDC); LONG len = bm.bmWidth * bm.bmHeight * 4;
HGLOBAL hClipData = GlobalAlloc(GHND, len);
BYTE *pClipData = (BYTE *)GlobalLock(hClipData);
memcpy(pClipData, pData, len);
ret = GlobalUnlock(hClipData); ret = OpenClipboard(hWnd);
ret = EmptyClipboard();
SetClipboardData(CF_BITMAP, hClipData);
ret = CloseClipboard(); DeleteObject(hBitmap);
ReleaseDC(hWnd, hClientDC); MessageBox(hWnd, TEXT("image has been copy into clipboard"), TEXT("info"), MB_OK);
}
break; case IDC_COPY_TXT:
{
BOOL ret;
TCHAR buf[256]; GetWindowText(GetDlgItem(hWnd, IDC_LABEL), buf, _countof(buf));
int len = _tcslen(buf) + 1; HGLOBAL hClipData = GlobalAlloc(GHND, len * sizeof(TCHAR));
TCHAR *pClipData = (TCHAR *)GlobalLock(hClipData);
memcpy(pClipData, buf, len * sizeof(TCHAR));
pClipData[len-1] = (TCHAR)0;
ret = GlobalUnlock(hClipData); ret = OpenClipboard(hWnd);
ret = EmptyClipboard();
SetClipboardData(CF_TEXT, hClipData);
ret = CloseClipboard(); MessageBox(hWnd, TEXT("text has been copy into clipboard"), TEXT("info"), MB_OK);
}
break; default:
break;
}
}
return 0; case WM_LBUTTONUP:
{
BOOL ret;
WORD xPos = LOWORD(lParam);
WORD yPos = HIWORD(lParam); ret = IsClipboardFormatAvailable(CF_BITMAP);
if (ret)
{
ret = OpenClipboard(hWnd);
HGLOBAL hglb = GetClipboardData(CF_BITMAP);
//len = GlobalSize(hglb);
BYTE *pClipData = (BYTE *)GlobalLock(hglb);
HDC hClientDC = GetDC(hWnd);
DrawBmp(hClientDC, xPos, yPos, bm.bmWidth, bm.bmHeight, 4, pClipData);
GlobalUnlock(hglb);
CloseClipboard();
ReleaseDC(hWnd, hClientDC);
} ret = IsClipboardFormatAvailable(CF_TEXT);
if (ret)
{
ret = OpenClipboard(hWnd);
HGLOBAL hglb = GetClipboardData(CF_TEXT);
TCHAR *pClipData = (TCHAR *)GlobalLock(hglb);
HDC hClientDC = GetDC(hWnd);
int len = _tcslen(pClipData);
//len = GlobalSize(hglb);
TextOut(hClientDC, xPos, yPos, pClipData, len);
GlobalUnlock(hglb);
CloseClipboard();
ReleaseDC(hWnd, hClientDC);
}
}
return 0; case WM_DESTROY:
DeleteObject(hBmp);
PostQuitMessage(0);
return 0 ;
} return DefWindowProc (hWnd, message, wParam, lParam);
}
示例中在设置剪贴板时,需要用GlobalAlloc函数分配全局内存,设置和获取数据前需要GlobalLock函数锁定内存一般拷贝数据,使用后再用GlobalUnlock函数解锁内存,这几个函数在使用剪贴板基本成了讨论,照葫芦画瓢就行了,要了解详细参数请查看MSDN。本示例程序程序运行后,分别点击了拷贝图像和拷贝文本本随意点击,效果如下:

总的来说剪贴板的基本应用还是比较简单,相关的其他或更多的信息请查看MSDN。对本文有什么疑议请给我留言。
更多经验交流可以加入Windows编程讨论QQ群:454398517。
关注微信公众平台:程序员互动联盟(coder_online),你可以第一时间获取原创技术文章,和(java/C/C++/Android/Windows/Linux)技术大牛做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人员自己的家。
转载请注明出处http://www.coderonline.net/?p=1815,谢谢合作!
【Windows编程】系列第九篇:剪贴板使用的更多相关文章
- [ 高并发]Java高并发编程系列第二篇--线程同步
		
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
 - java并发编程JUC第九篇:CountDownLatch线程同步
		
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
 - java并发编程系列原理篇--JDK中的通信工具类Semaphore
		
前言 java多线程之间进行通信时,JDK主要提供了以下几种通信工具类.主要有Semaphore.CountDownLatch.CyclicBarrier.exchanger.Phaser这几个通讯类 ...
 - 【Windows编程】入门篇——win 32窗口的hello word!
		
✍ Windows编程基础 1.Win 32应用程序基本类型 1) 控制台程序 不需要完善的windows窗口,可以使用DOS窗口方式显示 2) Win 32窗口程序 包含窗口的程序,可以通过窗 ...
 - Java9系列第九篇-对HTTP2协议的支持与非阻塞HTTP-API
		
在HTTP/1.1 发布了16 年之后,IETF在2015年终于通过了HTTP/2 协议.HTTP/2协议旨在降低延迟,满足当今时代对于信息响应时间的要求.在这篇文章中,我会简要的对HTTP/2协议进 ...
 - [高并发]Java高并发编程系列开山篇--线程实现
		
Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...
 - [C入门 - 游戏编程系列]  环境篇
		
这一系列笔记的代码都是在Ubuntu 14.04下编码并测试的,原因无他,因为我笔记本电脑只装了一个Ubuntu系统,其中唯一使用的第三方库SDL也是开源并且跨平台的.所以即使你用的是Windows或 ...
 - [C入门 - 游戏编程系列]  序言篇
		
记得学习C语言的时候,看着别人能写各种各样的小游戏和小软件,甚是羡慕.而自己,虽然说语法都会,但是真正上手写个几百行的代码,就显得力不从心.曾经一度很是郁闷,看过一些书,大都处于教语法的层面,有些涉及 ...
 - MongoDB基础教程系列--第九篇 MongoDB 分片
		
1.分片介绍 分片(sharding)是将数据拆分,将其分散存到不同机器上的过程.MongoDB 支持自动分片,可以使数据库架构对应用程序不可见.对于应用程序来说,好像始终在使用一个单机的 Mongo ...
 
随机推荐
- STM32CubeMX安装指南
			
1.STM32CubeMX软件下载 地址:http://pan.baidu.com/s/1bn8sXOV 密码:6u3p 2.安装 1)安装Java SDK 2)安装SetupSTM3 ...
 - C#不对称加密
			
对称加密的缺点是双方使用相同的密钥和IV进行加密.解密.由于接收方必须知道密钥和IV才能解密数据,因此发送方需要先将密钥和IV传递给接收方.这就 有一个问题,如果攻击者截获了密钥和IV,也就等于知道了 ...
 - 常用html、CSS、javascript前端命名规范
			
无论是从技术角度还是开发视角,对于web前端开发规范文档都有一定规范,本文就css3和html5的发展前景总结了一系列的web开发文档,仅供大家参考. 规范目的: 为提高团队协作效率, 便于后台人员添 ...
 - 转载:《TypeScript 中文入门教程》 12、类型推导
			
版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 介绍 这节介绍TypeScript里的类型推论.即,类型是在哪里如何被推断的. 基础 ...
 - mybatis中的延迟加载
			
一.延迟加载 resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. 延迟加载:先 ...
 - 【夯实Mysql基础】mysql explain执行计划详解
			
原文地址 1).id列数字越大越先执行,如果说数字一样大,那么就从上往下依次执行,id列为null的就表是这是一个结果集,不需要使用它来进行查询. 2).select_type列常见的有: A ...
 - java web学习总结(二十) -------------------监听器属性详解
			
一.监听域对象中属性的变更的监听器 域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信 ...
 - C#中HashTable的用法
			
一,哈希表(Hashtable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对,其中 ...
 - SQL Server创建索引(转)
			
什么是索引 拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数据记录也是按页存放的,每页容量一般为4K .为了加快查找的速度,汉语字(词)典一般都有按拼音. ...
 - js 获取鼠标选中值
			
if (window.getSelection) {//一般浏览器 userSelection = window.getSelection();} else if (document.selectio ...
 
			
		