12.3 实现一个剪贴板查看器 – wilim

Windows顺序(第五版)摘,保藏版 著》P462

        条件顺序可以认识到剪贴板使满意的更改,这么地顺序就高尚的“剪贴板查看器”。Windows 带有单独剪贴板查看器,又你也可以写作本人的剪贴板查看器顺序。剪贴板查看器经过发派遣查看器窗口换异的音讯知悉剪贴板使满意的更改。

  剪贴板查看器链

        在 Windows 下可以同时运转恣意数专注的剪贴板查看器应用顺序,剪贴板达到目标更改可以警告他们。。又从 Windows 从视角,只要单独剪贴板查看器,我称之为“目前的剪贴板查看器”。Windows 只预防性维修单独特征目前的剪贴板查看器的窗口句柄,只发送音讯到哪一个窗口,警告剪贴板使满意已更改。。

        剪贴板查看器应用顺序适宜加法“剪贴板查看器链”,这么缠住运转的剪贴板查看器顺序就都能收到 Windows 发放目前的剪贴板查看器的音讯。当某顺序把本人报户口为剪贴板查看器时,这么地顺序就变为目前的剪贴板查看器。Windows 把上单独目前的剪贴板查看器的窗口句柄搀扶这么地顺序,顺序并且容纳句柄。当它收到剪贴板查看器音讯时,它会把音讯发派遣剪贴板查看器链中下单独顺序的窗口换异。

  剪贴板查看器作用和音讯

        经过呼叫 SetClipboardViewer 作用,顺序就能变为剪贴板查看器链的偏爱的

。条件此顺序的首要专注的执意作为单独剪贴板查看器,因而可以处置 WM_CREATE 当援引音讯时援引此作用。这么地作用恢复上单独目前的剪贴板查看器的窗口句柄。顺序适宜用动态变量容纳这么地句柄。:

static HWND hwndNextViewer;
[安宁顺序旅程的]
case WM_CREATE:
    [安宁顺序旅程的]
    hwndNextViewer = SetClipboardViewer (hwnd);

条件你的顺序在 Windows 交谈持续的时间是头单独变为剪贴板查看器的顺序,这么 hwndNextViewer 将为 NULL。

        剪贴板使满意一旦更改,Windows 它将跌倒目前的剪贴板查看器(即最新报户口变为为剪贴板查看器的窗口)发送 WM_DRAWCLIPBOARD 音讯。剪贴板查看器链的结局单独顺序(即第单独报户口变为剪贴板查看器的窗口)将会有单独值为 NULL 的 hwndNextViewer。条件 hwndNextViewer 值为 NULL,顺序率直的恢复,不喜欢向另单独顺序发送音讯。。(不要把它挂起来。 WM_DRAWCLIPBOARD
和 WM_PAINTCLIPBOARD 迷惑新闻报道。WM_PAINTCLIPBOARD 是由剪贴板查看器发放应用 CF_OWNERDISPLAY 剪贴板电视节目的总安排顺序。WM_DRAWCLIPBOARD 它是由 Windows 发放目前的剪贴板查看器的。)

        处置 WM_DRAWCLIPBOARD 音讯的最复杂的方式是播种新闻报道下单独剪贴板查看器(除非 hwndNextViewer 为 空),使窗口的客户端区域失去健康:

case WM_DRAWCLIPBOARD:
    if (hwndNextViewer)
        SendMessage (hwndNextViewer, message, wParam, lParam);
    InvalidateRect (hwnd, NULL, 真的)
    return 0;

处置 WM_PAINT 音讯句号,你可以经过普通 OpenClipboard、GetClipboardData 和 CloseClipboard 援引以读取剪贴板使满意。

        当某顺序想从剪贴板查看器链中掉出时,霉臭援引 ChangeClipboardChain。这么地作用需求掉出的顺序的窗口句柄和它下单独剪贴板查看器的窗口句柄:

ChangeClipboardChain(hwnd, hwndNextViewer);

当顺序援引 ChangeClipboardChain 时,Windows 会向目前的剪贴板查看器发送单独 WM_CHANGECBCHAIN 音讯

