Поделиться через


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

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

Проектирование обработки окна

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

При регистрации класса окна вы связываете процедуру обработки окна с классом окна. Необходимо заполнить структуру WNDCLASS информацией о классе, а член lpfnWndProc должен указывать адрес оконной процедуры. Чтобы зарегистрировать класс, передайте адрес структуры WNDCLASS в функцию RegisterClass. После регистрации класса окна процедура окна автоматически связывается с каждым новым окном, созданным с этим классом.

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

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); 
}