【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就是想要查询的数据格式,该函数不须要打开剪贴板。

  • 剪贴板实例

以上几个就是最基本的剪贴板相关函数:

以下我们用这些函数来完毕主要的文本复制粘贴和图像复制粘贴功能。为了演示。我们设定了一幅图和一行文本作为数据源。同一时候创建两个button“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。

本演示样例程序程序执行后,分别点击了拷贝图像和拷贝文本本任意点击,效果例如以下:

clipboard

总的来说剪贴板的基本应用还是比較简单。相关的其它或很多其它的信息请查看MSDN。

对本文有什么疑议请给我留言。

很多其它经验交流能够增加Windows编程讨论QQ群454398517

 

关注微信公众平台:程序猿互动联盟(coder_online),你能够第一时间获取原创技术文章,和(java/C/C++/Android/Windows/Linux)技术大牛做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序猿互动联盟,开发者自己的家。

【Windows编程】系列第八篇:创建通用对话框

转载请注明出处http://www.coderonline.net/?

p=1815。谢谢合作!

posted @ 2017-06-05 20:57  yfceshi  阅读(604)  评论(0编辑  收藏  举报