    Обзор традиционной методики программирования в Windows 

    В главе 1 уже говорилось о том, что раньше, до появления MFC, программы 
для Windows писались без иерархий классов, функцийчленов и обработчиков 
сообщений. Традиционный подход к программированию под Windows предусматривал 
непосредственное использование API-функций и требовал от программиста явной 
обработки всех необходимых деталей. Основное преимущество MFC состоит в том, 
что использование библиотеки классов дало возможность скрыть большинство 
частных деталей, обычных для традиционных программ. Для написания MFC-программ 
не требуется широких знаний в области программирования под Windows. Однако это 
может оказаться полезным, особенно в тех случаях, когда необходимо 
конвертировать обычную программу в MFC-программу. В данном приложении кратко 
рассматривается традиционная методика написания приложений. Кроме того, здесь 
описываются некоторые из наиболее важных элементов Windowsпрограмм, такие как 
цикл сообщений, функция окна и функция WinMain(). 

    481 

    Если раньше вам не приходилось писать традиционные программы под Windows, 
то данное приложение даст вам представление о необходимых основах. 
    В отличие от MFC-кода, который в значительной степени независим от 
конкретной платформы, традиционные Windows-программы должны быть адаптированы 
к определенной версии Windows. Программа, разрабатываемая в данном приложении, 
ориентирована на работу в Windows 95. Однако описываемые методы 
программирования применимы для всех версий Windows, включая Windows 3.1 и 
Windows NT. 
    Примечание: Данное приложение было заимствовано автором из его же книги 
"Программирование но С и C++ для Windows 95" ("Windows 95 Programming in С and 
C++"). Тем, кто интересуется традиционной методикой программирования под 
Windows, рекомендуем прочесть эту книгу. 

    Базовые элементы Windows-приложений 

    Перед разработкой каркаса приложения для Windows 95 необходимо рассмотреть 
ряд базовых элементов, лежащих в основе всех Windows-программ. В начале книги 
вы познакомились с этими элементами с точки зрения MFC. Здесь же они 
представлены с точки зрения традиционной методики программирования. 

    Функция WinMainQ 

    Все Windows-программы начинают выполнение с вызова функции WinMainQ. (Как 
правило, Windows-программы не содержат 4)ункцию main().) Эта функция имеет ряд 
особенностей, отличающих ее от остальных функций, используемых в программе. В 
частности, она должна указываться со спецификатором WINAPI, обозначающим тип 
вызова ф)ункции. (Может использоваться также спецификатор APIENTRY, который, в 
принципе, означает то же самое.) В программах, написанных на С и C++, по 
умолчанию используется соглашение о вызовах функций, принятое для языка С. 
Однако допускается компилировать функции с другим типом вызова. Например, 
часто используется соглашение о вызовах функций, принятое для языка Pascal. По 
некоторым причинам в Windows 95 для функции WinMainQ определен тип вызова 
WINAPI. Эта функция должна возвращать значение типа int. 

    Функция окна 

    Все Windows-программы должны содержать специальную функцию, которая не 
используется в самой программе, но вызывается операционной системой. Эту 
функцию обычно называют функцией окна, или процедурой окна. Она вызывается 
Windows, когда системе необходимо передать сообщение в программу. Именно через 
нее осуществляется взаимодействие между программой и системой. Функция окна 
передает сообщение в своих аргументах. В Windows 95 функции окна должны быть 
объявлены как LRESULT CALLBACK. Тип LRESULT определен с помощью 
typedefдекларации и на момент написания книги обозначал длинное целое (long 
int). Спецификатор CALLBACK, обозначающий тип вызова функции, используется для 
тех функций, которые должны вызываться самой Windows 95. По терминологии 
Windows такие функции называются функциями обратного вызова. 

    482                                    MFC: основы программирования 

    Помимо принятия сообщения от Windows, функция окна должна вызывать 
