#include<windows.h>
#include"SYSMET.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("SysMets1");
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,
TEXT("Get System Metrics No.1"),
WS_OVERLAPPEDWINDOW | WS_VSCROLL,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
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)
{
HDC hdc;
PAINTSTRUCT ps;
static int cxChar, cxCaps, cyChar, cyClient, iVscrollPos;
TEXTMETRIC tm;
int i, y;
TCHAR szBuffer[10];
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm); //获取字体的各种信息
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
ReleaseDC(hwnd, hdc);
SetScrollRange(hwnd, SB_VERT, 0, NUMLINES - 1, FALSE);
SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
return 0;
case WM_SIZE:
cyClient = HIWORD(lParam); //客户区高度
return 0;
case WM_VSCROLL:
switch (LOWORD(wParam))
{
case SB_LINEUP:
iVscrollPos -= 1;
break;
case SB_LINEDOWN:
iVscrollPos += 1;
break;
case SB_PAGEUP:
iVscrollPos -= cyClient / cyChar;
break;
case SB_PAGEDOWN:
iVscrollPos += cyClient / cyChar;
break;
case SB_THUMBPOSITION:
iVscrollPos = HIWORD(wParam);
break;
}
iVscrollPos = max(0, min(iVscrollPos, NUMLINES - 1));
if (iVscrollPos != GetScrollPos(hwnd, SB_VERT))
{
SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
InvalidateRect(hwnd, NULL, TRUE); //使客户区无效,从而发送WM_PAINT进行重绘
}
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
for (i = 0; i < NUMLINES; i++)
{
y = cyChar * (i - iVscrollPos);
TextOut(hdc, 0, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));
TextOut(hdc, 22 * cxCaps, y, sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));
SetTextAlign(hdc, TA_RIGHT | TA_TOP); //设置右对齐
TextOut(hdc, 22 * cxCaps + 40 * cxChar, y, szBuffer, wsprintf(szBuffer, TEXT("%5d"), GetSystemMetrics(sysmetrics[i].Index)));
SetTextAlign(hdc, TA_LEFT | TA_TOP);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
获取句柄和释放句柄只能在一跳消息中,CreateDC除外
case WM_PAINT:
return 0;
这种代码会使windows不停发生WM_PAINT,因为没有使用BeginPaint使无效区域有效化,即一直处于无效状态,所以才会一直发送WM_PAINT。
GetWindowDC返回的是整个窗口的设备环境句柄,GetWindowDC返回的句柄可以在窗口的标题栏进行输出,相应的,程序也要处理WM_NCPAINT(非客户区绘制)消息。
GetDC返回的设备环境句柄中的裁剪矩形是整个客户区,所以可以在客户区任意部分绘制,即使没有无效矩形也没有关系。GetDC不会讲无效区域有效化,如果要使整个客户区有效化,需调用ValidateRect(hwnd, NULL)。而InvalidateRect(hwnd, NULL, TRUE)会是整个客户区无效化,并使其后调用的BeginPaint擦除原有的背景