Использование оконных процедур
В этом разделе объясняется, как выполнять следующие задачи, связанные с процедурами окон.
Проектирование процедуры окна
В следующем примере показана структура типичной процедуры окна. Процедура окна использует аргумент сообщения в операторе switch с отдельными сообщениями, обрабатываемыми отдельными операторами case . Обратите внимание, что каждый случай возвращает определенное значение для каждого сообщения. Для сообщений, которые не обрабатываются, процедура окна вызывает функцию 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;
}
Сообщение WM_NCCREATE отправляется сразу после создания окна, но если приложение отвечает на это сообщение, возвращая значение FALSE, функция CreateWindowEx завершается ошибкой. Сообщение WM_CREATE отправляется после создания окна.
Сообщение WM_DESTROY отправляется, когда окно будет уничтожено. Функция DestroyWindow отвечает за уничтожение всех дочерних окон окна, которые будут уничтожены. Сообщение WM_NCDESTROY отправляется непосредственно перед уничтожением окна.
По крайней мере, оконная процедура должна обрабатывать WM_PAINT сообщение для рисования себя. Как правило, он также должен обрабатывать сообщения мыши и клавиатуры. Ознакомьтесь с описаниями отдельных сообщений, чтобы определить, следует ли обрабатывать их в процедуре окна.
Приложение может вызывать функцию DefWindowProc в процессе обработки сообщения. В этом случае приложение может изменить параметры сообщения перед передачей сообщения в DefWindowProc или продолжить обработку по умолчанию после выполнения собственных операций.
Процедура диалогового окна получает WM_INITDIALOG сообщение вместо сообщения WM_CREATE и не передает необработанные сообщения в функцию DefDlgProc . В противном случае процедура диалогового окна точно такая же, как и процедура окна.
Связывание процедуры Window с классом Window
При регистрации класса процедура окна связывается с оконным классом. Необходимо заполнить структуру WNDCLASS сведениями о классе, а член lpfnWndProc должен указать адрес процедуры окна. Чтобы зарегистрировать класс, передайте адрес структуры WNDCLASS в функцию RegisterClass . После регистрации класса window процедура окна автоматически связывается с каждым новым окном, созданным с помощью этого класса.
В следующем примере показано, как связать процедуру окна в предыдущем примере с классом окна.
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.
//
}
Подклассы окна
Чтобы выполнить подкласс экземпляра окна, вызовите функцию SetWindowLong и укажите дескриптор окна для подкласса флага GWL_WNDPROC и указателя на процедуру подкласса. SetWindowLong возвращает указатель на исходную процедуру окна; Используйте этот указатель для передачи сообщений в исходную процедуру. Процедура окна подкласса должна использовать функцию CallWindowProc для вызова исходной процедуры окна.
Примечание
Чтобы написать код, совместимый как с 32-разрядной, так и с 64-разрядной версиями Windows, используйте функцию SetWindowLongPtr .
В следующем примере показано, как выполнить подкласс экземпляра элемента управления редактирования в диалоговом окне. Процедура окна подкласса позволяет элементу управления редактирования получать все входные данные с клавиатуры, включая клавиши ВВОД и TAB, всякий раз, когда элемент управления имеет фокус ввода.
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);
}