выполнение действия, указанного в сообщении. Обычно, функция окна состоит из 
оператора switch, в котором на каждое сообщение предусмотрена соответствующая 
реакция. Конечно, программа не обязана отвечать на все сообщения, посылаемые 
Windows. Поскольку их могут быть сотни, то большинство из них обычно 
обрабатывается самой системой, а программе достаточно поручить Windows 
выполнить действия, предусмотренные по умолчанию. 
    В Windows 95 все сообщения представляются 32-разрядными целочисленными 
значениями. Кроме того, с сообщением может быть связана дополнительная информация. 

    Класс окна 

    Когда Windows-приложение начинает свое выполнение, оно должно определить и 
зарегистрировать класс окна. (Здесь понятие "класс" не идентично используемому 
в C++. Скорее, оно означает стиль или тип.) При регистрации необходимо 
сообщить Windows, какой вид должно иметь окно и какую функцию оно выполняет. В 
то же время регистрация класса окна еще не означает создания самого окна. Для 
этого требуется выполнить дополнительные действия. 

    Цикл сообщений 

    Как объяснялось ранее, Windows взаимодействует с программой, посылая ей 
сообщения. Все приложения Windows должны организовывать так называемый цикл 
сообщений внутри функции WinMain(). В этом цикле каждое необработанное 
сообщение должно быть извлечено из очереди сообщений данного приложения и 
передано назад в Windows, которая затем вызывает функцию окна программы с 
данным сообщением в качестве аргумента. Процесс получения и обработки 
сообщений может показаться чересчур сложным, но, тем не менее, ему должны 
следовать все Windows-программы. (Отчасти это необходимо для передачи 
управления назад в Windows, чтобы системный планировщик мог распределить 
ресурсы центрального процессора более эффективно, а не дожидаться, пока 
истечет промежуток времени, выделенный программе.) 

    Типы данных в Windows 

    Как вы, наверное, знаете, в Windows-программах не слишком широко 
применяются стандартные типы данных из С или C++, такие как int или char*. 
Вместо них используются типы данных, определенные с помощью typedef-деклараций 
в файле WINDOWS.H и аналогичных ему файлах. Этот файл поставляется фирмой 
Microsoft (а также любой другой фирмой, выпускающей компиляторы с C/C++ для 
Windows) и должен быть включен во все Windows-программы. Наиболее часто 
используемыми типами являются HANDLE, HWND, BYTE, WORD, DWORD, UINT, LONG, 
BOOL, LPSTR и LPCSTR. В 32-разрядных версиях Windows (включая Windows 95) тип 
HANDLE обозначает 32-разрядное целое, используемое в качестве дескриптора. 
Есть несколько похожих типов данных, но все они имеют ту же длину, что и 
HANDLE, и начинаются с литеры H. Дескриптор — это просто число, определяющее 
некоторый ресурс. Например, тип HWND обозначает 32-разрядное целое — 
дескриптор окна. Тип BYTE обозначает 8-разрядное беззнаковое символьное 
значение, тип WORD — 

    А. Обзор традиционной методики программирования в Windows        483 

    16-разрядное беззнаковое короткое целое, тип DWORD — беззнаковое длинное 
целое, тип UINT — беззнаковое 32-разрядное целое. Тип LONG эквивалентен типу 
long. Тип BOOL обозначает целое и используется, когда значение может быть либо 
истинным, либо ложным. Тип LPSTR определяет указатель на строку, a LPCSTR— 
константный (const) указатель на строку. 
    Помимо базовых типов, перечисленных выше, в Windows 95 определено 
несколько структур. В следующем примере используются две из них: MSG и 
WNDCLASSEX. Структура MSG содержит информацию о сообщении, посылаемом Windows. 
Структура WNDCLASSEX определяет класс окна. Эти структуры будут подробно 
рассмотрены далее. 

    Каркас программы для Windows 95 

    Теперь, когда необходимая информация изложена, давайте напишем минимальное 
