摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P281
本章的最后一个程序我在第 5 章也提及过。我觉得该程序是 GetPixel 函数唯一有用的地方。
WHATCLR 显示了鼠标指针当前所指的热点的 RGB 颜色。
/*--------------------------------------------------------
WHATCLR.C -- Displays Color Under Cursor
(c) Charles Petzold, 1998
--------------------------------------------------------*/
#include <windows.h>
#define ID_TIMER 1
void FindWindowSize (int *, int *);
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("WhatClr") ;
HWND hwnd ;
int cxWindow, cyWindow;
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 ;
}
FindWindowSize(&cxWindow, &cyWindow);
hwnd = CreateWindow (szAppName, TEXT ("What Color"),
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER,
CW_USEDEFAULT, CW_USEDEFAULT, cxWindow, cyWindow,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
void FindWindowSize (int * pcxWindow, int * pcyWindow)
{
HDC hdcScreen;
TEXTMETRIC tm;
hdcScreen = CreateIC (TEXT("DISPLAY"), NULL, NULL, NULL);
GetTextMetrics(hdcScreen, &tm);
DeleteDC(hdcScreen);
*pcxWindow = 2 * GetSystemMetrics(SM_CXBORDER) +
12 * tm.tmAveCharWidth;
*pcyWindow = 2 * GetSystemMetrics(SM_CYBORDER) +
GetSystemMetrics(SM_CYCAPTION) +
2 * tm.tmHeight;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static COLORREF cr, crLast;
static HDC hdcScreen;
HDC hdc;
PAINTSTRUCT ps;
POINT pt;
RECT rc;
TCHAR szBuffer[16];
switch (message)
{
case WM_CREATE:
hdcScreen = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
SetTimer(hwnd, ID_TIMER, 100, NULL);
return 0;
case WM_TIMER:
GetCursorPos(&pt);
cr = GetPixel(hdcScreen, pt.x, pt.y);
SetPixel(hdcScreen, pt.x, pt.y, 1);
if (cr != crLast)
{
crLast = cr;
InvalidateRect(hwnd, NULL, FALSE);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
wsprintf(szBuffer, TEXT(" %02X %02X %02X "),
GetRValue(cr), GetGValue(cr), GetBValue(cr));
DrawText(hdc, szBuffer, -1, &rc,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
DeleteDC(hdcScreen);
KillTimer(hwnd, ID_TIMER);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
当 WHATCLR 还在 WinMain 的时候,它做了一件不太一样的小事。因为 WHATCLR 的窗口只需要显示一个十六进制的 RGB 颜色,所以它用 WS_BORDER 窗口风格通过 CreateWindow 函数创建了一个固定大小的窗口。为了计算窗口的大小,WHATCLR 通过调用 CreateIC和 GetSystemMetrics 从视频显示设备 获取一个信息设备环境。计算所得的窗口宽度和高度被传入到 CreateWindow 函数来创建窗口。
在处理 WM_CREATE 消息时,通过调用 CreateDC,WHATCLR 的窗口过程为整个视频显示创建了一个设备环境。这个设备环境会再程序运行时一直维持有效。在处理 WM_TIMER 消息的时候,程序会获得当前鼠标指针位置的像素颜色,然后在处理 WM_PAINT 的时候,显示所获得的 RGB 颜色。
你可能会想,从 CreateDC 函数获取的设备环境的句柄是否也可以用来在屏幕上的任何区域显示一些其他东西,而不仅仅是获取一个像素的颜色?答案是肯定的。虽然通常一个应用程序越界到另一个程序的版面上画图是不礼貌的,但在某些特殊情况下,也未尝不可。