。该音讯的 wParam 确定因素是要从链里掉出的窗口的句柄(即 ChangeClipboardChain 第单独确定因素),lParam 是将要掉出的窗口的下单独剪贴板查看器的窗口句柄(即 ChangeClipboardChain 瞬间确定因素。

        当您的顺序已收到 WM_CHANGECBCHAIN 音讯,霉臭反省 wParam 它倘若等同你所容纳的 hwndNextViewer 值。条件相当,你的顺序霉臭是 hwndNextViewer 设为 lParam。这么地巧妙地控制确保你将来得到什么 WM_CHANGECBCHAIN 音讯不能的从链发送到窗口。。条件 wParam 不等同 hwndNextViewer,并且 hwndNextViewer 不为 NULL,就把音讯发派遣下单独剪贴板查看器:

case WM_CHANGECBCHAIN:
    if ((HWND) wParam == hwndNextViewer)
        hwndNextViewer = (HWND)lParam);

    else if (hwndNextViewer)
        SendMessage (hwndNextViewer, message, wParam, lParam);
    return 0;

它不喜欢添加。 else if 陈述,这合法的一张打勾。 hwndNextViewer 不尊重它倘若责怪 NULL。hwndNextViewer 值为 NULL 打算实施这段编码的顺序是链里的结局单独剪贴板查看器,在这种情况下,音讯不应再次运送。

        条件你的顺序在要止付时依然在剪贴板查看器链里,霉臭从连锁上取下。。可加工 WM_DESTROY 援引音讯时援引 ChangeClipboardChain 充分发挥潜在的能力拟出:

case WM_DESTROY:
    ChangeClipboardChain (hwnd, hwndNextViewer);
    PostQuitMessage (0);
    return 0;

        Windows 也有单独让顺序腰槽第单独剪贴板查看器的窗口句柄的作用:

hwndViewer = GetClipboardViewer();

这么地作用通常责怪使对某人有利的。。条件目前的剪贴板查看器不存在,并且恢复值为 NULL。

        这时有单独侦查阐明剪贴板查看器链是方式派遣的。当 Windows 在开端的开端,目前的剪贴板查看器为 NULL:

        目前的剪贴板查看器:                                                      NULL

        有钱人窗口句柄 hwnd1 这么地顺序叫做 SetClipboardViewer。这么地作用恢复 NULL,这么地值在这么地顺序中 hwndNextViewer 值:

        目前的剪贴板查看器:                                                      hwnd1

        hwnd1 下单独看片机:                                             NULL

        有钱人窗口句柄 hwnd2 瞬间个顺序现时叫做 SetClipboardViewer,并腰槽 hwnd1:

        目前的剪贴板查看器:                                                      hwnd2

        hwnd2 下单独看片机:                                            hwnd1

        hwnd1 下单独看片机:                                            NULL

        第三个顺序(hwnd3)和月的第四日顺序(hwnd4)也援引了 SetClipboardViewer,并腰槽 hwnd2 和 hwnd3:

        目前的剪贴板查看器:                                                      hwnd4

        hwnd4 下单独看片机:                                            hwnd3

        hwnd3 下单独看片机:                                            hwnd2

        hwnd2 下单独看片机:                                            hwnd1

        hwnd1 下单独看片机:                                            NULL

        剪贴板使满意更改时,Windows 向 hwnd4 发送 WM_DRAWCLIPBOARD 音讯,hwnd4 播种新闻报道 hwnd3,hwnd3 重行发行 hwnd2,hwnd2 发放 hwnd1,hwnd1 恢复。

        现时 hwnd2 确定掉出连锁,它援引以下作用:

ChangeClipboardChain (hwnd2, hwnd1);

        Windows 会向 hwnd4 发送 WM_CHANGECBCHAIN 音讯,对应的的 wParam 等同 hwnd2,lParam 等同 hwnd1。鉴于 hwnd4 下单独看片机时 hwnd3,相应地 hwnd4 把音讯传给你 hwnd3。现时 hwnd3 注意到 wParam 等同它下单独看片机(hwnd2),因而它把它下单独看片机设置成等同 lParam(hwnd1)并且恢复。这么地派遣充分发挥潜在的能力了。剪贴板查看器现时出现如次:

        目前的剪贴板查看器:                                                      hwnd4

        hwnd4 下单独看片机:                                            hwnd3

        hwnd3 下单独看片机:                                            hwnd1

        hwnd1 下单独看片机:                                            NULL