Windows-приложение. Как уже упоминалось, оно предназначено для Windows 95. Тем 
не менее текст такой программы был бы практически одинаков для всех версий 
Windows. В программировании под Windows каркасы программ используются довольно 
часто, поскольку создавать Windows-приложение "с нуля" иногда очень сложно. 
Если минимальная MFC-программа может занимать лишь несколько строчек, то для 
написания аналогичного приложения традиционным способом требуется около 50 
строк. Поэтому в последнем случае имеет смысл заранее создавать каркас программы. 
    Минимальная программа для Windows 95 содержит две функции: WinMain() и 
функцию окна. Функция WinMain() должна выполнить следующие основные действия: 
    1. Определить класс окна. 
    2. Зарегистрировать класс окна в Windows 95. 
    3. Создать окно, определяемое данным классом. 
    4. Отобразить это окно. 
    5. Запустить цикл сообщений. 
    Функция окна должна отвечать на все поступающие сообщения. Поскольку 
данная программа не выполняет никаких специальных действий, а лишь отображает 
окно, то единственное сообщение, которое она должна обрабатывать, поступает 
при завершении пользователем приложения. 
    Прежде всего проверьте работу данной программы. В ней создается 
стандартное окно с заголовком. Это окно также содержит системное меню, 
следовательно, его можно минимизировать, раскрывать на весь экран, перемещать, 
масштабировать и закрывать. Кроме того, в окне имеются стандартные копки 
минимизации, максимизации и закрытия. Программа написана на C++ и может быть 
откомпилирована с помощью любого стандартного компилятора с C/C++, который 
позволяет создавать программы для Windows 95. 

    /* Каркас программы для Windows 95 */ 
    ftinclude <windows.h> 
    LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM); 


    484                                    MFC: основы программирования 


    char szWinName[] = "MyWin"; /* имя класса окна */ 
    int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, 
    LPSTR IpszArgs, int nWinMode) I 
    HWND hwnd; 
    MSG msg; 
    WNDCLASSEX wcl; 
    /* Определение класса окна*/ 
    wcl.hinstance = hThisInst; /* дескриптор данного экземпляра */ 
    wcl.IpszClassName = szWinName; /* имя класса окна */ 
    wcl. IpfnWndProc = WindowFunc; /* функциж-жна */ 
    wcl.style = 0; /* стиль по умолчанию */ 
    
    wcl.cbSize = sizeof(WNDCLASSEX); /* размер структуры */ 
    /* WNDCLASSEX */ 
    
    wcl.hlcon = LoadIcon(NULL, IDI_APPLICATION); /* большая */ 
    
    /* пиктограмма */ 
    wcl.hIconSm = LoadIcon(NULL, IDI_WINLOGO); /* малая */ 
    
    /* пиктограмма */ 
    
    wcl.hCursor = LoadCursor(NULL, IDC_ARROW); /* форма курсора */ 
    wcl.IpszMenuName = NULL; /* меню не используется */ 
    
    wcl.cbClsExtra = 0; /* дополнительная информация отсутствует */ 
    wcl.cbMndExtra = 0; 
    
    /* Фон окна задается белым */ 
    wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 
    
    /* Регистрация класса окна */ 
    ;     if(IRegisterClassEx(&wcl)) return 0; 
    /* Создание окна */ 
    hwnd = CreateWindow ( 
    szWinName, /* имя класса окна */ 
    "Windows 95 Skeleton", /* заголовок */ 
    WS OVERLAPPEDWINDOW, /* стандартное окно */ 
    CW_USEDEFAULT, /* координата X - определяется Windows */ 
    CW_USEDEFAULT, /* координата Y — определяется Windows */ 
    CW_USEDEFAULT, /* ширина - определяется Windows */ 
    CW USEDEFAULT, /* высота — определяется Windows */ 
    HWND_DESKTOP, /* родительского окна нет */ 
    NULL, /* меню нет */ 
    hThisInst, /* дескриптор данного экземпляра приложения */ 
    NULL, /* дополнительных аргументов нет */ 
    ); 
    
    /* Отображение окна */ 
    ShowWindow(hwnd, nWinMode); 
    UpdateWindow(hwnd) ; 


    А. Обзор традиционной методики программирования в Windows        485 


    /* Цикл сообщений */ 
    while(GetMessaqe(&msg, NULL, О, О)) 
    ( 
    
    TranslateMessage(&msg); /* разрешает использование */ 
    /* клавиатуры */ 
    
    DispatchMessage(&msg); /* возвращает управление Windows */ 
    ) 
    return msg.wParam; 
    
    /* Эта функция вызывается Windows 95, которая передает ей */ 
    /* сообщения из очереди сообщений */ 
    LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, 
    
    WPARAM wParam, LPARAM IParam) 
    ( 
    
    switch(message) { 
    
    case WM_DESTROY: /* завершение программы */ 
    PostQuitMessage(0) ; 
    
    break; 
    
    default: 
    
    
    /* Позволяет Windows 95 обрабатывать любые сообщения, */ 
    /* не указанные в предыдущем случае */ 
    return DefWindowProc (hwnd, message, wParam, IParam); 
    
    ) 
    return 0; 
    
    } 
    
    Пример работы программы показан на рис. A.I. Давайте пошагово проследим 
