Использование оконных процедур

В этом разделе объясняется, как выполнять следующие задачи, связанные с процедурами окон.

Проектирование процедуры окна

В следующем примере показана структура типичной процедуры окна. Процедура окна использует аргумент сообщения в операторе 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); 
}