12.3.3  单独复杂的剪贴板查看器

        剪贴板查看器不一定要和 Windows 看守者和所陈设的平均复杂。。比方,剪贴板查看器可以只显示一种剪贴板体式。图 12-2 所示的 CLIPVIEW 顺序合法的单独范围 CF_TEXT 体式的剪贴板查看器。

/*---------------------------------------------
	CLIPVIEW.C -- Simple Clipboard Viewer
				(c) Charles Petzold, 1998
----------------------------------------------*/

#include 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT(".ClipView.");
	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, 版本(这么地 program requires Windows NT!"),
			szAppName, MB_ICONERROR);
		return 0;
	}

	hwnd = CreateWindow(szAppName, 
版本(复杂 Clipboard Viewer (版本) 只要,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT,
		CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInstance, 空);

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND  hwndNextViewer;
	HGLOBAL		 hGlobal;
	HDC			 hdc;
	PTSTR		 pGlobal;
	PAINTSTRUCT  ps;
	RECT		 rect;

	switch (音讯)
	{
	case WM_CREATE:
		hwndNextViewer = SetClipboardViewer(hwnd);
		return 0;

	case WM_CHANGECBCHAIN:
		if ((HWND)wParam == hwndNextViewer)
			hwndNextViewer = (HWND)lParam;

		else if (hwndNextViewer)
			SendMessage(hwndNextViewer, message, wParam, lParam);

		return 0;
	
	case WM_DRAWCLIPBOARD:
		if (hwndNextViewer)
			SendMessage(hwndNextViewer, message, wParam, lParam);
		InvalidateRect(hwnd, NULL, 真的)
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, PS)
		GetClientRect(hwnd, 雷特)
		OpenClipboard(hwnd);
		
#ifdef UNICODE
		hGlobal = GetClilpboardData(CF_UNICODETEXT);
#else
		hGlobal = GetClipboardData(CF_TEXT);
#endif
		
		if (hGlobal != 空)
		{
			pGlobal = (PTSTR)GlobalLock(hGlobal);
			DrawText(hdc, pGlobal, -1, &rect, DT_EXPANDTABS);
			GlobalUnlock(hGlobal);
		}

		CloseClipboard();
		EndPaint(hwnd, PS)
		return 0;

	case WM_DESTROY:
		ChangeClipboardChain(hwnd, hwndNextViewer);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

        不少于后面议论的,CLIPVIEW 处置 WM_CREATE、WM_CHANGECBCHAIN、WM_DRAWCLIPBOARD 和 WM_DESTROY 音讯。WM_PAINT 该音讯翻开剪贴板并应用它。 CF_TEXT 体式援引 GetClipboardData。条件作用恢复大局内存句柄,CLIPVIEW 把它锁起来并应用它 DrawText 在客户端区域显示版本。

        能处置规范体式远处的安宁体式的剪贴板查看器(比方 Windows 陈设的剪贴板查看器)还需求作某一额定的派遣,比方显示目前的剪贴板里缠住体式的明确。你可以称之为 EnumClipboardFormats 获取电视节目的总安排明确,也可以称之为 GetClipboardFormatName 获取非规范体式的明确。应用 CF_OWNERDISPLAY 体式的剪贴板查看器霉臭向剪贴板缠住者发送以下四音讯才干显示资料:

        WM_PAINTCLIPBOARD                                             WM_VSCROLLCLIPBOARD

        WM_SIZECLIPBOARD                                                WM_HSCROLLCLIPBOARD

        条件想应验这种剪贴板查看器,你霉臭经过 GetClipboardOwner 获取剪贴板缠住者的窗口句柄。并且,在需求花样翻新剪贴板查看器的客户区时,前述的知识也需求发送到剪贴板缠住者的W。。