выполнение программы. 
    
    ! Windows 95 Skeleton 

    Рис. А. I. Окно каркасной программы 


    486 MFC: основы программирования 

    Все программы, написанные для Windows 95, должны включать библиотечный 
файл WINDOWS.H. Как уже упоминалось, этот файл (вместе с рядом других 
вспомогательных файлов) содержит прототипы API-функций, а также определения 
различных типов данных, макросов и констант, используемых в Windows 95. 
Например, типы HWND и WNDCLASSEX определены именно в файле WINDOWS.H. 
    Функция окна, используемая в программе, называется WindowFunc(). Она 
объявлена как 4:>ункция обратного вызова, поскольку вызывается Windows 95 для 
взаимодействия с программой. 
    Программа начинает выполнение с вызова функции WinMainQ, которой 
передается четыре параметра. Параметры hThisInst и hPrevInst являются 
дескрипторами. Первый из них идентифицирует текущий экземпляр приложения. 
Помните, что Windows является многозадачной операционной системой, в которой 
возможно одновременное выполнение нескольких экземпляров одной и той же 
программы. Параметр hPrevInst всегда равен NULL. (В Windows 3.1 этот параметр 
содержал бы ненулевое значение, если бы в данный момент выполнялись другие 
экземпляры программы. Однако в Windows 95 это больше не используется.) 
Параметр IpszArgs является указателем на строку, содержащую аргументы 
командной строки, переданные приложению при запуске. Параметр nWinMode 
содержит значение, определяющее, каким образом должно быть отображено окно 
программы при запуске. 
    В функции WinMainQ создаются три переменные. Первая из них, hwnd, будет 
содержать дескриптор окна программы. В структуре msg будет храниться 
информация о получаемых сообщениях, а структура wcl предназначена для 
определения класса окна. 

    Определение класса окна 

    Первые два действия, которые выполняет функция WinMainQ, — это определение 
класса окна и его регистрация. Класс окна определяется путем заполнения полей 
структуры типа WNDCLASSEX. Эти поля заданы следующим образом: 

    UINT cbSize; /* размер структуры WNDCLASSEX */ 
    UINT style; /* тип окна */ 
    WNDPROC IpfnMndProc; /* адрес функции окна */ 
    int cbClsExtra; /* дополнительная информация о классе */ 
    int cbWndExtra; /* дополнительная информация об окне */ 
    HINSTANCE hinstance; /* дескриптор данного экземпляра программы */ 
    HICON Ысоп; /* дескриптор большой пиктограммы */ 
    HICON hIconSm; /* дескриптор малой пиктограммы */ 
    HCURSOR hCursor; /* дескриптор курсора мыши */ 
    HBRUSH hbrBackground; /* цвет фона */ 
    LPCSTR IpszMenuName; /* имя главного меню */ 
    LPCSTR IpszClassName; /* имя класса окна */ 

    Из текста программы видно, что в поле cbSize записывается размер структуры 
