Korzystanie z funkcji okna
W tej sekcji opisano sposób wykonywania następujących zadań skojarzonych z procedurami okien.
Projektowanie procedury obsługi okna
Poniższy przykład przedstawia strukturę typowej procedury okna (window procedure). Procedura okna używa argumentu komunikatu w instrukcji przełącznika jako, gdzie poszczególne komunikaty są obsługiwane przez oddzielne instrukcje case. Zwróć uwagę, że każdy przypadek zwraca określoną wartość dla każdego komunikatu. W przypadku komunikatów, które nie są przetwarzane, procedura okna wywołuje funkcję DefWindowProc.
LRESULT CALLBACK MainWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{
switch (uMsg)
{
case WM_CREATE:
// Initialize the window.
return 0;
case WM_PAINT:
// Paint the window's client area.
return 0;
case WM_SIZE:
// Set the size and position of the window.
return 0;
case WM_DESTROY:
// Clean up window-specific data objects.
return 0;
//
// Process other messages.
//
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
Komunikat WM_NCCREATE jest wysyłany tuż po utworzeniu okna, ale jeśli aplikacja odpowie na ten komunikat, zwracając false, funkcja CreateWindowEx zakończy się niepowodzeniem. Komunikat WM_CREATE jest wysyłany po utworzeniu okna.
Komunikat WM_DESTROY jest wysyłany, gdy okno ma zostać zniszczone. Funkcja DestroyWindow zajmuje się zniszczeniem wszelkich okien podrzędnych okna, które jest niszczone. Komunikat WM_NCDESTROY jest wysyłany tuż przed zniszczeniem okna.
Przynajmniej procedura okna powinna przetworzyć komunikat WM_PAINT, aby wykonać rysowanie. Zazwyczaj powinna obsługiwać również komunikaty myszy i klawiatury. Zapoznaj się z opisami poszczególnych komunikatów, aby określić, czy procedura okna powinna je obsługiwać.
Aplikacja może wywołać funkcję DefWindowProc w ramach przetwarzania komunikatu. W takim przypadku aplikacja może zmodyfikować parametry komunikatu przed przekazaniem komunikatu do DefWindowProclub może kontynuować domyślne przetwarzanie po wykonaniu własnych operacji.
Procedura okna dialogowego odbiera komunikat WM_INITDIALOG zamiast komunikatu WM_CREATE i nie przekazuje nieprzetworzonych komunikatów do funkcji DefDlgProc. W przeciwnym razie procedura okna dialogowego jest dokładnie taka sama jak procedura okna.
Kojarzenie procedury okna z klasą okien
Podczas rejestrowania klasy okna należy skojarzyć procedurę okna z klasą okien. Należy wypełnić strukturę WNDCLASS informacjami o klasie, a element członkowski lpfnWndProc musi określić adres procedury okna. Aby zarejestrować klasę, przekaż adres struktury WNDCLASS do funkcji RegisterClass . Po zarejestrowaniu klasy okna procedura okna jest automatycznie skojarzona z każdym nowym oknem utworzonym z tą klasą.
W poniższym przykładzie pokazano, jak skojarzyć procedurę okna w poprzednim przykładzie z klasą okien.
int APIENTRY WinMain(
HINSTANCE hinstance, // handle to current instance
HINSTANCE hinstPrev, // handle to previous instance
LPSTR lpCmdLine, // address of command-line string
int nCmdShow) // show-window type
{
WNDCLASS wc;
// Register the main window class.
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MainWindowClass";
if (!RegisterClass(&wc))
return FALSE;
//
// Process other messages.
//
}
Podklasowanie okna
Aby podklasować wystąpienie okna, wywołaj funkcję SetWindowLong i określ uchwyt do okna z flagą GWL_WNDPROC oraz wskaźnik do procedury podklasy. SetWindowLong zwraca wskaźnik do oryginalnej procedury okna; użyj tego wskaźnika, aby przekazać komunikaty do oryginalnej procedury. Procedura okna podklasy musi używać funkcji CallWindowProc, aby wywołać oryginalną procedurę okna.
Notatka
Aby napisać kod zgodny zarówno z 32-bitowymi, jak i 64-bitowymi wersjami systemu Windows, użyj funkcji SetWindowLongPtr.
W poniższym przykładzie pokazano, jak podklasować wystąpienie kontrolki edycji w oknie dialogowym. Procedura okna podklasy umożliwia kontrolce edycji odbieranie wszystkich danych wejściowych klawiatury, w tym ENTER i TAB, za każdym razem, gdy kontrolka ma fokus wejściowy.
WNDPROC wpOrigEditProc;
LRESULT APIENTRY EditBoxProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndEdit;
switch(uMsg)
{
case WM_INITDIALOG:
// Retrieve the handle to the edit control.
hwndEdit = GetDlgItem(hwndDlg, ID_EDIT);
// Subclass the edit control.
wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit,
GWL_WNDPROC, (LONG) EditSubclassProc);
//
// Continue the initialization procedure.
//
return TRUE;
case WM_DESTROY:
// Remove the subclass from the edit control.
SetWindowLong(hwndEdit, GWL_WNDPROC,
(LONG) wpOrigEditProc);
//
// Continue the cleanup procedure.
//
break;
}
return FALSE;
UNREFERENCED_PARAMETER(lParam);
}
// Subclass procedure
LRESULT APIENTRY EditSubclassProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
if (uMsg == WM_GETDLGCODE)
return DLGC_WANTALLKEYS;
return CallWindowProc(wpOrigEditProc, hwnd, uMsg,
wParam, lParam);
}