標籤:directhwnd libuidk 介面 c++ skin
廣告先:
LibUIDK介面庫:製作QQ、360介面時,你能找到的最強大的介面庫。基於DirectHWND技術!
3.1 視窗的建立
一個簡單的win32程式如下(假設工程名為“HelloWin32”,下面的代碼是使用vc6.0建立一個名為HelloWin32的“Win32 Application”,並且選擇“A typical "Hello World" application”後建立的代碼精簡後得到):
// HelloWin32.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// Register class.
static TCHAR szClassName[] = _T("HelloWin32");
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_HELLOWIN32);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_HELLOWIN32;
wcex.lpszClassName = szClassName;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
RegisterClassEx(&wcex);
// Perform application initialization:
HWND hWnd = CreateWindow(szClassName, _T("The hello win32 app"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (hWnd == NULL)
{
return 0;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
HACCEL hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_HELLOWIN32);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
static TCHAR szHello[] = _T("Hello win32");
switch (message)
{
case WM_CREATE:
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
我們單步調試上面的代碼,在WndProc的WM_PAINT訊息中加個斷點,在執行UpdateWindow(hWnd)這行代碼時,我們就會發現會進入到WM_PAINT中,但這時,還沒有進入下面的訊息迴圈。我們知道,訊息迴圈是從訊息佇列中取訊息,既然沒有執行訊息迴圈前就可以處理WM_PAINT訊息,說明這個WM_PAINT訊息是直接發往視窗、而沒有進入訊息佇列的。這句話的意思是:訊息迴圈會調用WndProc,但並不是只有訊息迴圈可以調用WndPorc,windows本身也可以調用。我們可以想像一下CreateWindow的虛擬碼:
HWND CreateWindow(...)
{
HWND hWnd = NULL;
// 分配視窗記憶體,產生視窗
hWnd = ...;
CREATESTRUCT cs;
// 初始化cs.
WndProc(hWnd, WM_CREATE, 0, LPARAM(&cs)); // CreateWindow內部不經訊息迴圈,直接調用WndProc
// 執行其它操作
return hWnd;
}
DispatchMessage的虛擬碼可能如下:
LRESULT DispatchMessage(const MSG *lpmsg)
{
// 執行其它操作
WndProc(lpmsg->hwnd, lpmsg->message, lpmsg->wParam, lpmsg->lParam);
// 執行其它操作
return 0;
}
其實,早在CreateWindow時,Windows就調用WndProc並傳遞了WM_CREATE訊息。WM_CREATE是程式收到的第一個訊息。類似的,ShowWindow可能會觸發WM_SIZE和WM_SHOWWINDOW訊息。
被投遞到訊息佇列中的訊息叫“隊列訊息”,不在隊列中的為“非隊列訊息”。一個訊息是隊列訊息還是非隊列訊息並不是絕對的,比如WM_PAINT可以是隊列訊息(視窗顯示之後調用InvalidateRect,就會往訊息佇列中增加一條WM_PAINT訊息),也可以是非隊列訊息(上面UpdateWindow發出的那個),對於程式員,大部分時間,不用關心某個訊息是隊列訊息,還是非隊列訊息,你只需知道它們都最終是交給WndProc視窗過程、以同步方式 處理的就可以了。
在CreateWindow時,指定視窗初始位置和尺寸時,CW_USEDEFAULT參數表示使用預設值,預設值意味著:Windows會將連續建立的視窗的左上方位置沿水平方向和垂直方向分別作步長為1的位移。
《Windows程式設計 第5版》第3章 視窗與訊息 筆記