WNDCLASSEX. В поле hinstance записывается дескриптор текущего экземпляра 
приложения, содержащийся в параметре hThisInst. Поле IpszClassName содержит 
указатель на имя класса окна, которым в данном случае является строка "MyWin". 
Адрес функции окна записывается в поле IpfnWndProc. 

    А. Обзор традиционной методики программирования в Windows        487 

    Все приложения Windows должны определять стандартный вид курсора мыши, а 
также пиктограммы приложения. В программе могут использоваться собственные 
ресурсы курсоров и пиктограмм, но могут задаваться и встроенные стили, как это 
сделано в данном примере. В любом случае дескрипторы указанных ресурсов должны 
быть записаны в соответствующие поля структуры WNDCLASSEX. Эти действия стоит 
рассмотреть подробнее. 
    В Windows 95 с приложением связаны две пиктограммы: малая и большая. Малая 
пиктограмма отображается в системном меню, а также когда окно приложения 
минимизировано. Большая пиктограмма отображается при перемещении или 
копировании приложения (точнее ссылки на него) на рабочий стол. Обычно большие 
пиктограммы имеют размер 32х32 пикселя, а малые пиктограммы — 16х16 пикселей. 
Каждая пиктограмма загружается с помощью API-функции LoadIconQ, которая имеет 
такой прототип: 

    HICON Loadlcon(HINSTANCE hinst, LPCSTR IpszName); 

    Эта функция возвращает дескриптор пиктограммы. Здесь параметр hinsi 
является дескриптором модуля, который содержит пиктограмму, а ее имя задается 
параметром IpszName. При использовании встроенных пиктограмм первый параметр 
должен равняться NULL, а второй параметр должен содержать одну из следующих 
констант (табл. A.I): 
    
    Таблица А. 1. Встроенные пиктограммы Windov/s 95 

    Константа               Вид пиктограммы 
    
    IDI_APPLICATION      Стандартная системная пиктограмма 
    IDI_ASTERISK         Информационная пиктограмма с буквой "I" 
    IDI_EXCLAMATION     Пиктограмма с восклицательным знаком 
    IDI_HAND             Пиктограмма с надписью "Stop" 
    IDI_QUESTION         Пиктограмма с вопросительным знаком 
    IDI_WINLOGO         Пиктограмма с логотипом Windows 95 
    
    В данном примере в качестве большой пиктограммы используется пиктограмма 
IDl_APPLICATION, а в качестве малой пиктограммы — пиктограмма IDI_WINLOGO. 
Можно также определять собственные пиктограммы. 
    Для загрузки курсора мыши используется API-функция LoadCiirsorQ, имеющая 
такой прототип: 

    HCURSOR LoadCursor(HINSTANCE hinst, LPCSTR IpszName); 

    Эта функция возвращает дескриптор курсора. Здесь параметр hinst является 
дескриптором модуля, который содержит данный курсор, а имя курсора задается 
параметром IpszName. При использовании встроенных курсоров первый параметр 
должен равняться NULL, а второй параметр должен содержать одну из констант 
встроенных курсоров. Ниже приведены некоторые из наиболее часто используемых 
констант (табл. А.2): 

    488                                    MFC: основы программирования 

    Таблица А. 2. Некоторые из встроенных курсоров Windows 95 

    Константа            Форма курсора 

    IDC_ARROW         Стандартный указатель типа "стрелка" 
    IDC_CROSS           Перекрестие 
    IDC_IBEAM          Текстовый курсор 
    IDC_WAIT            Песочные часы 

    Цвет фона окна, создаваемого в программе, определяется белым, а дескриптор 
кисти фона получается с помощью API-функции GetStockObject(). Кистью 
называется ресурс, предназначенный для рисования на экране различных 
графических объектов с использованием готовой маски определенного размера, 
цвета и имеющей некоторый шаблон заполнения. Функция GetStockObject() 
используется для получения дескрипторов различных стандартных графических 
объектов, включая кисти, перья (предназначенные для рисования линий) и шрифты. 
Она имеет следующий прототип: 

    HGDIOBJ GetStockObject(int object); 

    Эта функция возвращает дескриптор объекта, задаваемого параметром object. 
(Тип HGDIOBJ задает дескриптор GDI-объекта.) Вот названия некоторых 
стандартных кистей (табл. А.З): 

    Таблица А.З. Некоторые стандартные кисти 

    Константа            Тип фона 

    BLACK_BRUSH      Черный 
    DKGRAY_BRUSH     Темно-серый 
    HOLLOW_BRUSH     "Прозрачный" 
    LTGRAY_BRUSH     Светло-серый 
    WHITE_BRUSH_____Белый_______________________________ 

    Эти константы можно использовать в качестве параметров функции GetStockObject(). 
    Когда класс окна полностью определен, его необходимо зарегистрировать в 
Windows 95 с помощью API-функции RegisterClassExQ, имеющей такой прототип: 

    ATOM RegisterClassEx(CONST WNDCLASSEX *IpWClass}; 

    Эта функция возвращает значение, идентифицирующее класс окна. Тип ATOM 
определен с помощью typedef-декларации и соответствует типу WORD. Каждому 
классу окна соответствует уникальное числовое значение. Параметр lp WClass 
должен содержать адрес структуры типа WNDCLASSEX. 

    А. Обзор традиционной методики программирования в Windows        489 


    Создание окна 

    Когда класс окна определен и зарегистрирован, приложение может создать 
само окно с помощью API-функции CreateWindowQ, которая имеет следующий прототип: 

    HWND CreateWindow( 
    LPCSTR IpszClassName, /* имя класса окна */ 
    LPCSTR IpszWinName, /* заголовок окна */ 
    DWORD dwStyle, /* тип окна */ 
    int X, int Y, I* координаты верхнего левого угла */ 
    int Width, int Height, /* размеры окна */ 
    HWND hParent, I* дескриптор родительского окна */ 
    HMENU hMenu, /* дескриптор главного меню */ 
    HINSTANCE hThisInsk, /* дескриптор программы, создающей окно*/ 
    LPVOID IpszAdditional /* указатель на дополнительную */ 
    /* информацию */ 
    ) ; 

    Из текста программы видно, что большинство параметров функции могут быть 
заданы по умолчанию или определены как NULL. Например, для параметров X, Y, 
Width и Height чаще всего используется константа CW_USEDEFAULT, которая 
указывает на то, что Windows 95 сама выберет требуемый размер окна и его 
расположение на экране. Если окно не имеет родительского окна, как в данном 
примере, то в параметре hParent необходимо указать константу HWND_DESKTOP (или 
NULL). Если окно не содержит главного меню, то параметр hMenu должен равняться 
NULL. Если никакая дополнительная информация для создания окна не требуется (а 
так чаще всего и бывает), то параметр Ips^Additional также должен равняться 
NULL. (Тип LPVOID определен с помощью typedef-декларации как void *. 
Исторически, тип LPVOID обозначает длинный указатель на void.) 
    Оставшиеся четыре параметра должны быть заданы явно. Первый из них, 
Ips^ClassName, должен указывать на имя класса окна. (Это имя было присвоено 
классу при регистрации.) Заголовок окна содержится в строке, на которую 
указывает параметр Ips^WinName. Это может быть и пустая строка, но обычно окну 
дается заголовок. Стиль (или тип) создаваемого окна задается значением 
параметра dwStyle. Константа WS_OVERLAPPEDWINDOW определяет стандартное окно, 
в котором имеется системное меню, рамка, кнопки минимизации, максимизации и 
закрытия. Хотя этот стиль является наиболее общим, можно определить другой 
стиль по собственным критериям. Для этого достаточно с помощью операции 
побитового ИЛИ объединить несколько констант. Наиболее часто используемые 
константы приведены в табл. А.4. 

    Таблица А.4. Стили масштабируемых окон 

    Константа стиля            Элемент окна 

    WS_OVERLAPPED         Стандартное окно с рамкой 
    WS_MAXIMIZEBOX        Кнопка максимизации 
    WS_MINIMIZEBOX        Кнопка минимизации 
    WS_SYSMENU            Системное меню 
    WS_HSCROLL             Горизонтальная полоса прокрутки 
    WS_VSCROLL__________Вертикальная полоса прокрутки     __ ___ 


    490                                    MFC: основы программирования 

    Параметр hThislnst должен содержать дескриптор текущего экземпляра 
приложения. Функция CreateWindow() возвращает дескриптор создаваемого окна или 
NULL, если окно не может быть создано. 
    Хотя окно создано, оно еще не отображено на экране. Для этого необходимо 
вызвать API-функцию ShowWindowQ, которая имеет такой прототип: 

    BOOL ShowWindow(HWND hund, int nHou) ; 

    Дескриптор отображаемого окна указывается в параметре hwnd. Режим 
отображения задается параметром nHow. При первом отображении окна необходимо в 
качестве данного параметра указать параметр nWinMode функции WinMain(). 
Помните, что этот параметр определяет способ отображения окна при создании 
программы. При последующих вызовах функции можно отображать окно в других 
режимах или закрывать его в случае необходимости. Ниже приведены наиболее 
распространенные значения параметра nHow (табл. А.5): 

    Таблица А.5. Режимы отображения 

    Константа отображения      Действие 

    SW_HIDE                  Окно закрывается 
    SW_MAXIMIZE             Окно раскрывается на весь экран 
    SW_MINIMIZE             Окно сворачивается в пиктограмму 
    SW_RESTORE              Окно приводится к нормальному размеру 

    Функция ShowWindowQ возвращает признак предыдущего состояния окна. Если 
оно было на экране, то результат ненулевой, в противном случае значением 
функции будет ноль. 
    Хотя с технической точки зрения в данной программе нет необходимости 
вызывать функцию UpdateWindowQ, ее вызов все же присутствует, потому что 
данная функция используется в большинстве приложений для Windows 95. 
Фактически, она указывает Windows 95 на необходимость послать программе 
сообщение WM_PAINT. 

    Цикл сообщений 

    В конце функции WinMainQ расположен цикл сообщений. Он является 
неотъемлемой частью всех приложений Windows и предназначен для принятия и 
обработки сообщений, посылаемых Windows 95. Когда приложение выполняется, ему 
непрерывно посылаются сообщения. Они хранятся в очереди сообщений приложения 
до тех пор, пока не будут прочитаны и обработаны. Каждый раз, когда приложение 
собирается прочесть очередное сообщение, оно должно вызвать API-функцию 
GetMessageQ, которая имеет такой прототип: 

    BOOL GetMessage(LPMSG msg, HWND hwnd, UINT min, UINT max} ; 

    Информация, связанная с сообщением, будет записана в структуру, на которую 
указывает параметр msg. Все сообщения, посылаемые окнам, представляются в виде 
структуры типа MSG, которая определена следующим образом: 

    А. Обзор традиционной методики программирования в Windows        491 


    /* Структура сообщения */ 
    typedef struct tagMSG 
    ( 
    HWND hwnd; /* дескриптор окна, которому послано сообщение */ 
    UINT message; /* идентификатор сообщения */ 
    WPARAM wParam; /* информация, зависящая от сообщения */ 
    LPARAM IPararn; /* дополнительная информация */ 
    DWORD time; /* время, когда было послано сообщение */ 
    POINT pt; /* координаты курсора мыши */ 
    ) MSG; 

    Дескриптор окна, которому послано сообщение, содержится в поле hwnd. В 
Windows 95 каждое сообщение представляется 32-разрядным числом, записываемым в 
поле message. Дополнительная информация, связанная с сообщением, указывается в 
полях wParam и IParani. Тип WPARAM определен с помощью typedef-декларации как 
UINT, а тип LPARAM - как LONG. 
    Время, когда было послано сообщение, задается в миллисекундах в поле time. 
В поле pt содержатся координаты курсора мыши на момент передачи сообщения. 
Координаты записываются в структуру типа POINT, которая определена следующим образом: 

    typedef struct tagPOINT 
    ( 
    LONG x,y; 
    } POINT; 

    Если очередь сообщений приложения пуста, то вызов функции GetMessageQ 
передаст управление назад в Windows. 
    Параметр hwnd функции GetMessageQ определяет, для какого окна необходимо 
получить сообщение. Если в приложении несколько окон, то желательно, чтобы 
сообщения принимались каждым из них отдельно. Если же необходимо передавать 
сообщения непосредственно приложению, то в качестве данного параметра нужно 
задать NULL. 
    Оставшиеся два параметра функции GetMessageQ определяют диапазон 
идентификаторов принимаемых сообщений. Как правило, приложение принимает все 
сообщения. В этом случае параметры min и wax должны задаваться равными нулю, 
что и сделано в данной программе. 
    Функция GetMessageQ возвращает ноль, когда пользователь завершает работу с 
программой, что эквивалентно завершению цикла сообщений. В противном случае 
возвращается ненулевое значение. 
    В цикле сообщений вызываются две функции. Первая из них — это API-функция 
TranslateMessage(). Она преобразует виртуальные коды клавиш, генерируемые 
Windows 95, в сообщения клавиатуры. Хотя эта 4:>ункция не обязательно должна 
использоваться во всех приложениях, тем не менее большинство программ ее 
вызывают для корректной работы с клавиатурой. 
    Когда сообщение прочитано и преобразовано, оно должно быть передано назад 
в Windows с помощью API-функции DispatchMessage(). Windows будет хранить это 
сообщение до тех пор, пока не сможет передать его программе в качестве 
параметра функции окна. 

    492                                    MFC: основы программирования 

    Когда цикл сообщений завершается, функция WinMain() также завершает свое 
выполнение, возвращая Windows 95 значение поля msg.wParam. Это поле содержит 
код возврата, генерируемый при завершении программы. 

    Функция окна 

    Вторая функция, используемая в программе, — это функция окна. В данном 
случае она называется WindowFunc(), хотя ее название может быть произвольным. 
В качестве параметров функции окна передаются первые четыре параметра 
структуры MSG. Из них в примере используется лишь идентификатор сообщения. 
    В данном примере функция окна явно отвечает только на сообщение 
WM_DESTROY, которое генерируется, когда пользователь завершает работу с 
приложением. После получения этого сообщения программа должна вызвать 
API-функцию PostQuitMessageQ. Аргументом данной функции является код возврата, 
записываемый в поле msg.wParam в функции WinMain(). При вызове функции 
PostQuitMessage() приложению посылается сообщение WM_QUIT, после чего функция 
GetMessageQ возвращает ноль и останавливает выполнение программы. 
    Все остальные сообщения, принимаемые функцией WindowFunc(), с помощью 
функции DefWindowProc() передаются обратно Windows, которая выполняет 
связанные с ними стандартные действия. Этот шаг необходим, поскольку все 
сообщения так или иначе должны быть обработаны. 

    Сравнение традиционных и MFC-программ 

    Вы, должно быть, заметили, что в некоторых местах каркасная программа 
аналогична MFC-программам. Например, для загрузки пиктограммы в традиционной 
программе используется API-функция LoadIconQ. А в MFC ту же роль выполняет 
функция CWinApp::LoadIcon(). Однако совершенно очевидно, что эквивалентная 
MFC-программа будет гораздо короче и легче для понимания. Как видно из 
примера, в традиционных Windows-программах все детали должны быть указаны 
явно. При использовании MFC многие из этих деталей обрабатываются 
автоматически. Хотя их количество в примере не столь велико, чтобы шокировать 
программиста, все же это весьма существенно. Но еще более важно то, что 
сложность такой программы стремительно возрастает по мере увеличения ее 
размера. По опыту программирования вы должны знать, что при увеличении 
количества частных деталей отладка программы занимает больше времени. Это 
основная причина того, почему все большее число программистов, пишущих 
программы под Windows, переходит на использование MFC. Хотя традиционные 
программы будут существовать еще достаточно долго, уже сейчас очевидно, что 
будущее принадлежит MFC. 

    А. Обзор традиционной методики программирования в Windows        493