Текстовый ввод-вывод

Ввод-вывод с использованием WinAPI

Разбить на страницы
Показывать лекцию целиком

9.1. Файловые операции ввода-вывода с использованием WinAPI

9.1.1. Особенности файловых операций в Microsoft Windows

Файловые операции в операционной системе Microsoft Windows отличаются от файловых операций MS-DOS следующим:

  • Заявлена переносимость всех файловых операций в операционных системах MS Windows на последующие версии. Это значит, что если строго следовать рекомендациям Microsoft Windows в описании её файловых функций, программа будет "эффективно компилироваться" как для платформы Win16, так и для платформы Win32 и Win64;
  • Указанные ниже функции позволяют создавать текстовые файлы размером как до 64 Кбайт, так и до 2 Гбайт (напомню, что в MS-DOS максимальный размер текстового файла - 64 Кбайт);
  • Имена файлов теперь могут писаться в кодировке ANSI с использованием "длинных имён" файлов. В MS-DOS возможно именовать файлы только в кодировке OEM с "короткими" именами файлов и каталогов;
  • Содержимое файла, созданного средствами Windows, сразу и целиком читается в оперативную память компьютера, и уже потом анализируются другими функциями (например, sscanf). В MS-DOS Вы могли вводить и выводить файлы последовательно по строкам, по формату и по записям (используя функции fges, getc, fscanf и др.). Используемый в Windows способ чтения-записи является более "безопасным" для обработчика данных и операционной системы;
  • Следствие вышесказанного. В операционной системе Microsoft Windows нужно открывать файл, осуществлять все операции чтения записи и закрывать файл в пределах обработчика одного сообщения из очереди сообщений Windows. В MS-DOS Вы могли вначале программы открыть файл, где-то в теле программы осуществить операции ввода-вывода, и закрыть файлы в конце программы. В Windows этот способ не работает - программа в ней выполняется не в том порядке, в котором записаны действия, а в том порядке, в каком поступают программе системные вызовы. Вследствие этого, по "логике программы", закрытие файла может произойти прежде, чем операция записи-чтения из файла. Естественно, произойдёт "отказ системы" со всеми вытекающими неприятными последствиями;
  • Функции открытия файлов возвращают операционной системе намного больше информации, чем "обычные" функции открытия файлов MS-DOS. При этом принимать решение, использовать или нет эту расширенную информацию, может сам программист;
  • "Стандартными средствами открытия файлов" в Microsoft Windows невозможно открытие файлов для добавления информации в конец файла.… Наверное, Вы поняли почему. Если нет - отвечаю: при чтении всего файла в буфер в конец файла можно записать любую информацию, с тем чтобы затем её сбросить на диск под тем же именем, и дополнительного режима открытия файлов не требуется;
  • Помимо функций файлового ввода-вывода Microsoft Windows Вы также можете использовать аналогичные функции ввода-вывода MS-DOS, с указанными Выше ограничениями. Но учтите, что функциями ввода-вывода MS-DOS (всё равно, являются ли они консольными, потоковыми или другими), нельзя выводить текст на экран, принтер, COM порт, а также вводить данные с клавиатуры;
  • Примечание: операции потокового вывода на экран и ввода с клавиатуры можно также осуществить и в Windows, указав опцию в IDE при создании проекта "консольное приложение Windows". Этот вопрос Вы можете изучить самостоятельно [38].

    9.1.2. Функции создания и закрытия файлов методами Win API

    Для создания, открытия и закрытия файлов Windows API использует следующие функции:

    ФУНКЦИЯ OpenFile
    СИНТАКСИС: HFILE WINAPI OpenFile( lpszFileName, lpOpenStruct, fuMode)

    LPCSTR lpszFileName - путь к файлу (в виде дальнего указателя на строку в кодировке ANSI, заканчивающуюся двоичным нулём);

    OFSTRUCT FAR* lpOpenStruct - адрес структуры OFSTRUCT, заполняемой при первом открытии файла;

    UINT fuMode - режим работы и атрибуты файла;

    НАЗНАЧЕНИЕ: Открывает файл и связывает с ним дескриптор файла;
    ОПИСАНИЕ: Функция предназначена для создания, открытия, повторного открытия и удаления файлов. В имени файла допускается указывать символы шаблона, такие как "*" и "?". Параметр fuMode используется для определения действий, выполняемых функцией OpenFile, а также задаёт атрибуты файла. Когда функция OpenFile вызывается в первый раз для открытия файла, она заполняет структуру OFSTRUCT, описанную в приложении №1 (смотри пункт 9.4 данной лекции);
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает идентификатор файла, который можно (и нужно) использовать во всех последующих операциях с файлом, или -1 при ошибке;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    ФУНКЦИЯ _lopen
    СИНТАКСИС: HFILE WINAPI _lopen( LPCSTR lpszFileName, int fuOpenMode)

    LPCSTR lpszFileName - путь к файлу (в виде дальнего указателя на строку в кодировке ANSI, заканчивающуюся двоичным нулём);

    int fnOpenMode - параметр определяет режим, в котором открывается файл;

    НАЗНАЧЕНИЕ: Открывает файл и связывает с ним дескриптор файла (упрощённая версия);
    ОПИСАНИЕ: Функция предназначена для открытия, повторного открытия файлов. В имени файла допускается указывать символы шаблона, такие как "*" и "?". Параметр fuMode используется для определения действий, выполняемых функцией _lopen ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает идентификатор файла, который можно (и нужно) использовать во всех последующих операциях с файлом, или HFILE_ERROR при ошибке;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    ФУНКЦИЯ _lclose
    СИНТАКСИС: HFILE WINAPI _lclose( hf )

    HFILE hf - дескриптор закрываемого файла;

    НАЗНАЧЕНИЕ: Закрывает файл, связанный с соответствующим дескриптором;
    ОПИСАНИЕ: Закрывает файл с дескриптором hf ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Если файл закрыт успешно, _lclose возвращает нулевое значение. При ошибке возвращается значение: HFILE_ERROR ;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    ФУНКЦИЯ _lcreat
    СИНТАКСИС: HFILE _lcreat( lpszFileName, fuAttribute)

    LPCSTR lpszFileName - путь к файлу (в виде дальнего указателя на строку в кодировке ANSI, заканчивающуюся двоичным нулём);

    int fuAttribute - переменная позволяет определить атрибуты создаваемого файла;

    НАЗНАЧЕНИЕ: Создаёт файл средствами Win API;
    ОПИСАНИЕ: Это более простая, чем OpenFile, функция для создания новых файлов. Имя файла не должно содержать метасимволов шаблона. Если указанный первым параметром файл не существует, функция _lcreat создаёт его и открывает для записи, возвращая его дескриптор файла. Если файл существует, он обрезается до нулевой длины, и затем открывается для чтения и записи;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Идентификатор созданного файла;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    Отличие функции OpenFile от функции _lopen заключается в поддержке ей расширенной информации о файле, передаваемой структуре OFSTRUCT, и в большем числе поддерживаемых флагов команды. Информацию о флагах функций OpenFile, _lcreate и _lopen смотри в таблице 9.1. Описание функций смотри в приложении №I к данной лекции (пункт 9.4).

    Флаги и режимы открытия файлов средствами WinAPI.
    Константа Описание
    ФУНКЦИЯ OpenFile
    OF_READ Файл открывается только для чтения.
    OF_WRITE Файл открывается только для записи.
    OF_READWRITE Файл открывается для чтения и записи.
    OF_SHARE_COMPAT Открытие файла в режиме совместимости. В этом режиме несколько приложений могут одновременно открыть файл, причём все эти приложения должны открывать файл в режиме совместимости.
    OF_SHARE_EXCLUSIVE Файл открывается в монопольном режиме. Для всех других приложений доступ к этому файлу на чтение и запись запрещён.
    OF_SHARE_DENY_WRITE После открытия файла к нему запрещается доступ со стороны других приложений на запись.
    OF_SHARE_DENY_READ После открытия файла к нему запрещается доступ со стороны других приложений на чтение.
    OF_SHARE_DENY_NONE Для открываемого файла не запрещается доступ к файлу ни на чтение, ни на запись.
    OF_PARSE Если указан этот флаг, функция OpenFile не выполняет никаких других действий, кроме заполнения структуры OFSTRUCT.
    OF_DELETE Уничтожение существующего файла.
    OF_VERIFY Если указан этот флаг, то функция OpenFile сравнивает время и дату, записанную в структуре OFSTRUCT, со временем и датой изменений указанного файла. Если обнаружено несоответствие, функция OpenFile возвращает значение HFILE_ERROR.
    OF_SEARCH Операционная система выполняет поиск файла в каталогах даже в том случае, когда текстовая строка, указанная параметром lpszFileName, содержит полный путь к файлу.
    OF_PROMPT Если указан этот флаг, то в случае невозможности найти указанный файл Windows выдаёт диалоговую панель с предложением вставить в дисковод A: дискету с файлом. Это флаг используется очень редко.
    OF_CANCEL Данный флаг указывается вместе с флагом OF_PROMPT. Если он указан, то в описанную выше диалоговую панель будет добавлена кнопка "Cancel" для отмены открытия файла. Приложение при этом получит код ошибки, соответствующий ненайденному файлу, а пользователь – возможность выйти из затруднительного положения, в которое он попадает при отсутствии дискеты с нужным файлом.
    OF_CREATE выполняется создание нового файла. Если указанный файл существует, то он обрезается до нулевой длины.
    OF_EXIST При указании этого флага функция OpenFile вначале открывает файл, а потом сразу же его закрывает. Эта операция может быть использована для того, чтобы убедиться в существовании указанного файла на диске.
    OF_REOPEN Этот флаг используется при повторном открытии файла на основе информации, хранящейся в структуре OFSTRUCT.
    ФУНКЦИЯ _lopen
    OF_READ Файл открывается только для чтения.
    OF_WRITE Файл открывается только для записи.
    OF_READWRITE Файл открывается для чтения и записи.
    OF_SHARE_COMPAT Открытие файла в режиме совместимости. В этом режиме несколько приложений могут одновременно открыть файл, причём все эти приложения должны открывать файл в режиме совместимости.
    OF_SHARE_EXCLUSIVE Файл открывается в монопольном режиме. Для всех других приложений доступ к этому файлу на чтение и запись запрещён.
    OF_SHARE_DENY_WRITE После открытия файла к нему запрещается доступ со стороны других приложений на запись.
    OF_SHARE_DENY_READ После открытия файла к нему запрещается доступ со стороны других приложений на чтение.
    OF_SHARE_DENY_NONE Для открываемого файла не запрещается доступ к файлу ни на чтение, ни на запись.
    ФУНКЦИЯ _lcreat
    0 Нормальный файл, для которого разрешено выполнение операций чтения и записи
    1 Этот файл можно открыть только для чтения
    2 Скрытый файл
    3 Системный файл

    9.1.3. Функции чтения-записи в файл

    Для операций чтения-записи в файл Microsoft Windows применяются следующие функции:

    ФУНКЦИЯ _lread
    СИНТАКСИС: UINT WINAPI _lread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    UINT cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция читает содержимое файла, определённого дескриптором, в текстовый буфер. Размер буфера ограничен 64 Кбайт;
    ОПИСАНИЕ: Функция предназначена для чтения информации из файла в буфер памяти. Через параметр hf функции следует передать идентификатор файла, для которого необходимо сделать операцию чтения. Прочитанные данные будут записаны в буфер hpvBuffer, имеющий размер cbBuffer байт. Этот буфер можно получить динамически, вызвав, например, функцию GlobalAlloc или, что лучше с точки зрения совместимости, LocalAlloc. Размер буфера не должен превышать 65 534 байт.
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, прочитанных из файла. Возвращённое значение может быть меньше затребованного в параметре cbBuffer, если достигнут конец файла. При ошибке функция возвращает значение HFILE_ERROR.
    ПЕРЕНОСИМОСТЬ: MS Windows 3.0 и старше;

    ФУНКЦИЯ _hread
    СИНТАКСИС: long WINAPI _hread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    long cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция читает содержимое файла, определённого дескриптором, в текстовый буфер. Размер буфера ограничен 2 Гбайт;
    ОПИСАНИЕ: Функция предназначена для чтения информации из файла в буфер памяти. Через параметр hf функции следует передать идентификатор файла, для которого необходимо сделать операцию чтения. Прочитанные данные будут записаны в буфер hpvBuffer, имеющий размер cbBuffer байт. Этот буфер можно получить динамически, вызвав функцию GlobalAlloc ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, прочитанных из файла. Возвращённое значение может быть меньше затребованного в параметре cbBuffer, если достигнут конец файла. При ошибке функция возвращает значение HFILE_ERROR.
    ПЕРЕНОСИМОСТЬ: MS Windows 3.1 и старше;

    ФУНКЦИЯ _lwrite
    СИНТАКСИС: UINT WINAPI _hread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    UINT cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция записывает содержимое текстового буфера в файл, определённого дескриптором. Размер буфера ограничен 64 Кбайт;
    ОПИСАНИЕ: Назначение параметров этой функции аналогично назначению параметров функции _lread, Перед вызовом функции _lwrite буфер должен содержать данные, записываемые в файл;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, записанных в файл, или значение HFILE_ERROR при ошибке;
    ПЕРЕНОСИМОСТЬ: MS Windows 3.0 и старше;

    ФУНКЦИЯ _hwrite
    СИНТАКСИС: long WINAPI _hread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    long cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция записывает содержимое текстового буфера в файл, определённого дескриптором. Размер буфера ограничен 2 Гбайт;
    ОПИСАНИЕ: Назначение параметров этой функции аналогично назначению параметров функции _hread, Перед вызовом функции _lwrite буфер должен содержать данные, записываемые в файл;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, записанных в файл, или значение HFILE_ERROR при ошибке;
    ПЕРЕНОСИМОСТЬ: MS Windows 3.1 и старше;

    ФУНКЦИЯ GetDriveType
    СИНТАКСИС: UINT WINAPI GetDriveType( DriveNumber )

    int DriveNumber - определяет номер диска, для которого требуется определить тип и расположение: (0 соответствует устройству A:, 1 - B;, 2 - C: и т.д.)

    НАЗНАЧЕНИЕ: Позволяет определить тип и расположение используемого дискового блочного устройства ввода-вывода;
    ОПИСАНИЕ: Иногда требуется определить тип и расположение используемого блочного устройства ввода-вывода. Для этого необходимо использовать эту функцию;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция может вернуть нуль при ошибке или одно их следующих значений (смотри таблицу 9.2);
    ПЕРЕНОСИМОСТЬ: MS Windows 3.0 и старше;
    Константы функции GetDriveType
    Константа Описание
    ФУНКЦИЯ GetDriveType
    DRIVE_REMOVABLE Сменный диск
    DRIVE_FIXED Несменный диск
    DRIVE_REMOTE Удалённый диск, расположен на другой машине в сети

    9.1.4. Стандартные "диалоги" открытия и сохранения файлов

    Основным способом задания имени файла для его открытия (или сохранения) средствами Windows является не командная строка, а диалоговые окна "Open" (для открытия файла) и "Save As" (для задания имени сохраняемого файла). Эти диалоговые окна вызываются с помощью ниже перечисленных функций:

    ФУНКЦИЯ GetOpenFileName
    ОПРЕДЕЛЕНА В: commdlg.dll (<commdlg.h>)
    СИНТАКСИС: BOOL WINAPI GetOpenFileName( lpofn )

    OPENFILENAME FAR *lpofn - структура данных, определяющая внешний вид диалоговых панелей;

    НАЗНАЧЕНИЕ: Вызов диалогового окна "Open…" для получения полного имени для открытия файла;
    ОПИСАНИЕ: Функция выводит стандартную диалоговую панель для открытия файлов. Параметры отображения считываются и заносятся в структуру OPENFILENAME ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает ненулевое значение, если пользователь сделал выбор файла, и ноль, если он отказался от выбора, нажав кнопку "Cancel" или выбрав пункт "Close" из системного меню диалоговой панели. Нулевое значение возвращается также при возникновении ошибок;
    ПЕРЕНОСИМОСТЬ: Только MS Windows 3.1. На новых системах (Windows 95 и старше) она, возможно, заменена другими инструментами;

    ФУНКЦИЯ GetSaveFileName
    ОПРЕДЕЛЕНА В: commdlg.dll (<commdlg.h>)
    СИНТАКСИС: BOOL WINAPI GetSaveFileName( lpofn )

    OPENFILENAME FAR *lpofn - структура данных, определяющая внешний вид диалоговых панелей;

    НАЗНАЧЕНИЕ: Вызов диалогового окна "Save As…" для получения полного имени для сохранения файла на диске;
    ОПИСАНИЕ: Функция выводит стандартную диалоговую панель для сохранения файлов. Параметры отображения считываются и заносятся в структуру OPENFILENAME ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает ненулевое значение, если пользователь сделал выбор файла, и ноль, если он отказался от выбора, нажав кнопку "Cancel" или выбрав пункт "Close" из системного меню диалоговой панели. Нулевое значение возвращается также при возникновении ошибок;
    ПЕРЕНОСИМОСТЬ: Только MS Windows 3.1. На новых системах (Windows 95 и старше) она, возможно, заменена другими инструментами;

    Описание синтаксиса структуры, описывающей внешний вид и поведение диалоговых окон, смотри в приложение №2 (п. 9.5) к данной лекции.

    9.2. Пример создания "каркаса" приложения средствами WinAPI в C++

    9.2.1. "Низкоуровневое" программирование в операционной системе Microsoft Windows

    Программирование на языке C++ в операционной системе Microsoft Windows условно можно разделить на "высокоуровневое" и "низкоуровневое". К "высокому уровню программирования" на языке C++ можно отнести программирование с использованием библиотеки MFC в Microsoft Visual C++, библиотеки ObjectVision в Borland C/C++ и других, менее распространённых библиотек. При написании этих библиотек учтён весь опыт программирования интерфейсов, поэтому с помощью этих библиотек легко сделать "рабочий шаблон" для своего проекта, и уже потом наполнять его нужными функциями. Это очень удобно.… Однако автор всё-таки советует для создания небольших утилит с ограниченной функциональностью использовать "низкоуровневое" программирование в Windows.

    При программировании на "низком уровне" пользователю приходится напрямую использовать функции API Windows (что в "высокоуровневых" библиотеках делать запрещено) и "вручную заниматься" выделением памяти, созданием/освобождением/закрытием контекста устройств, описывать реакцию приложения на поступившие сообщения о нажатых клавишах, событий от мыши и системных событий. Это всё гораздо сложнее.… Но не стоит расстраиваться. Для создания приложений можно использовать один или несколько предопределённых "шаблонов", которые могут быть созданы для определённых классов задач, и включать в себя все "наиболее важные и наиболее типичные" настройки для узкого круга задач и приложений. Все остальные настройки "наследуются Windows" по-умолчанию. Часть из этих шаблонов, предназначенных для обработки текстов, приведена в данном разделе.

    9.2.2. Функция WinMain

    Основной функцией создаваемого приложения Microsoft Windows является функция WinMain. Эта функция - аналог функции "main" для MS-DOS. Её задача - определить класс окна, создать главное окно приложения и "присоединить к нему" функцию обработки сообщений Windows. В отличие от функции main все входящие в неё параметры обязательны.

    Схематически алгоритм вызова любой функции WinMain можно описать следующим образом:

    int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
  • Описание и инициализация глобальных переменных;
  • Вызов функции InitApp для регистрации приложения;
  • Если инициализация прошла неудачно, то выход с возвращением значения "FALSE" ;
  • Создаётся главное окно приложения;
  • Если окно создать не удалось, то выход с возвращением значения "FALSE" ;
  • Рисуется окно приложения;
  • Запускается цикл обработки системных сообщений;
  • После выхода из цикла ставится оператор выхода из программы, с возвращаемым значением msg.wParam ;
  • Конец функции.
  • Шаблон этой функции, пригодный для создания программ для текстовой обработки данных, представлен в приложениях III и так далее к данной лекции.

    9.2.3. Инициализация приложения

    Для инициализации приложения Microsoft Windows используется функция InitApp. Назначение этой функции - заполнить структуру WNDCLASS и вызвать функцию регистрации класса окна. В случае неуспешной инициализации функция возвращает значение: "FALSE".

    В структуре WNDCLASS заполняются следующие поля:

  • wc.style - один или несколько предопределённых стилей окна;
  • wc.lpfnWndProc - указатель на функцию обработки сообщений WndProc ;
  • wc.cbClsExtra - размер дополнительной области данных для класса окна;
  • wc.cbWndExtra - размер дополнительной области памяти для каждого окна из данного класса;
  • wc.hInstance - идентификатор приложения;
  • wc.hIcon - идентификатор иконки по-умолчанию;
  • wc.hCursor - идентификатор курсора по-умолчанию;
  • wc.hbrBackground - цвет окна по-умолчанию;
  • wc.lpszMenuName - идентификатор меню для данного класса приложений;
  • wc.lpszClassName - имя класса окна (должно совпадать с классом окна для функции WinMain );
  • Пример шаблона для описания "стандартной функции" инициализации данных в программе, обрабатывающей текстовые данные, смотри в приложении III к данной лекции.

    9.2.4. Функция WndProc

    Наконец, рассмотрим функцию WndProc, которая, как нужно особо отметить, не вызывается "явно" из основной функции WinMain, но которая, тем не менее, управляет работой всего приложения Windows. Эта функция представляет собой "описание реакции системы на системные сообщения" операционной системы Microsoft Windows. Вкратце дадим понятие системных сообщений Microsoft Windows.

    "Линейная последовательность вычислений", применяемая в MS-DOS, не годится для программирования многозадачных операционных систем, таких как Windows. Во-первых, ресурсы ЭВМ при многозадачной обработке должны быть эффективно распределены между приложениями, а не предоставляться в "монопольное пользование" отдельной программе. Во-вторых, реализация реакции операционной системы MS-DOS на внешние и внутренние события, такие как прерывания от таймера ("системных часов"), от клавиатуры (на нажатие-отпускание клавиши), от мыши и т.д. далеки от совершенства. Как правило, приложению MS-DOS приходилось ждать, когда операционная система "обработает" эти прерывания. А это приводит к непроизводительному расходу ресурсов. Список неудобств можно продолжить.

    Чтобы "обойти" эти недостатки, уже в конце 80-х - начале 90-х годов XX века корпорацией Microsoft был разработан механизм эффективного использования ресурсов ЭВМ на основе архитектуры x86, полностью совместимый с MS-DOS. Этот механизм был использован сначала в файловой оболочке, а затем и в операционной системе Microsoft Windows. В его реализации используются "сообщения", которые генерируются операционной системой Microsoft Windows, ставятся в очередь на исполнение и затем передаются на обработку приложениям. После обработки сообщения приложением оно возвращает результат обратно операционной системе, на основе которого вновь генерируются сообщения и т.д. Поскольку сообщения генерируются постоянно и для всех приложений, им ничего не надо делать, кроме как "слушать" системную очередь сообщений, "отлавливать" своё сообщение и обрабатывать его. А из-за того, что все сообщения помещаются в одну очередь, не будет "опасений" по-поводу того, что сообщение "потеряется", или того, что сообщения поступят приложению не в той последовательности. И роль "всё слышащего уха" приложения Windows выполняет как раз функция WndProc.

    Синтаксис функции WndProc следующий:

    LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

    где

  • hwnd - идентификатор окна, получающего сообщение;
  • msg - идентификатор сообщения Windows;
  • wParam - первый параметр идентификатора сообщения;
  • lParam - второй параметр идентификатора сообщений.
  • Среди идентификаторов сообщений важнейшими являются следующие идентификаторы:

  • WM_CREATE - сообщение с этим идентификатором передаётся приложению в момент его создания;
  • WM_PAINT - сообщение с этим номером передаётся приложению в момент "отрисовки" его главного окна;
  • WM_COMMAND - сообщение с этим номером передаётся приложению, когда вызывается меню его главного окна (например, пользователь выбрал один из пунктов системного меню);
  • WM_DESTROY - сообщение с этим номером передаётся системе, когда необходимо "уничтожение" окна Windows;
  • Для описания реакции на сообщение Windows алгоритм функции WndProc пишется следующим образом:

  • После инициализации "внутренних переменных" программы реализуется конструкция "множественного выбора" значений идентификатора msg ;
  • В зависимости от его значения пишется "обработчик" этого сообщения. Им может быть как допустимая функция C/C++, функция API Windows, так и оператор "множественного выбора" по значению первого и второго параметра сообщения;
  • Оператор "множественного выбора" значений идентификатора msg должен обязательно содержать конструкцию "default". Это означает, что все сообщения, передаваемые операционной системой указанному окну, обработчик которых в программе отсутствует, должны обрабатываться операционной системой по-умолчанию. Эта конструкция обязательно должна иметь вид:
    default:
    	return DefWindowProc(hwnd, msg, wParam, lParam);
  • Примечание. Фактически, следуя формулировкам объектно-ориентированного программирования, сообщение "WM_CREATE" является конструктором приложения Windows, сообщение "WM_DESTROY" - деструктор приложения, а все остальные сообщения являются как бы "методами" этого приложения.

    Вводя и обрабатывая всё новые сообщения Microsoft Windows, мы можем наращивать функциональность операционной системы, независимо друг от друга и от "внешнего окружения" приложения Windows.

    9.2.5. Пример "стандартного каркаса" для приложения Microsoft Windows

    Пример "стандартного каркаса" приложения Microsoft Windows, разработанный для компиляторов Borland C/C++ версий от 3.1 до 5.5, представлен в приложении № III к данной лекции. В приложении № IV представлен пример программы для вывода текстовых строк в окно Windows. В приложениях №№ V и VI представлены те же программы, переписанные для системы Microsoft Visual Studio .Net 2003. Эти программы разработаны для 32-х битного режима Microsoft Windows и рационально используют ресурсы новых ЭВМ на основе технологий Intel и AMD.

    9.3. Резюме

    На этой лекции Вы познакомились с описанием функций ввода-вывода данных при помощи функций WinAPI, а также с "каркасом" для построения собственных приложений средствами WinAPI. Конечно же, Вы пока не умеете работать с контекстом отображения в Windows, метриками текста и т.д., необходимых для программирования на Си в операционных системах Microsoft Windows. Но начало положено…

    9.4. Приложение № I. Описание функций создания и открытия файлов

    typedef struct tagOFSTRUCT
    {
    	BYTE	cBytes;
    	BYTE	fFixedDisk;
    	UINT	nErrCode;
    	BYTE	reserved[4];
    	char	szPathName[128];
    } OFSTRUCT;

    Поле cBytes содержит размер самой структуры OFSTRUCT в байтах.

    С помощью поля fFixedDisk приложение может определить, находится ли открытый файл на жёстком диске, на флоппи-диске или другом съёмном носителе. Если содержимое этого поля отлично от нуля, то файл находится на жёстком диске.

    Если при открытии файла произошла ошибка, в поле nErrCode записывается код ошибки. Возможные значения для кода ошибки приведены в приложении №I к книге [37].

    Поле reserved зарезервировано, и не должно использоваться.

    В поле szPathName находится полный путь к файлу в кодировке OEM.

    9.5. Приложение № II. Основные опции стандартных диалогов GetOpenFileName и GetSaveFileName

    typedef struct tagOFN
    {
    	DWORD	lStructSize;
    	HWND  	hwndOwner;
    	HINSTANCE	hInstance;
    	LPCSTR	lpstrFilter;
    	LPSTR  	lpstrCustomFilter;
    	DWORD	nMaxCustFilter;
    	DWORD 	nFilterIndex;
    	LPSTR  	lpstrFile;
    	DWORD  	nMaxFile;
    	LPSTR  	lpstrFileTitle;
    	DWORD 	nMaxFileTitle;
    	LPCSTR	lpstrInitialDir;
    	LPCSTR	lpstrTitle;
    	DWORD 	Flags;
    	UINT      	nFileOffset;
    	UINT     	nFileExtension
    	LPCSTR   	lpstrDefExt;
    	LPARAM	lCustData;
    	UINT      	(CALLBACK *lpfnHook) (HWND, UINT, WPARAM, LPARAM);
    	LPCSTR 	lpTemplateName;
    } OPENFILENAME;

    В таблице 9.3 представлено назначение полей данной структуры. В таблице 9.4 представлено описание и расшифровка режимов вывода файлов, записанных в переменную Flags.

    Описание полей структуры OPENFILENAME
    Структура: OPENFILENAME
    Имя поля Назначение поля структуры
    lStructSize Перед вызовом функций, использующих эту структуру, в это поле должен быть занесён размер структуры в байтах.
    hwndOwner Поле должно содержать идентификатор окна, создающего диалоговую панель. Можно указать значение NULL, при этом диалоговое окно не будет иметь окна-владельца, но в этом случае будет нельзя использовать флаг OFN_SHOWHELP.
    hInstance Поле hInstance используется перед вызовом функции для идентификации блока памяти, содержащего шаблон диалоговой панели. Содержимое поля игнорируется в том случае, если не указан флаг OFN_ENABLETEMPLATE или OFN_ENABLETEMPLATEHANDLE.
    lpstrFilter В поле должен быть указан адрес текстовой строки, задающий фильтр для выбора имён файлов (шаблоны имён файлов). Фильтр должен состоять из одной или нескольких расположенных непосредственно друг за другом пар строк, закрытых двоичным нулём. Последняя строка должна иметь на конце два двоичных нуля. Первая строка в паре строк описывает название фильтра (например, "Text Files" ), а во второй строке из пары строк через знак ";" перечисляются возможные шаблоны для имён файлов.
    lpsrCustomFilter В поле должен быть указан адрес текстовой строки, задающий фильтр для выбора имён файлов (шаблон для выбора файлов). Фильтр должен состоять из одной расположенных непосредственно друг за другом пары строк, закрытых двоичным нулём. Последняя строка должна иметь на конце два двоичных нуля. Первая строка в паре описывает название фильтра (например, "Text Files" ), а во второй строке пары через знак ";" перечисляются возможные шаблоны для имён файлов. Этот фильтр используется только в том случае, если в поле lpstrFilter содержится NULL.
    nMaxCustFilter Определяет размер буфера в байтах, указанного в поле lpstrCustomFile. Размер этого буфера должен быть не меньше 40 байт.
    nFilterIndex Поле определяет номер пары строк, используемых для фильтра, указанного в поле lpstrFilter или lpstrCustomFilter.
    lpstrFile Поле должно содержать адрес текстовой строки, в которую будет записан полный путь к выбранному файлу. Если перед вызовом функций, использующих эту структуру, заполнить её значением, содержащем путь к файлу, этот путь будет выбран по-умолчанию при открытии диалоговых панелей "Open…" или "Save As…" ;
    nMaxFile Поле должно содержать размер в байтах буфера, расположенного по адресу, указанного в поле lpstrFile. Размер этого буфера должен быть достаточным для записи полного пути к файлу. FAT16 запрещает использовать для указания пути строку более 128 символов. VFAT и другие файловые системы имеют большее предельное значение "путевого имени".
    lpstrFileTitle В это поле необходимо записать адрес буфера, в который после выбора будет записано имя файла с расширением, но без пути к файлу. Это поле должно быть использовано приложением для отображения имени выбранного файла.
    nMaxFileTitle Поле должно содержать размер указанного буфера (13 для файлов MS-DOS и Windows 16, и до 255 для Windows 32/64).
    lpstrInitialDir Поле позволяет указать начальный каталог, который будет выбран для поиска файла сразу после отображения диалоговой панели: "Open…". Если нужно просмотреть файл в текущем каталоге, в это поле необходимо записать значение: NULL.
    lpstrTitle В этом поле задаётся "нестандартный" заголовок панели, появляющийся при вызове функции. Если в этом поле содержится значение "NULL", используются заголовки по-умолчанию: "Open…" и "Save As…".
    Flags Данное поле позволяет задать различные режимы выбора файла, влияющих на внешний вид диалоговых панелей. Описание этих флагов смотри в таблице D.4.???.
    nFileOffset После возврата из функции это поле будет содержать смещение первого символа имени файла относительно начала буфера lpstrFile. Это поможет Вам "разделить" имя файла и путь к нему.
    nFileExtension После возврата из функции это поле будет содержать смещение первого символа расширения имени файла относительно начала буфера lpstrFile.
    lpstrDefExt Поле указывает на буфер, который содержит расширение имени файла, используемого по-умолчанию. Это расширение добавляется к имени выбранного файла, если при выборе расширения имя указано не было.
    lCustData Значение, передаваемой функции фильтра через параметр lParam.
    (CALLBACK *lpfnHook)(HWND,UINT, WPARAM, LPARAM ) Указатель на функцию фильтра, обрабатывающую сообщения для диалоговой панели. Функция будет вызываться только в том случае, если указан флаг OFN_ENABLEHOOK. Если фильтр не обрабатывал сообщение, он должен вернуть нулевое значение. Если же он вернёт значение, отличное от нуля, стандартная функция диалога не будет обрабатывать сообщение, которое уже обработано функцией фильтра.
    lpTemplateName Идентификатор ресурса, содержащего шаблон диалоговой панели, используемого вместо шаблона, имеющегося в библиотеке commdlg.dll. Для ссылки на ресурс можно использовать макрокоманду MAKEINTRESORCE. Для использования альтернативного шаблона в поле Flags следует установить флаг OFN_ENABLETEMPLATE.
    Описание флагов структуры OPENFILENAME
    Флаги структуры: OPENFILENAME
    Флаг Описание
    OFN_ALLOWMULTISELECT Разрешается выбор нескольких файлов одновременно. Если указан этот флаг, после выбора поле lpstrFile будет указывать на буфер, заполненный именами выбранных файлов (или путями к выбранным файлам), разделёнными пробелом.
    OFN_CREATEPROMPT При использовании этого флага, если указанный файл не существует, создаётся диалоговая панель, в которой предлагается создать файл. Этот флаг устанавливается автоматически при использовании флагов OFN_PATHMUSTEXIST и OFN_FILEMUSTEXIST.
    OFN_ENABLEHOOK Разрешается использовать функцию фильтра, адрес которой указан в поле lpfnHook.
    OFN_ENABLETEMPLATE Если указан этот флаг, для создания диалоговой панели Windows будет использовать шаблон, определяемыйй содержимым полей hInstance и lpTemplateName.
    OFN_ENABLETEMPLATEHANDLE При использоваении этого флага поле hInstance используется для идентификации блока памяти, содержащего предварительно загруженный шаблон диалоговой панели. В этом случае содержимое поля lpTemplateName игнорируется.
    OFN_EXTENSIONDIFFERENT Устанавливается после возвращения из функции и указывает, что расширение файла отличается от заданного в поле lpstrDefExt. Этот флаг не устанавливается, если перед вызовом функции в поле lpstrDefExt было записано значение NULL, или если файл не имеет расширения имени.
    OFN_FILEMUSTEXIST Можно выбирать только имена файлов, которые существуют. Если в поле "File Name" ("Имя файла") диалоговойц панели набрать имя несуществующего файла, на экране появится диалоговая панель с предупреждающим сообщением.
    OFN_HIDEREADONLY Убрать переключатель "Read Only" ("Только чтение").
    OFN_NOCHANGEDIR Для выбора используется каталог, который был текущем при вызове функции.
    OFN_NOREADONLYRETURN Выбранные файлы не могут иметь атрибут "только чтение" или располагаться в защищённом от записи каталоге.
    OFN_NOTESTFILECREATE Перед завершением работы диалоговой панели создание файла не выполняется. Не выполняются и проверки на переполнение диска, защиту записи или наличия доступа в сети.
    OFN_NOVALIDATE В возвращаемом имени файла могут присутствовать неразрешённые символы.
    OFN_OVERWRITEPROMPT Используется для диалоговой панели "Save as…". Если выбранный файл существует, на экран выводится диалоговая панель с предупреждением.
    OFN_PATHMUSTEXIST Можно вводить только существующие пути к файлам.
    OFN_READONLY После вызова функции переключатель "Read Only" ("Только чтение") будет находиться во включённом состоянии.
    OFN_SHAREWARE Флаг устанавливается после возвращения из функции и указывает, что при вызове функции OpenFile произошла ошибка при совместном доступе к файлу в сети.
    OFN_SHOWHELP Если указан этот флаг, то в диалоговой панели будет создана кнопка "Help" ("Справка"). Если указан это флаг, поле hwndOwner не должно содержать значения NULL.

    9.6. Приложение № III

    /* Файл INIT.CPP */
    /**********************************************************
     * Каркас приложений Windows,
     * на основе которого можно строить более
     * сложные приложения MS WINDOWS.
     * Каркас использует правила для написани
     * программ на платформе Turbo C++ 3.1
     * 16-ти разрядных версий Windows.
     *
     * Более подробную информацию о "низкоуровневом" написании
     * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
     * Фролов, "Операционная система Microsoft Windows 3.1.
     * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
     * книги этих авторов.
    **********************************************************/
    #define STRICT
    #include <windows.h>
    #include <mem.h>
    // Прототипы функций
    // Первая функция - для инициализации
    // приложения Windows, вторая функция -
    // для обработки системных сообщений.
    BOOL InitApp(HINSTANCE);
    LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
    /* Значения класса и заголовка впоследствии нужно заменить */
    // Имя класса окна
    char const szClassName[]   = "WindowAppClass";
    // Заголовок окна
    char const szWindowTitle[] = "Window Application";
    // =====================================
    /***************************************
     * Функция WinMain
     * Получает управление при запуске
     * приложени
    ***************************************/
    // =====================================
    #pragma argsused
    int PASCAL
    WinMain(HINSTANCE hInstance,     // идентификатор текущей
    				 // копии приложени
    	HINSTANCE hPrevInstance, // идентификатор предыдущей
    				 // копии приложени
    	LPSTR     lpszCmdLine,   // указатель на командную строку
    	int       nCmdShow)      // способ отображения главного
    	                         // окна приложени
    {
      MSG  msg;   // структура для работы с сообщениями
      HWND hwnd;  // идентификатор главного окна приложени
      // Проверяем, не запускалось ли это приложение ранее
    //  if(!hPrevInstance)
    //  {
        // Если не запускалось, вызываем функцию InitApp
        // для инициализации приложения.
    /*****************************************************
     * Вызываем функцию InitApp
     * для инициализации приложения.
     * Если инициализацию выполнить не удалось,
     * завершаем приложение
    *****************************************************/
        if(!InitApp(hInstance))
          return FALSE;
    //  }
    /****************************************************
     * После успешной инициализации приложения создаём
     * главное окно приложени
    ****************************************************/
      hwnd = CreateWindow(
        szClassName,         // имя класса окна (см. Выше )
        szWindowTitle,       // заголовок окна (см. Выше)
        WS_OVERLAPPEDWINDOW, // стиль окна
    /****************************************************
     * В данном случае это перекрывающееся окно, но эту
     * опцию можно изменить для других типов окон
    *****************************************************/
        CW_USEDEFAULT,       // задаём размеры и расположение
        CW_USEDEFAULT,       // окна, принятые по умолчанию
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        0,                   // идентификатор родительского окна
    			// Для главного окна его менять нельз
        0,                   // идентификатор меню
    /**********************************************************
     * В случае, если у окна необходимо создать меню, вместо
     * нуля сюда вставляется идентификатор меню (тип HMENU),
     * созданный с помощью функции LoadMenu.
     *
     * Если меню подключается как ресурс приложения в функции
     * InitApp, в этом поле также нужно оставить 0
    **********************************************************/
        hInstance,           // идентификатор приложени
        NULL);               // указатель на дополнительные
    			 // параметры
    /**********************************************************
     * Далее код лучше не менять *
    **********************************************************/
      // Если создать окно не удалось, завершаем приложение
      if(!hwnd)
        return FALSE;
    /**********************************************************
     * В случае если Вам не нужно рисовать главное окно
     * приложения (например, Вы пишете программу мастер)
     * две нижеперечисленные функции:  ShowWindow и
     * UpdateWindow, указывать не надо
    **********************************************************/
      // Рисуем окно. Для этого после функции ShowWindow, рисующей
      // окно, вызываем функцию UpdateWindows, посылающую
      // сообщение WM_PAINT в функцию окна
      ShowWindow(hwnd, nCmdShow);
      UpdateWindow(hwnd);
    /**********************************************************
     * Далее до конца функции код лучше не менять *
    **********************************************************/
      // Запускаем цикл обработки сообщений
      while(GetMessage(msg, 0, 0, 0))
      {
        DispatchMessage(msg);
      }
      // Возвращаем значение WParam, переданное
      // в качестве параметра функции PostQuitMessage
      // в процессе инициирования завершения работы
      // приложения из функции окна.
      // Затем завершаем работу приложени
      return msg.wParam;
    }
    /* Конец функции WinMain *|
    // =====================================
    /**********************************************************
     * Функция InitApp
     * Вызывается из функции WinMain дл
     * инициализации приложения.
     * Выполняет регистрацию класса окна
    **********************************************************/
    // =====================================
    BOOL InitApp(HINSTANCE hInstance)
    {
      ATOM aWndClass; // атом для кода возврата
      WNDCLASS wc;    // структура для регистрации
                      // класса окна
      // Записываем нулевые значения во все поля структуры
      memset(wc, 0, sizeof(wc));
      // Стиль окна
    /**********************************************************
     * Поле style задаёт стиль класса окна и задаётся в виде
     * констант, описанных в файле <windows.h>. Описани
     * констант стилей начинается с префикса CS_. Стиль окна
     * задаёт реакцию окна на изменения его размера, на
     * выполнение в окне операции двойного щелчка мышью, а
     * также задаёт другие характеристики окна.
     * Если в главное окно предполагается вывод информации,
     * необходимо указать, по крайней мере:
     *   wc.style = CS_HREDRAW | CS_REDRAW;
     * в противном случае записать:
     *   wc.style = 0;
    **********************************************************/
      wc.style = 0;
      // Указатель на функцию окна, обрабатывающую
      // сообщения, предназначенные для всех окон,
      // созданных на основе данного класса
      /* Желательно не менять! */
      wc.lpfnWndProc = (WNDPROC) WndProc;
      // Размер дополнительной области данных,
      // зарезервированной в описании класса окна
      /* Желательно не менять! */
      wc.cbClsExtra = 0;
      // Размер дополнительной области данных,
      // зарезервированной для каждого окна,
      // созданного на основе данного класса
      /* Желательно не менять! */
      wc.cbWndExtra = 0;
      // Идентификатор приложения, которое
      // создало данный класс
      /* Желательно не менять! */
      wc.hInstance = hInstance;
      // Идентификатор пиктограммы, используемой
      // для окно данного класса
    /**********************************************************
     * Иконки создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadIcon.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется иконка (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * пиктограммы. Если Вы не уверены, то этот параметр
     * менять не нужно.
    **********************************************************/
      wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      // Идентификатор курсора, используемого
      // для окна данного класса
    /**********************************************************
     * Курсоры создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadCursor.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется курсор (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * курсора. Если Вы не уверены, то этот параметр менять
     * не нужно (оставляем стандартный курсор в виде стрелки).
    **********************************************************/
      wc.hCursor = LoadCursor(NULL, IDC_ARROW);
      // Цвет фона окна
      /* Желательно не менять, оставить системный цвет */
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
      // Идентификатор меню
    /**********************************************************
     * В случае если у окна необходимо создать меню, в это
     * поле нужно указать адрес текстовой строки, содержащей
     * имя шаблона меню в файле ресурсов. Все перекрывающиеся и
     * временные окна, созданные на базе этого класса, будут
     * иметь меню, определённое данным шаблоном. Пример:
     *  wc.lpszMenuName = "APP_MENU";
     * Если для идентификации шаблона использовать целые
     * числа, необходимо использовать макрокоманду
     * MAKEINTRESOURCE. Например, в файле описания ресурсов и в
     * файле исходного приложения определена константа:
     * #define APP_MENU 123
     * В этом случае строка примет вид:
     *  wc.lpszMenuName = MAKEINTRESOURCE( APP_MENU );
     * Если в окне меню не нужно, оставьте параметр без
     * изменения.
    **********************************************************/
      wc.lpszMenuName = (LPSTR)NULL;
      /* Желательно не менять остальные операторы до конца
         функции */
      // Имя, которое присваивается создаваемому
      // классу и используется при создании
      // окон данного класса
      wc.lpszClassName = (LPSTR)szClassName;
      // Регистрация класса
      aWndClass = RegisterClass(wc);
      // Возвращаем результат регистрации класса
      return (aWndClass != 0);
    }
    /* Файл WinProc.cpp */
    #define STRICT
    #include <windows.h>
    #include <mem.h>
    // =====================================
    /**********************************************************
     * Функция WndProc
     * НЕ ВЫЗЫВАЕТСЯ ни из одной функции приложения.
     * Эту функцию вызывает Windows в процессе
     * обработки сообщений. Для этого адрес функции WndProc
     * указывается при регистрации класса окна.
     * Функция выполняет обработку сообщений главного
     * окна приложени
     *
     * Более подробную информацию о "низкоуровневом" написании
     * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
     * Фролов, "Операционная система Microsoft Windows 3.1.
     * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
     * книги этих авторов.
    **********************************************************/
    // =====================================
    LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      // Выполняем обработку сообщений. Идентификатор
      // сообщения передаётся через параметр msg
      switch (msg)
      {
    /**********************************************************
     * Это сообщение приходит, когда создаётся окно приложени
     * Здесь нужно вызвать контекст экрана, сохранить в
     * переменных его метрики и освободить его.
    **********************************************************/
    
        case WM_CREATE:
        {
          // Получаем контекст отображения,
          // необходимый для определения метрик.
    	return 0;
        }
    /**********************************************************
     * Это сообщение приходит, когда "рисуется" окно приложения.
     * Здесь нужно вызвать контекст экрана, вывести необходимые
     * данные на экран, и освободить контекст.
    **********************************************************/
    
        case WM_PAINT:
        {
          // Инициализируем текущую позицию вывода текста
          // Получаем контекст экрана
          // Освобождаем контекст экрана
             return 0;
        }
    /*********************************************************
        // Это сообщение приходит, когда вы поместили курсор
        // мыши в область главного окна приложения и нажали
        // левую клавишу мыши
        case WM_LBUTTONDOWN:
          {
    	return 0;
          }
        // Это сообщение приходит, когда вы поместили курсор
        // мыши в область главного окна приложения и нажали
        // правую клавишу мыши
        case WM_RBUTTONDOWN:
          {
    	return 0;
          }
    **********************************************************/
    /**********************************************************
     * Это сообщение приходит, когда вы завершаете
     * работу приложения стандартным дл
     * Windows способом
    **********************************************************/
        case WM_DESTROY:
        {
          // Инициируем завершение работы приложения,
          // помещая в очередь приложения сообщение
          // WM_QUIT. Это приведёт к завершению
          // цикла обработки сообщений в функции WinMain
          PostQuitMessage(0);
          return 0;
        }
      }
      // Все сообщения, которые не обрабатываются нашей
      // функцией окна, ДОЛЖНЫ передаваться функции
      // DefWindowProc
      return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    /* Файл WINDOW.DEF */
    ; =============================
    ; Файл определения модул
    ; =============================
    ; Имя приложени
    NAME WINDOW
    ; Описание приложени
    DESCRIPTION 'Приложение WINDOW, (C) 1994, Frolov A.V.'
    ; Определение типа загрузочного модуля как
    ; приложения Windows
    EXETYPE windows
    ; Программа, которая будет записана в начало файла
    ; приложения. Эта программа получит управление
    ; при попытке запуска приложения в среде MS-DOS
    STUB 'winstub.exe'
    ; Размер стека в байтах
    STACKSIZE 5120
    ; Размер локальной кучи памяти приложения в байтах
    HEAPSIZE 1024
    ; Атрибуты сегмента кода
    CODE preload moveable discardable
    ; Атрибуты сегмента данных
    DATA preload moveable multiple

    9.7. Приложение № IV

    /* Файл INIT.CPP */
    /**********************************************************
     * Каркас приложений Windows,
     * на основе которого можно строить более
     * сложные приложения MS WINDOWS.
     * Каркас использует правила для написани
     * программ на платформе Turbo C++ 3.1
     * 16-ти разрядных версий Windows.
     *
     * Более подробную информацию о "низкоуровневом" написании
     * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
     * Фролов, "Операционная система Microsoft Windows 3.1.
     * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
     * книги этих авторов.
    **********************************************************/
    #define STRICT
    #include <windows.h>
    #include <mem.h>
    // Прототипы функций
    // Первая функция - для инициализации
    // приложения Windows, вторая функция -
    // для обработки системных сообщений.
    BOOL InitApp(HINSTANCE);
    LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
    /* Значения класса и заголовка впоследствии нужно заменить */
    // Имя класса окна
    char const szClassName[]   = "WindowAppClass";
    // Заголовок окна
    char const szWindowTitle[] = "Window Application";
    // =====================================
    /***************************************
     * Функция WinMain
     * Получает управление при запуске
     * приложени
    ***************************************/
    // =====================================
    #pragma argsused
    int PASCAL
    WinMain(HINSTANCE hInstance,     // идентификатор текущей
    				 // копии приложени
    	HINSTANCE hPrevInstance, // идентификатор предыдущей
    				 // копии приложени
    	LPSTR     lpszCmdLine,   // указатель на командную строку
    	int       nCmdShow)      // способ отображения главного
    	                         // окна приложени
    {
      MSG  msg;   // структура для работы с сообщениями
      HWND hwnd;  // идентификатор главного окна приложени
      // Проверяем, не запускалось ли это приложение ранее
    //  if(!hPrevInstance)
    //  {
        // Если не запускалось, вызываем функцию InitApp
        // для инициализации приложения.
    /*****************************************************
     * Вызываем функцию InitApp
     * для инициализации приложения.
     * Если инициализацию выполнить не удалось,
     * завершаем приложение
    *****************************************************/
        if(!InitApp(hInstance))
          return FALSE;
    //  }
    /****************************************************
     * После успешной инициализации приложения создаём
     * главное окно приложени
    ****************************************************/
      hwnd = CreateWindow(
        szClassName,         // имя класса окна (см. Выше )
        szWindowTitle,       // заголовок окна (см. Выше)
        WS_OVERLAPPEDWINDOW, // стиль окна
    /****************************************************
     * В данном случае это перекрывающееся окно, но эту
     * опцию можно изменить для других типов окон
    *****************************************************/
        CW_USEDEFAULT,       // задаём размеры и расположение
        CW_USEDEFAULT,       // окна, принятые по умолчанию
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        0,                   // идентификатор родительского окна
    			// Для главного окна его менять нельз
        0,                   // идентификатор меню
    /**********************************************************
     * В случае если у окна необходимо создать меню, вместо
     * нуля сюда вставляется идентификатор меню (тип HMENU),
     * созданный с помощью функции LoadMenu.
     *
     * Если меню подключается как ресурс приложения в функции
     * InitApp, в этом поле также нужно оставить 0
    **********************************************************/
        hInstance,           // идентификатор приложени
        NULL);               // указатель на дополнительные
    			 // параметры
    /**********************************************************
     * Далее код лучше не менять *
    **********************************************************/
      // Если создать окно не удалось, завершаем приложение
      if(!hwnd)
        return FALSE;
    /**********************************************************
     * В случае если Вам не нужно рисовать главное окно
     * приложения (например, Вы пишете программу-мастер)
     * две нижеперечисленные функции:  ShowWindow и
     * UpdateWindow, указывать не надо
    **********************************************************/
      // Рисуем окно. Для этого после функции ShowWindow, рисующей
      // окно, вызываем функцию UpdateWindows, посылающую
      // сообщение WM_PAINT в функцию окна
      ShowWindow(hwnd, nCmdShow);
      UpdateWindow(hwnd);
    /**********************************************************
     * Далее до конца функции код лучше не менять *
    **********************************************************/
      // Запускаем цикл обработки сообщений
      while(GetMessage(msg, 0, 0, 0))
      {
        DispatchMessage(msg);
      }
      // Возвращаем значение WParam, переданное
      // в качестве параметра функции PostQuitMessage
      // в процессе инициирования завершения работы
      // приложения из функции окна.
      // Затем завершаем работу приложени
      return msg.wParam;
    }
    /* Конец функции WinMain *|
    // =====================================
    /**********************************************************
     * Функция InitApp
     * Вызывается из функции WinMain дл
     * инициализации приложения.
     * Выполняет регистрацию класса окна
    **********************************************************/
    // =====================================
    BOOL InitApp(HINSTANCE hInstance)
    {
      ATOM aWndClass; // атом для кода возврата
      WNDCLASS wc;    // структура для регистрации
                      // класса окна
      // Записываем нулевые значения во все поля структуры
      memset(wc, 0, sizeof(wc));
      // Стиль окна
    /**********************************************************
     * Поле style задаёт стиль класса окна и задаётся в виде
     * констант, описанных в файле <windows.h>. Описани
     * констант стилей начинается с префикса CS_. Стиль окна
     * задаёт реакцию окна на изменения его размера, на
     * выполнения в окне операции двойного щелчка мышью, а
     * также задаёт другие характеристики окна.
     * Если в главное окно предполагается вывод информации,
     * необходимо указать, по крайней мере:
     *   wc.style = CS_HREDRAW | CS_REDRAW;
     * в противном случае записать:
     *   wc.style = 0;
    **********************************************************/
      wc.style = 0;
      // Указатель на функцию окна, обрабатывающую
      // сообщения, предназначенные для всех окон,
      // созданных на основе данного класса
      /* Желательно не менять! */
      wc.lpfnWndProc = (WNDPROC) WndProc;
      // Размер дополнительной области данных,
      // зарезервированной в описании класса окна
      /* Желательно не менять! */
      wc.cbClsExtra = 0;
      // Размер дополнительной области данных,
      // зарезервированной для каждого окна,
      // созданного на основе данного класса
      /* Желательно не менять! */
      wc.cbWndExtra = 0;
      // Идентификатор приложения, которое
      // создало данный класс
      /* Желательно не менять! */
      wc.hInstance = hInstance;
      // Идентификатор пиктограммы, используемой
      // для окно данного класса
    /**********************************************************
     * Иконки создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadIcon.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется иконка (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * пиктограммы. Если Вы не уверены, то этот параметр
     * менять не нужно.
    **********************************************************/
      wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      // Идентификатор курсора, используемого
      // для окно данного класса
    /**********************************************************
     * Курсоры создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadCursor.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется курсор (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * курсора. Если Вы не уверены, то этот параметр менять
     * не нужно (оставляем стандартный курсор в виде стрелки).
    **********************************************************/
      wc.hCursor = LoadCursor(NULL, IDC_ARROW);
      // Цвет фона окна
      /* Желательно не менять, оставить системный цвет */
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
      // Идентификатор меню
    /**********************************************************
     * В случае если у окна необходимо создать меню, в это
     * поле нужно указать адрес текстовой строки, содержащей
     * имя шаблона меню в файле ресурсов. Все перекрывающиеся и
     * временные окна, созданные на базе этого класса, будут
     * иметь меню, определённое данным шаблоном. Пример:
     *  wc.lpszMenuName = "APP_MENU";
     * Если для идентификации шаблона использовать целые
     * числа, необходимо использовать макрокоманду
     * MAKEINTRESOURCE. Например, в файле описания ресурсов и в
     * файле исходного приложения определена константа:
     * #define APP_MENU 123
     * В этом случае строка примет вид:
     *  wc.lpszMenuName = MAKEINTRESOURCE( APP_MENU );
     * Если в окне меню не нужно, оставьте параметр без
     * изменения.
    **********************************************************/
      wc.lpszMenuName = (LPSTR)NULL;
      /* Желательно не менять остальные операторы до конца
         функции */
      // Имя, которое присваивается создаваемому
      // классу и используется при создании
      // окон данного класса
      wc.lpszClassName = (LPSTR)szClassName;
      // Регистрация класса
      aWndClass = RegisterClass(wc);
      // Возвращаем результат регистрации класса
      return (aWndClass != 0);
    }
    /* Файл TEXTW.CPP */
    /**********************************************************
     * Функция WndProc
    **********************************************************/
    #define STRICT
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    // Задание максимальной длины символьного буфера строки
    // для вывода в окно
    #ifndef SCREEN_BUFSIZE
    #define SCREEN_BUFSIZE	80
    #endif
    // Прототип функции для печати строки символов
    void Print(HDC, char *, int);
    void PrintLn(void);
    /**********************************************************
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
    **********************************************************/
    static int cxChar, cyChar;
    static int cxCurrentPosition;
    static int cyCurrentPosition;
    LRESULT CALLBACK _export
    WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      HDC hdc;              // индекс контекста устройства
      PAINTSTRUCT ps;       // структура для рисовани
      static TEXTMETRIC tm; // структура для записи метрик
                            // шрифта
      switch (msg)
      {
        case WM_CREATE:
        {
          // Получаем контекст отображения,
          // необходимый для определения метрик шрифта
          hdc = GetDC(hwnd);
          // Заполняем структуру информацией
          // о метрике шрифта, выбранного в
          // контекст отображени
          GetTextMetrics(hdc, tm);
          // Запоминаем значение ширины дл
          // самого широкого символа
          cxChar = tm.tmMaxCharWidth;
          // Запоминаем значение высоты букв с
          // учётом межстрочного интервала
          cyChar = tm.tmHeight + tm.tmExternalLeading;
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
          // Освобождаем контекст
          ReleaseDC(hwnd, hdc);
          return 0;
        }
        case WM_PAINT:
        {
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
          hdc = BeginPaint(hwnd, ps);
          // Выводим последовательно строки:
          Print(hdc, "Первая строка", 0); PrintLn();
          Print(hdc, "Вторая строка", 0); PrintLn();
          Print(hdc, "Третья строка( смещённая )", 10); PrintLn();
          EndPaint(hwnd, ps);
          return 0;
        }
        case WM_DESTROY:
        {
          PostQuitMessage(0);
          return 0;
        }
      }
      return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    /**********************************************************
     * Функция Print
     * Функция предназначена для вывода текста
     * в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * HDC hdc -- индекс контекста устройства;
     * char *str -- указатель на выводимую строку;
     * int iOFFSET -- смещение горизонтальной позиции
     * вывода текста в окно, указанное в символах;
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void Print(HDC hdc, char *str, int iOFFSET )
    {
      char buf[SCREEN_BUFSIZE];
      int i;
    /* Проверяем смещение на неравенство единице
       и корректируем его */
      if( iOFFSET < 0 ) iOFFSET = 0;
      // Подготавливаем в рабочем буфере
      i = strlen(str);
      // Проверка, что строка умещается в буфере
      if( i < SCREEN_BUFSIZE - 1 )
      // и выводим строку в зависимости от проверки
    	sprintf(buf, "%s", str);
      else
    	sprintf(buf, "%.*s", SCREEN_BUFSIZE-1, str);
      // Выводим текст в окно, начиная с текущей позиции
      // вывода текста + смещение в максимальном
      // количестве символов
      TextOut(hdc,
        cxCurrentPosition + iOFFSET * cxChar,
        cyCurrentPosition,
        buf, i);
    }
    /**********************************************************
     * Функция PrintLn
     * Функция предназначена для перевода на новую строку
     * при выводе в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * Не имеет.
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void PrintLn( void )
    {
      // Увеличиваем текущую позицию по
      // вертикали на высоту символа
      cyCurrentPosition += cyChar;
    }
    /* Файл TEXTWN.DEF*/
    ; =============================
    ; Файл определения модул
    ; =============================
    ; Имя приложени
    NAME TEXTWIN
    ; Описание приложени
    DESCRIPTION 'Приложение WINDOW, (C) 1994, Frolov A.V.'
    ; Определение типа загрузочного модуля как
    ; приложения Windows
    EXETYPE windows
    ; Программа, которая будет записана в начало файла
    ; приложения. Эта программа получит управление
    ; при попытке запуска приложения в среде MS-DOS
    STUB 'winstub.exe'
    ; Размер стека в байтах
    STACKSIZE 5120
    ; Размер локальной кучи памяти приложения в байтах
    HEAPSIZE 1024
    ; Атрибуты сегмента кода
    CODE preload moveable discardable
    ; Атрибуты сегмента данных
    DATA preload moveable multiple

    9.8. Приложение № V

    Примечание: Для создания данного приложения средствами Microsoft Visual Studio 2008 вначале создайте "пустой проект", а затем заполните его этими файлами.

    /* stdafx.cpp*/
    // stdafx.cpp : исходный файл, который включает в себя стандартные заголовочные файлы.
    // WINDOW.pch будет заголовком предпроцессора
    // stdafx.obj будет содержать информацию предварительной компиляции
    #include "stdafx.h"
    // Поместите сюда всю дополнительную информацию, которая Вам нужна,
    // в этот файл, а ни где-либо ещё.
    /* stdafx.h */
    // stdafx.h : заголовочный файл, со стандартными системными заголовочными файлами
    // или специфичные для всего проекта часто используемые заголовочные файлы,
    // но изменяемые не часто
    //
    #pragma once
    #pragma once
    // Измените следующие определения, если Вы используете платформу из тех, что обозначена ниже.
    // Укажите MSDN последнюю информацию на соответствующее значение для разных платформ.
    #ifndef WINVER				// Позволяет использовать особенности, характерные для Windows XP и поздних версий.
    #define WINVER 0x0501		// Измените значение на соответствующую величину текущей версии Windows.
    #endif
    #ifndef _WIN32_WINNT		// Позволяет использовать особенности, характерные для Windows XP и поздних версий.
    #define _WIN32_WINNT 0x0501	// Измените значение на соответствующую величину текущей версии Windows.
    #endif
    #ifndef _WIN32_WINDOWS		// Позволяет использовать особенности, характерные для Windows 98 и поздних версий.
    #define _WIN32_WINDOWS 0x0410 // Измените значение на соответствующую величину текущей версии Windows Me or later.
    #endif
    #ifndef _WIN32_IE			// Позволяет использовать особенности, характерные для  IE 6.0 и поздних версий.
    #define _WIN32_IE 0x0600	// Измените значение на соответствующую величину текущей версии IE.
    #endif
    #define WIN32_LEAN_AND_MEAN		// Не допущение ранее используемого наполнения из заголовка Windows.
    // Заголовочный файл Windows:
    #include <windows.h>
    // Заголовочные файлы C RunTime
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <tchar.h>
    // TODO: разместите дополнительные заголовки модулей, необходимых для Вашего проекта, здесь
    /* WINDOW.h*/
    #pragma once
    #include "resource.h"
    /* WINDOW.cpp */
    // WINDOW.cpp : Определяет точку входа для приложения.
    //
    #include "stdafx.h"
    #include "WINDOW.h"
    #define MAX_LOADSTRING 100
    // Глобальные переменные:
    HINSTANCE hInst;								// текущий экземпляр класса
    TCHAR szTitle[MAX_LOADSTRING];					// Текст главного меню
    TCHAR szWindowClass[MAX_LOADSTRING];			// имя класса главного окна
    // Далее идут объявления функций, включённых в модуль Code:
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
    	// Отмена определения параметров hPrevInstance (предыдущий
    	// Экземпляр приложения) и lpCmdLine (командная строка)
    	UNREFERENCED_PARAMETER(hPrevInstance);
    	UNREFERENCED_PARAMETER(lpCmdLine);
     	// TODO: Поместите свой код здесь.
    	MSG msg;
    	HACCEL hAccelTable;
    	// Инициализация глобальных настроек
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_WINDOW, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
    	// Подготовить инициализацию приложения:
    	if (!InitInstance (hInstance, nCmdShow))
    	{
    		return FALSE;
    	}
    	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOW));
    	// Основной цикл сообщений:
    	while (GetMessage(msg, NULL, 0, 0))
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg))
    		{
    			TranslateMessage(msg);
    			DispatchMessage(msg);
    		}
    	}
    	return (int) msg.wParam;
    }
    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Регистрирует класс окна.
    //
    //  COMMENTS:
    //
    //    Эта функция и её использование необходимо только
    //    в том случае, если Вы хотите, чтобы этот код
    //    был совместим с кодом системы Win32 прежде, чем функция 'RegisterClassEx'
    //   была добавлена в Windows 95. Очень важно использовать эту функцию так
    //    чтобы это приложение давала "правильно оформленными" иконками, ассоциированных с ними
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
    	wcex.cbSize = sizeof(WNDCLASSEX);
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc	= WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOW));
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_WINDOW);
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    	return RegisterClassEx(wcex);
    }
    //
    //   FUNCTION: InitInstance(HINSTANCE, int)
    //
    //
    //   PURPOSE: Сохраняет экземпляр класса и создаёт основное окно
    //
    //   COMMENTS:
    //
    //        В этой функции мы сохраняем дескриптор экземпляр класса в глобальную переменную и
    //        создаёт и показывает основное окно программы..
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
       hInst = hInstance; // Store instance handle in our global variable
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
       if (!hWnd)
       {
          return FALSE;
       }
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
       return TRUE;
    }
    //
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  PURPOSE:  Обработка сообщений для главного окна.
    //
    //  WM_COMMAND	- обрабатывает меню приложени
    //  WM_PAINT	- Рисует основное окно
    //  WM_DESTROY	- Посылает завершающее сообщение и выход
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
    	switch (message)
    	{
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		// Сканирует раздел меню:
    		switch (wmId)
    		{
    		case IDM_ABOUT:
    			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
    			break;
    		case IDM_EXIT:
    			DestroyWindow(hWnd);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, ps);
    		// TODO: Добавьте сюда любой "рисующий" код...
    		EndPaint(hWnd, ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    // Дескриптор сообщения окна About.
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	UNREFERENCED_PARAMETER(lParam);
    	switch (message)
    	{
    	case WM_INITDIALOG:
    		return (INT_PTR)TRUE;
    	case WM_COMMAND:
    		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
    		{
    			EndDialog(hDlg, LOWORD(wParam));
    			return (INT_PTR)TRUE;
    		}
    		break;
    	}
    	return (INT_PTR)FALSE;
    }

    9.9. Приложение № VI

    Примечание: Для создания данного приложения средствами Microsoft Visual Studio 2008 вначале создайте "пустой проект", а затем заполните его этими файлами.

    /* stdafx.cpp*/
    // stdafx.cpp : исходный файл, который включает в себя стандартные заголовочные файлы.
    // textwin.pch будет заголовком предпроцессора
    // stdafx.obj будет содержать информацию предварительной компиляции
    #include "stdafx.h"
    // Поместите сюда всю дополнительную информацию, которая Вам нужна,
    // в этот файл, а ни где-либо
    /* stdafx.h */
    // stdafx.h : заголовочный файл, со стандартными системными заголовочными файлами
    // или специфичные для всего проекта часто используемые заголовочные файлы,
    // но изменяемые не часто
    //
    #pragma once
    #define WIN32_LEAN_AND_MEAN		// Использовать ранее использованный шаблон заголовков Windows
    // Windows Заголовочный файл Windows:
    #include <windows.h>
    // Общие заголовки языка Си
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <tchar.h>
    // TODO: Укажите здесь дополнительные заголовочные файлы
    // для Вашей программы
    /* textwin.h */
    #pragma once
    #include "resource.h"
    /* textwin.cpp*/
    // textwin.cpp : Определение точек входа в программу.
    //
    #include "stdafx.h"
    #include "textwin.h"
    #define MAX_LOADSTRING 100
    // Файлы с описанием функций
    #ifndef __STDIO_H
    #include <stdio.h>
    #endif
    #ifndef __STRING_H
    #include <string.h>
    #endif
    /* Глобальные константы */
    // Задание максимальной длины символьного буфера строки
    // для вывода в окно
    #ifndef SCREEN_BUFSIZE
    #define SCREEN_BUFSIZE	80
    #endif
    // Прототип функции для печати строки символов
    void Print(HDC, char *, int);
    void PrintLn(void);
    /* Глобальные переменные */
    /**********************************************************
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
    **********************************************************/
    static int cxChar, cyChar;
    static int cxCurrentPosition;
    static int cyCurrentPosition;
    // Global Variables:
    HINSTANCE hInst;								// current instance
    TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
    // Далее находятся описания функций, включённых в модули кода
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
     	// TODO: Поместите код здесь
    	MSG msg;
    	HACCEL hAccelTable;
    	// Инициализация глобальных строк
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_TEXTWIN, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
    	// Подготовка к инициализации приложения:
    	if (!InitInstance (hInstance, nCmdShow))
    	{
    		return FALSE;
    	}
    	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TEXTWIN);
    	// Основной цикл сообщений:
    	while (GetMessage(msg, NULL, 0, 0))
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg))
    		{
    			TranslateMessage(msg);
    			DispatchMessage(msg);
    		}
    	}
    	return (int) msg.wParam;
    }
    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Регистрация класса окна.
    //
    //  COMMENTS:
    //
    //    Эта функция и её использование необходима только
    //    в том случае, если Вы хотите, чтобы этот код
    //    был совместим с кодом системы Win32 прежде, чем функция 'RegisterClassEx'
    //    была добавлена в Windows 95. Очень важно использовать эту функцию так
    //    чтобы это приложение давала "правильно оформленными" иконками, ассоциированных с ними
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
    	wcex.cbSize = sizeof(WNDCLASSEX);
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc		= (WNDPROC)WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance			= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_TEXTWIN);
    	wcex.hCursor			= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground		= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName		= (LPCTSTR)IDC_TEXTWIN;
    	wcex.lpszClassName		= szWindowClass;
    	wcex.hIconSm			= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
    	return RegisterClassEx(wcex);
    }
    //
    //   FUNCTION: InitInstance(HANDLE, int)
    //
    //   PURPOSE: Сохраняет экземпляр класса и создаёт основное окно
    //
    //   COMMENTS:
    //
    //        В этой функции мы сохраняем дескриптор экземпляр класса в глобальную переменную и
    //        создаём и показываем основное окно программы..
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
       hInst = hInstance;	// Сохраняем дескриптор экземпляра класса 			// в нашу глобальную переменную
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
       if (!hWnd)
       {
          return FALSE;
       }
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
       return TRUE;
    }
    //
    //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
    //
    //  PURPOSE:  Обработка сообщений для главного окна.
    //
    //  WM_COMMAND	- обрабатывает меню приложени
    //  WM_PAINT	- Рисует основное окно
    //  WM_DESTROY	- Посылает завершающее сообщение и выход
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;        // структура для рисовани
    	HDC hdc;               // индекс контекста устройства
        static TEXTMETRIC tm;  // структура для записи метрик
                               // шрифта
    	switch (message)
    	{
        case WM_CREATE:
        {
          // Получаем контекст отображения,
          // необходимый для определения метрик шрифта
          hdc = GetDC(hWnd);
          // Заполняем структуру информацией
          // о метрике шрифта, выбранного в
          // контекст отображени
          GetTextMetrics(hdc, tm);
          // Запоминаем значение ширины дл
          // самого широкого символа
          cxChar = tm.tmMaxCharWidth;
          // Запоминаем значение высоты букв с
          // учётом межстрочного интервала
          cyChar = tm.tmHeight + tm.tmExternalLeading;
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
          // Освобождаем контекст
          ReleaseDC(hWnd, hdc);
          return 0;
        }
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		// Сканируем секцию меню:
    		switch (wmId)
    		{
    		case IDM_ABOUT:
    			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
    			break;
    		case IDM_EXIT:
    			DestroyWindow(hWnd);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, ps);
    		// TODO: Добавляем код для рисования здесь...
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
    	  // Выводим последовательно строки:
          Print(hdc, "Первая строка", 0); PrintLn();
          Print(hdc, "Вторая строка", 0); PrintLn();
          Print(hdc, "Третья строка( смещённая )", 10); PrintLn();
    		EndPaint(hWnd, ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    // Дескриптор диалогового окна сообщения: About.
    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)
    	{
    	case WM_INITDIALOG:
    		return TRUE;
    	case WM_COMMAND:
    		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
    		{
    			EndDialog(hDlg, LOWORD(wParam));
    			return TRUE;
    		}
    		break;
    	}
    	return FALSE;
    }
    /**********************************************************
     * Функция Print
     * Функция предназначена для вывода текста
     * в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * HDC hdc -- индекс контекста устройства;
     * char *str -- указатель на выводимую строку;
     * int iOFFSET -- смещение горизонтальной позиции
     * вывода текста в окно, указанное в символах;
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void Print(HDC hdc, char *str, int iOFFSET )
    {
      char buf[SCREEN_BUFSIZE];
      int i;
    /* Проверяем смещение на неравенство единице
       и корректируем его */
      if( iOFFSET < 0 ) iOFFSET = 0;
      // Подготавливаем в рабочем буфере
      i = strlen(str);
      // Проверка, что строка умещается в буфере
      if( i < SCREEN_BUFSIZE - 1 )
      // и выводим строку в зависимости от проверки
    	sprintf(buf, "%s", str);
      else
    	sprintf(buf, "%.*s", SCREEN_BUFSIZE-1, str);
      // Выводим текст в окно, начиная с текущей позиции
      // вывода текста + смещение в максимальном
      // количестве символов
      TextOut(hdc,
        cxCurrentPosition + iOFFSET * cxChar,
        cyCurrentPosition,
        buf, i);
    }
    /**********************************************************
     * Функция PrintLn
     * Функция предназначена для перевода на новую строку
     * при выводе в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * Не имеет.
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void PrintLn( void )
    {
      // Увеличиваем текущую позицию по
      // вертикали на высоту символа
      cyCurrentPosition += cyChar;
    }
    Страницы:

    9.1. Файловые операции ввода-вывода с использованием WinAPI

    9.1.1. Особенности файловых операций в Microsoft Windows

    Файловые операции в операционной системе Microsoft Windows отличаются от файловых операций MS-DOS следующим:

  • Заявлена переносимость всех файловых операций в операционных системах MS Windows на последующие версии. Это значит, что если строго следовать рекомендациям Microsoft Windows в описании её файловых функций, программа будет "эффективно компилироваться" как для платформы Win16, так и для платформы Win32 и Win64;
  • Указанные ниже функции позволяют создавать текстовые файлы размером как до 64 Кбайт, так и до 2 Гбайт (напомню, что в MS-DOS максимальный размер текстового файла - 64 Кбайт);
  • Имена файлов теперь могут писаться в кодировке ANSI с использованием "длинных имён" файлов. В MS-DOS возможно именовать файлы только в кодировке OEM с "короткими" именами файлов и каталогов;
  • Содержимое файла, созданного средствами Windows, сразу и целиком читается в оперативную память компьютера, и уже потом анализируются другими функциями (например, sscanf). В MS-DOS Вы могли вводить и выводить файлы последовательно по строкам, по формату и по записям (используя функции fges, getc, fscanf и др.). Используемый в Windows способ чтения-записи является более "безопасным" для обработчика данных и операционной системы;
  • Следствие вышесказанного. В операционной системе Microsoft Windows нужно открывать файл, осуществлять все операции чтения записи и закрывать файл в пределах обработчика одного сообщения из очереди сообщений Windows. В MS-DOS Вы могли вначале программы открыть файл, где-то в теле программы осуществить операции ввода-вывода, и закрыть файлы в конце программы. В Windows этот способ не работает - программа в ней выполняется не в том порядке, в котором записаны действия, а в том порядке, в каком поступают программе системные вызовы. Вследствие этого, по "логике программы", закрытие файла может произойти прежде, чем операция записи-чтения из файла. Естественно, произойдёт "отказ системы" со всеми вытекающими неприятными последствиями;
  • Функции открытия файлов возвращают операционной системе намного больше информации, чем "обычные" функции открытия файлов MS-DOS. При этом принимать решение, использовать или нет эту расширенную информацию, может сам программист;
  • "Стандартными средствами открытия файлов" в Microsoft Windows невозможно открытие файлов для добавления информации в конец файла.… Наверное, Вы поняли почему. Если нет - отвечаю: при чтении всего файла в буфер в конец файла можно записать любую информацию, с тем чтобы затем её сбросить на диск под тем же именем, и дополнительного режима открытия файлов не требуется;
  • Помимо функций файлового ввода-вывода Microsoft Windows Вы также можете использовать аналогичные функции ввода-вывода MS-DOS, с указанными Выше ограничениями. Но учтите, что функциями ввода-вывода MS-DOS (всё равно, являются ли они консольными, потоковыми или другими), нельзя выводить текст на экран, принтер, COM порт, а также вводить данные с клавиатуры;
  • Примечание: операции потокового вывода на экран и ввода с клавиатуры можно также осуществить и в Windows, указав опцию в IDE при создании проекта "консольное приложение Windows". Этот вопрос Вы можете изучить самостоятельно [38].

    9.1.2. Функции создания и закрытия файлов методами Win API

    Для создания, открытия и закрытия файлов Windows API использует следующие функции:

    ФУНКЦИЯ OpenFile
    СИНТАКСИС: HFILE WINAPI OpenFile( lpszFileName, lpOpenStruct, fuMode)

    LPCSTR lpszFileName - путь к файлу (в виде дальнего указателя на строку в кодировке ANSI, заканчивающуюся двоичным нулём);

    OFSTRUCT FAR* lpOpenStruct - адрес структуры OFSTRUCT, заполняемой при первом открытии файла;

    UINT fuMode - режим работы и атрибуты файла;

    НАЗНАЧЕНИЕ: Открывает файл и связывает с ним дескриптор файла;
    ОПИСАНИЕ: Функция предназначена для создания, открытия, повторного открытия и удаления файлов. В имени файла допускается указывать символы шаблона, такие как "*" и "?". Параметр fuMode используется для определения действий, выполняемых функцией OpenFile, а также задаёт атрибуты файла. Когда функция OpenFile вызывается в первый раз для открытия файла, она заполняет структуру OFSTRUCT, описанную в приложении №1 (смотри пункт 9.4 данной лекции);
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает идентификатор файла, который можно (и нужно) использовать во всех последующих операциях с файлом, или -1 при ошибке;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    ФУНКЦИЯ _lopen
    СИНТАКСИС: HFILE WINAPI _lopen( LPCSTR lpszFileName, int fuOpenMode)

    LPCSTR lpszFileName - путь к файлу (в виде дальнего указателя на строку в кодировке ANSI, заканчивающуюся двоичным нулём);

    int fnOpenMode - параметр определяет режим, в котором открывается файл;

    НАЗНАЧЕНИЕ: Открывает файл и связывает с ним дескриптор файла (упрощённая версия);
    ОПИСАНИЕ: Функция предназначена для открытия, повторного открытия файлов. В имени файла допускается указывать символы шаблона, такие как "*" и "?". Параметр fuMode используется для определения действий, выполняемых функцией _lopen ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает идентификатор файла, который можно (и нужно) использовать во всех последующих операциях с файлом, или HFILE_ERROR при ошибке;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    ФУНКЦИЯ _lclose
    СИНТАКСИС: HFILE WINAPI _lclose( hf )

    HFILE hf - дескриптор закрываемого файла;

    НАЗНАЧЕНИЕ: Закрывает файл, связанный с соответствующим дескриптором;
    ОПИСАНИЕ: Закрывает файл с дескриптором hf ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Если файл закрыт успешно, _lclose возвращает нулевое значение. При ошибке возвращается значение: HFILE_ERROR ;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    ФУНКЦИЯ _lcreat
    СИНТАКСИС: HFILE _lcreat( lpszFileName, fuAttribute)

    LPCSTR lpszFileName - путь к файлу (в виде дальнего указателя на строку в кодировке ANSI, заканчивающуюся двоичным нулём);

    int fuAttribute - переменная позволяет определить атрибуты создаваемого файла;

    НАЗНАЧЕНИЕ: Создаёт файл средствами Win API;
    ОПИСАНИЕ: Это более простая, чем OpenFile, функция для создания новых файлов. Имя файла не должно содержать метасимволов шаблона. Если указанный первым параметром файл не существует, функция _lcreat создаёт его и открывает для записи, возвращая его дескриптор файла. Если файл существует, он обрезается до нулевой длины, и затем открывается для чтения и записи;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Идентификатор созданного файла;
    ПЕРЕНОСИМОСТЬ: Версии MS Windows 3.0 и старше;

    Отличие функции OpenFile от функции _lopen заключается в поддержке ей расширенной информации о файле, передаваемой структуре OFSTRUCT, и в большем числе поддерживаемых флагов команды. Информацию о флагах функций OpenFile, _lcreate и _lopen смотри в таблице 9.1. Описание функций смотри в приложении №I к данной лекции (пункт 9.4).

    Флаги и режимы открытия файлов средствами WinAPI.
    Константа Описание
    ФУНКЦИЯ OpenFile
    OF_READ Файл открывается только для чтения.
    OF_WRITE Файл открывается только для записи.
    OF_READWRITE Файл открывается для чтения и записи.
    OF_SHARE_COMPAT Открытие файла в режиме совместимости. В этом режиме несколько приложений могут одновременно открыть файл, причём все эти приложения должны открывать файл в режиме совместимости.
    OF_SHARE_EXCLUSIVE Файл открывается в монопольном режиме. Для всех других приложений доступ к этому файлу на чтение и запись запрещён.
    OF_SHARE_DENY_WRITE После открытия файла к нему запрещается доступ со стороны других приложений на запись.
    OF_SHARE_DENY_READ После открытия файла к нему запрещается доступ со стороны других приложений на чтение.
    OF_SHARE_DENY_NONE Для открываемого файла не запрещается доступ к файлу ни на чтение, ни на запись.
    OF_PARSE Если указан этот флаг, функция OpenFile не выполняет никаких других действий, кроме заполнения структуры OFSTRUCT.
    OF_DELETE Уничтожение существующего файла.
    OF_VERIFY Если указан этот флаг, то функция OpenFile сравнивает время и дату, записанную в структуре OFSTRUCT, со временем и датой изменений указанного файла. Если обнаружено несоответствие, функция OpenFile возвращает значение HFILE_ERROR.
    OF_SEARCH Операционная система выполняет поиск файла в каталогах даже в том случае, когда текстовая строка, указанная параметром lpszFileName, содержит полный путь к файлу.
    OF_PROMPT Если указан этот флаг, то в случае невозможности найти указанный файл Windows выдаёт диалоговую панель с предложением вставить в дисковод A: дискету с файлом. Это флаг используется очень редко.
    OF_CANCEL Данный флаг указывается вместе с флагом OF_PROMPT. Если он указан, то в описанную выше диалоговую панель будет добавлена кнопка "Cancel" для отмены открытия файла. Приложение при этом получит код ошибки, соответствующий ненайденному файлу, а пользователь – возможность выйти из затруднительного положения, в которое он попадает при отсутствии дискеты с нужным файлом.
    OF_CREATE выполняется создание нового файла. Если указанный файл существует, то он обрезается до нулевой длины.
    OF_EXIST При указании этого флага функция OpenFile вначале открывает файл, а потом сразу же его закрывает. Эта операция может быть использована для того, чтобы убедиться в существовании указанного файла на диске.
    OF_REOPEN Этот флаг используется при повторном открытии файла на основе информации, хранящейся в структуре OFSTRUCT.
    ФУНКЦИЯ _lopen
    OF_READ Файл открывается только для чтения.
    OF_WRITE Файл открывается только для записи.
    OF_READWRITE Файл открывается для чтения и записи.
    OF_SHARE_COMPAT Открытие файла в режиме совместимости. В этом режиме несколько приложений могут одновременно открыть файл, причём все эти приложения должны открывать файл в режиме совместимости.
    OF_SHARE_EXCLUSIVE Файл открывается в монопольном режиме. Для всех других приложений доступ к этому файлу на чтение и запись запрещён.
    OF_SHARE_DENY_WRITE После открытия файла к нему запрещается доступ со стороны других приложений на запись.
    OF_SHARE_DENY_READ После открытия файла к нему запрещается доступ со стороны других приложений на чтение.
    OF_SHARE_DENY_NONE Для открываемого файла не запрещается доступ к файлу ни на чтение, ни на запись.
    ФУНКЦИЯ _lcreat
    0 Нормальный файл, для которого разрешено выполнение операций чтения и записи
    1 Этот файл можно открыть только для чтения
    2 Скрытый файл
    3 Системный файл

    9.1.3. Функции чтения-записи в файл

    Для операций чтения-записи в файл Microsoft Windows применяются следующие функции:

    ФУНКЦИЯ _lread
    СИНТАКСИС: UINT WINAPI _lread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    UINT cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция читает содержимое файла, определённого дескриптором, в текстовый буфер. Размер буфера ограничен 64 Кбайт;
    ОПИСАНИЕ: Функция предназначена для чтения информации из файла в буфер памяти. Через параметр hf функции следует передать идентификатор файла, для которого необходимо сделать операцию чтения. Прочитанные данные будут записаны в буфер hpvBuffer, имеющий размер cbBuffer байт. Этот буфер можно получить динамически, вызвав, например, функцию GlobalAlloc или, что лучше с точки зрения совместимости, LocalAlloc. Размер буфера не должен превышать 65 534 байт.
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, прочитанных из файла. Возвращённое значение может быть меньше затребованного в параметре cbBuffer, если достигнут конец файла. При ошибке функция возвращает значение HFILE_ERROR.
    ПЕРЕНОСИМОСТЬ: MS Windows 3.0 и старше;

    ФУНКЦИЯ _hread
    СИНТАКСИС: long WINAPI _hread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    long cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция читает содержимое файла, определённого дескриптором, в текстовый буфер. Размер буфера ограничен 2 Гбайт;
    ОПИСАНИЕ: Функция предназначена для чтения информации из файла в буфер памяти. Через параметр hf функции следует передать идентификатор файла, для которого необходимо сделать операцию чтения. Прочитанные данные будут записаны в буфер hpvBuffer, имеющий размер cbBuffer байт. Этот буфер можно получить динамически, вызвав функцию GlobalAlloc ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, прочитанных из файла. Возвращённое значение может быть меньше затребованного в параметре cbBuffer, если достигнут конец файла. При ошибке функция возвращает значение HFILE_ERROR.
    ПЕРЕНОСИМОСТЬ: MS Windows 3.1 и старше;

    ФУНКЦИЯ _lwrite
    СИНТАКСИС: UINT WINAPI _hread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    UINT cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция записывает содержимое текстового буфера в файл, определённого дескриптором. Размер буфера ограничен 64 Кбайт;
    ОПИСАНИЕ: Назначение параметров этой функции аналогично назначению параметров функции _lread, Перед вызовом функции _lwrite буфер должен содержать данные, записываемые в файл;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, записанных в файл, или значение HFILE_ERROR при ошибке;
    ПЕРЕНОСИМОСТЬ: MS Windows 3.0 и старше;

    ФУНКЦИЯ _hwrite
    СИНТАКСИС: long WINAPI _hread( hf, hpvBuffer, cbBuffer )

    HFILE hf - дескриптор файла;

    void _huge *hpvBuffer - адрес буфера с содержимым файла;

    long cbBuffer - размер буфера;

    НАЗНАЧЕНИЕ: Функция записывает содержимое текстового буфера в файл, определённого дескриптором. Размер буфера ограничен 2 Гбайт;
    ОПИСАНИЕ: Назначение параметров этой функции аналогично назначению параметров функции _hread, Перед вызовом функции _lwrite буфер должен содержать данные, записываемые в файл;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает количество байт данных, записанных в файл, или значение HFILE_ERROR при ошибке;
    ПЕРЕНОСИМОСТЬ: MS Windows 3.1 и старше;

    ФУНКЦИЯ GetDriveType
    СИНТАКСИС: UINT WINAPI GetDriveType( DriveNumber )

    int DriveNumber - определяет номер диска, для которого требуется определить тип и расположение: (0 соответствует устройству A:, 1 - B;, 2 - C: и т.д.)

    НАЗНАЧЕНИЕ: Позволяет определить тип и расположение используемого дискового блочного устройства ввода-вывода;
    ОПИСАНИЕ: Иногда требуется определить тип и расположение используемого блочного устройства ввода-вывода. Для этого необходимо использовать эту функцию;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция может вернуть нуль при ошибке или одно их следующих значений (смотри таблицу 9.2);
    ПЕРЕНОСИМОСТЬ: MS Windows 3.0 и старше;
    Константы функции GetDriveType
    Константа Описание
    ФУНКЦИЯ GetDriveType
    DRIVE_REMOVABLE Сменный диск
    DRIVE_FIXED Несменный диск
    DRIVE_REMOTE Удалённый диск, расположен на другой машине в сети

    9.1.4. Стандартные "диалоги" открытия и сохранения файлов

    Основным способом задания имени файла для его открытия (или сохранения) средствами Windows является не командная строка, а диалоговые окна "Open" (для открытия файла) и "Save As" (для задания имени сохраняемого файла). Эти диалоговые окна вызываются с помощью ниже перечисленных функций:

    ФУНКЦИЯ GetOpenFileName
    ОПРЕДЕЛЕНА В: commdlg.dll (<commdlg.h>)
    СИНТАКСИС: BOOL WINAPI GetOpenFileName( lpofn )

    OPENFILENAME FAR *lpofn - структура данных, определяющая внешний вид диалоговых панелей;

    НАЗНАЧЕНИЕ: Вызов диалогового окна "Open…" для получения полного имени для открытия файла;
    ОПИСАНИЕ: Функция выводит стандартную диалоговую панель для открытия файлов. Параметры отображения считываются и заносятся в структуру OPENFILENAME ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает ненулевое значение, если пользователь сделал выбор файла, и ноль, если он отказался от выбора, нажав кнопку "Cancel" или выбрав пункт "Close" из системного меню диалоговой панели. Нулевое значение возвращается также при возникновении ошибок;
    ПЕРЕНОСИМОСТЬ: Только MS Windows 3.1. На новых системах (Windows 95 и старше) она, возможно, заменена другими инструментами;

    ФУНКЦИЯ GetSaveFileName
    ОПРЕДЕЛЕНА В: commdlg.dll (<commdlg.h>)
    СИНТАКСИС: BOOL WINAPI GetSaveFileName( lpofn )

    OPENFILENAME FAR *lpofn - структура данных, определяющая внешний вид диалоговых панелей;

    НАЗНАЧЕНИЕ: Вызов диалогового окна "Save As…" для получения полного имени для сохранения файла на диске;
    ОПИСАНИЕ: Функция выводит стандартную диалоговую панель для сохранения файлов. Параметры отображения считываются и заносятся в структуру OPENFILENAME ;
    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ: Функция возвращает ненулевое значение, если пользователь сделал выбор файла, и ноль, если он отказался от выбора, нажав кнопку "Cancel" или выбрав пункт "Close" из системного меню диалоговой панели. Нулевое значение возвращается также при возникновении ошибок;
    ПЕРЕНОСИМОСТЬ: Только MS Windows 3.1. На новых системах (Windows 95 и старше) она, возможно, заменена другими инструментами;

    Описание синтаксиса структуры, описывающей внешний вид и поведение диалоговых окон, смотри в приложение №2 (п. 9.5) к данной лекции.

    9.2. Пример создания "каркаса" приложения средствами WinAPI в C++

    9.2.1. "Низкоуровневое" программирование в операционной системе Microsoft Windows

    Программирование на языке C++ в операционной системе Microsoft Windows условно можно разделить на "высокоуровневое" и "низкоуровневое". К "высокому уровню программирования" на языке C++ можно отнести программирование с использованием библиотеки MFC в Microsoft Visual C++, библиотеки ObjectVision в Borland C/C++ и других, менее распространённых библиотек. При написании этих библиотек учтён весь опыт программирования интерфейсов, поэтому с помощью этих библиотек легко сделать "рабочий шаблон" для своего проекта, и уже потом наполнять его нужными функциями. Это очень удобно.… Однако автор всё-таки советует для создания небольших утилит с ограниченной функциональностью использовать "низкоуровневое" программирование в Windows.

    При программировании на "низком уровне" пользователю приходится напрямую использовать функции API Windows (что в "высокоуровневых" библиотеках делать запрещено) и "вручную заниматься" выделением памяти, созданием/освобождением/закрытием контекста устройств, описывать реакцию приложения на поступившие сообщения о нажатых клавишах, событий от мыши и системных событий. Это всё гораздо сложнее.… Но не стоит расстраиваться. Для создания приложений можно использовать один или несколько предопределённых "шаблонов", которые могут быть созданы для определённых классов задач, и включать в себя все "наиболее важные и наиболее типичные" настройки для узкого круга задач и приложений. Все остальные настройки "наследуются Windows" по-умолчанию. Часть из этих шаблонов, предназначенных для обработки текстов, приведена в данном разделе.

    9.2.2. Функция WinMain

    Основной функцией создаваемого приложения Microsoft Windows является функция WinMain. Эта функция - аналог функции "main" для MS-DOS. Её задача - определить класс окна, создать главное окно приложения и "присоединить к нему" функцию обработки сообщений Windows. В отличие от функции main все входящие в неё параметры обязательны.

    Схематически алгоритм вызова любой функции WinMain можно описать следующим образом:

    int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
  • Описание и инициализация глобальных переменных;
  • Вызов функции InitApp для регистрации приложения;
  • Если инициализация прошла неудачно, то выход с возвращением значения "FALSE" ;
  • Создаётся главное окно приложения;
  • Если окно создать не удалось, то выход с возвращением значения "FALSE" ;
  • Рисуется окно приложения;
  • Запускается цикл обработки системных сообщений;
  • После выхода из цикла ставится оператор выхода из программы, с возвращаемым значением msg.wParam ;
  • Конец функции.
  • Шаблон этой функции, пригодный для создания программ для текстовой обработки данных, представлен в приложениях III и так далее к данной лекции.

    9.2.3. Инициализация приложения

    Для инициализации приложения Microsoft Windows используется функция InitApp. Назначение этой функции - заполнить структуру WNDCLASS и вызвать функцию регистрации класса окна. В случае неуспешной инициализации функция возвращает значение: "FALSE".

    В структуре WNDCLASS заполняются следующие поля:

  • wc.style - один или несколько предопределённых стилей окна;
  • wc.lpfnWndProc - указатель на функцию обработки сообщений WndProc ;
  • wc.cbClsExtra - размер дополнительной области данных для класса окна;
  • wc.cbWndExtra - размер дополнительной области памяти для каждого окна из данного класса;
  • wc.hInstance - идентификатор приложения;
  • wc.hIcon - идентификатор иконки по-умолчанию;
  • wc.hCursor - идентификатор курсора по-умолчанию;
  • wc.hbrBackground - цвет окна по-умолчанию;
  • wc.lpszMenuName - идентификатор меню для данного класса приложений;
  • wc.lpszClassName - имя класса окна (должно совпадать с классом окна для функции WinMain );
  • Пример шаблона для описания "стандартной функции" инициализации данных в программе, обрабатывающей текстовые данные, смотри в приложении III к данной лекции.

    9.2.4. Функция WndProc

    Наконец, рассмотрим функцию WndProc, которая, как нужно особо отметить, не вызывается "явно" из основной функции WinMain, но которая, тем не менее, управляет работой всего приложения Windows. Эта функция представляет собой "описание реакции системы на системные сообщения" операционной системы Microsoft Windows. Вкратце дадим понятие системных сообщений Microsoft Windows.

    "Линейная последовательность вычислений", применяемая в MS-DOS, не годится для программирования многозадачных операционных систем, таких как Windows. Во-первых, ресурсы ЭВМ при многозадачной обработке должны быть эффективно распределены между приложениями, а не предоставляться в "монопольное пользование" отдельной программе. Во-вторых, реализация реакции операционной системы MS-DOS на внешние и внутренние события, такие как прерывания от таймера ("системных часов"), от клавиатуры (на нажатие-отпускание клавиши), от мыши и т.д. далеки от совершенства. Как правило, приложению MS-DOS приходилось ждать, когда операционная система "обработает" эти прерывания. А это приводит к непроизводительному расходу ресурсов. Список неудобств можно продолжить.

    Чтобы "обойти" эти недостатки, уже в конце 80-х - начале 90-х годов XX века корпорацией Microsoft был разработан механизм эффективного использования ресурсов ЭВМ на основе архитектуры x86, полностью совместимый с MS-DOS. Этот механизм был использован сначала в файловой оболочке, а затем и в операционной системе Microsoft Windows. В его реализации используются "сообщения", которые генерируются операционной системой Microsoft Windows, ставятся в очередь на исполнение и затем передаются на обработку приложениям. После обработки сообщения приложением оно возвращает результат обратно операционной системе, на основе которого вновь генерируются сообщения и т.д. Поскольку сообщения генерируются постоянно и для всех приложений, им ничего не надо делать, кроме как "слушать" системную очередь сообщений, "отлавливать" своё сообщение и обрабатывать его. А из-за того, что все сообщения помещаются в одну очередь, не будет "опасений" по-поводу того, что сообщение "потеряется", или того, что сообщения поступят приложению не в той последовательности. И роль "всё слышащего уха" приложения Windows выполняет как раз функция WndProc.

    Синтаксис функции WndProc следующий:

    LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

    где

  • hwnd - идентификатор окна, получающего сообщение;
  • msg - идентификатор сообщения Windows;
  • wParam - первый параметр идентификатора сообщения;
  • lParam - второй параметр идентификатора сообщений.
  • Среди идентификаторов сообщений важнейшими являются следующие идентификаторы:

  • WM_CREATE - сообщение с этим идентификатором передаётся приложению в момент его создания;
  • WM_PAINT - сообщение с этим номером передаётся приложению в момент "отрисовки" его главного окна;
  • WM_COMMAND - сообщение с этим номером передаётся приложению, когда вызывается меню его главного окна (например, пользователь выбрал один из пунктов системного меню);
  • WM_DESTROY - сообщение с этим номером передаётся системе, когда необходимо "уничтожение" окна Windows;
  • Для описания реакции на сообщение Windows алгоритм функции WndProc пишется следующим образом:

  • После инициализации "внутренних переменных" программы реализуется конструкция "множественного выбора" значений идентификатора msg ;
  • В зависимости от его значения пишется "обработчик" этого сообщения. Им может быть как допустимая функция C/C++, функция API Windows, так и оператор "множественного выбора" по значению первого и второго параметра сообщения;
  • Оператор "множественного выбора" значений идентификатора msg должен обязательно содержать конструкцию "default". Это означает, что все сообщения, передаваемые операционной системой указанному окну, обработчик которых в программе отсутствует, должны обрабатываться операционной системой по-умолчанию. Эта конструкция обязательно должна иметь вид:
    default:
    	return DefWindowProc(hwnd, msg, wParam, lParam);
  • Примечание. Фактически, следуя формулировкам объектно-ориентированного программирования, сообщение "WM_CREATE" является конструктором приложения Windows, сообщение "WM_DESTROY" - деструктор приложения, а все остальные сообщения являются как бы "методами" этого приложения.

    Вводя и обрабатывая всё новые сообщения Microsoft Windows, мы можем наращивать функциональность операционной системы, независимо друг от друга и от "внешнего окружения" приложения Windows.

    9.2.5. Пример "стандартного каркаса" для приложения Microsoft Windows

    Пример "стандартного каркаса" приложения Microsoft Windows, разработанный для компиляторов Borland C/C++ версий от 3.1 до 5.5, представлен в приложении № III к данной лекции. В приложении № IV представлен пример программы для вывода текстовых строк в окно Windows. В приложениях №№ V и VI представлены те же программы, переписанные для системы Microsoft Visual Studio .Net 2003. Эти программы разработаны для 32-х битного режима Microsoft Windows и рационально используют ресурсы новых ЭВМ на основе технологий Intel и AMD.

    9.3. Резюме

    На этой лекции Вы познакомились с описанием функций ввода-вывода данных при помощи функций WinAPI, а также с "каркасом" для построения собственных приложений средствами WinAPI. Конечно же, Вы пока не умеете работать с контекстом отображения в Windows, метриками текста и т.д., необходимых для программирования на Си в операционных системах Microsoft Windows. Но начало положено…

    9.4. Приложение № I. Описание функций создания и открытия файлов

    typedef struct tagOFSTRUCT
    {
    	BYTE	cBytes;
    	BYTE	fFixedDisk;
    	UINT	nErrCode;
    	BYTE	reserved[4];
    	char	szPathName[128];
    } OFSTRUCT;

    Поле cBytes содержит размер самой структуры OFSTRUCT в байтах.

    С помощью поля fFixedDisk приложение может определить, находится ли открытый файл на жёстком диске, на флоппи-диске или другом съёмном носителе. Если содержимое этого поля отлично от нуля, то файл находится на жёстком диске.

    Если при открытии файла произошла ошибка, в поле nErrCode записывается код ошибки. Возможные значения для кода ошибки приведены в приложении №I к книге [37].

    Поле reserved зарезервировано, и не должно использоваться.

    В поле szPathName находится полный путь к файлу в кодировке OEM.

    9.5. Приложение № II. Основные опции стандартных диалогов GetOpenFileName и GetSaveFileName

    typedef struct tagOFN
    {
    	DWORD	lStructSize;
    	HWND  	hwndOwner;
    	HINSTANCE	hInstance;
    	LPCSTR	lpstrFilter;
    	LPSTR  	lpstrCustomFilter;
    	DWORD	nMaxCustFilter;
    	DWORD 	nFilterIndex;
    	LPSTR  	lpstrFile;
    	DWORD  	nMaxFile;
    	LPSTR  	lpstrFileTitle;
    	DWORD 	nMaxFileTitle;
    	LPCSTR	lpstrInitialDir;
    	LPCSTR	lpstrTitle;
    	DWORD 	Flags;
    	UINT      	nFileOffset;
    	UINT     	nFileExtension
    	LPCSTR   	lpstrDefExt;
    	LPARAM	lCustData;
    	UINT      	(CALLBACK *lpfnHook) (HWND, UINT, WPARAM, LPARAM);
    	LPCSTR 	lpTemplateName;
    } OPENFILENAME;

    В таблице 9.3 представлено назначение полей данной структуры. В таблице 9.4 представлено описание и расшифровка режимов вывода файлов, записанных в переменную Flags.

    Описание полей структуры OPENFILENAME
    Структура: OPENFILENAME
    Имя поля Назначение поля структуры
    lStructSize Перед вызовом функций, использующих эту структуру, в это поле должен быть занесён размер структуры в байтах.
    hwndOwner Поле должно содержать идентификатор окна, создающего диалоговую панель. Можно указать значение NULL, при этом диалоговое окно не будет иметь окна-владельца, но в этом случае будет нельзя использовать флаг OFN_SHOWHELP.
    hInstance Поле hInstance используется перед вызовом функции для идентификации блока памяти, содержащего шаблон диалоговой панели. Содержимое поля игнорируется в том случае, если не указан флаг OFN_ENABLETEMPLATE или OFN_ENABLETEMPLATEHANDLE.
    lpstrFilter В поле должен быть указан адрес текстовой строки, задающий фильтр для выбора имён файлов (шаблоны имён файлов). Фильтр должен состоять из одной или нескольких расположенных непосредственно друг за другом пар строк, закрытых двоичным нулём. Последняя строка должна иметь на конце два двоичных нуля. Первая строка в паре строк описывает название фильтра (например, "Text Files" ), а во второй строке из пары строк через знак ";" перечисляются возможные шаблоны для имён файлов.
    lpsrCustomFilter В поле должен быть указан адрес текстовой строки, задающий фильтр для выбора имён файлов (шаблон для выбора файлов). Фильтр должен состоять из одной расположенных непосредственно друг за другом пары строк, закрытых двоичным нулём. Последняя строка должна иметь на конце два двоичных нуля. Первая строка в паре описывает название фильтра (например, "Text Files" ), а во второй строке пары через знак ";" перечисляются возможные шаблоны для имён файлов. Этот фильтр используется только в том случае, если в поле lpstrFilter содержится NULL.
    nMaxCustFilter Определяет размер буфера в байтах, указанного в поле lpstrCustomFile. Размер этого буфера должен быть не меньше 40 байт.
    nFilterIndex Поле определяет номер пары строк, используемых для фильтра, указанного в поле lpstrFilter или lpstrCustomFilter.
    lpstrFile Поле должно содержать адрес текстовой строки, в которую будет записан полный путь к выбранному файлу. Если перед вызовом функций, использующих эту структуру, заполнить её значением, содержащем путь к файлу, этот путь будет выбран по-умолчанию при открытии диалоговых панелей "Open…" или "Save As…" ;
    nMaxFile Поле должно содержать размер в байтах буфера, расположенного по адресу, указанного в поле lpstrFile. Размер этого буфера должен быть достаточным для записи полного пути к файлу. FAT16 запрещает использовать для указания пути строку более 128 символов. VFAT и другие файловые системы имеют большее предельное значение "путевого имени".
    lpstrFileTitle В это поле необходимо записать адрес буфера, в который после выбора будет записано имя файла с расширением, но без пути к файлу. Это поле должно быть использовано приложением для отображения имени выбранного файла.
    nMaxFileTitle Поле должно содержать размер указанного буфера (13 для файлов MS-DOS и Windows 16, и до 255 для Windows 32/64).
    lpstrInitialDir Поле позволяет указать начальный каталог, который будет выбран для поиска файла сразу после отображения диалоговой панели: "Open…". Если нужно просмотреть файл в текущем каталоге, в это поле необходимо записать значение: NULL.
    lpstrTitle В этом поле задаётся "нестандартный" заголовок панели, появляющийся при вызове функции. Если в этом поле содержится значение "NULL", используются заголовки по-умолчанию: "Open…" и "Save As…".
    Flags Данное поле позволяет задать различные режимы выбора файла, влияющих на внешний вид диалоговых панелей. Описание этих флагов смотри в таблице D.4.???.
    nFileOffset После возврата из функции это поле будет содержать смещение первого символа имени файла относительно начала буфера lpstrFile. Это поможет Вам "разделить" имя файла и путь к нему.
    nFileExtension После возврата из функции это поле будет содержать смещение первого символа расширения имени файла относительно начала буфера lpstrFile.
    lpstrDefExt Поле указывает на буфер, который содержит расширение имени файла, используемого по-умолчанию. Это расширение добавляется к имени выбранного файла, если при выборе расширения имя указано не было.
    lCustData Значение, передаваемой функции фильтра через параметр lParam.
    (CALLBACK *lpfnHook)(HWND,UINT, WPARAM, LPARAM ) Указатель на функцию фильтра, обрабатывающую сообщения для диалоговой панели. Функция будет вызываться только в том случае, если указан флаг OFN_ENABLEHOOK. Если фильтр не обрабатывал сообщение, он должен вернуть нулевое значение. Если же он вернёт значение, отличное от нуля, стандартная функция диалога не будет обрабатывать сообщение, которое уже обработано функцией фильтра.
    lpTemplateName Идентификатор ресурса, содержащего шаблон диалоговой панели, используемого вместо шаблона, имеющегося в библиотеке commdlg.dll. Для ссылки на ресурс можно использовать макрокоманду MAKEINTRESORCE. Для использования альтернативного шаблона в поле Flags следует установить флаг OFN_ENABLETEMPLATE.
    Описание флагов структуры OPENFILENAME
    Флаги структуры: OPENFILENAME
    Флаг Описание
    OFN_ALLOWMULTISELECT Разрешается выбор нескольких файлов одновременно. Если указан этот флаг, после выбора поле lpstrFile будет указывать на буфер, заполненный именами выбранных файлов (или путями к выбранным файлам), разделёнными пробелом.
    OFN_CREATEPROMPT При использовании этого флага, если указанный файл не существует, создаётся диалоговая панель, в которой предлагается создать файл. Этот флаг устанавливается автоматически при использовании флагов OFN_PATHMUSTEXIST и OFN_FILEMUSTEXIST.
    OFN_ENABLEHOOK Разрешается использовать функцию фильтра, адрес которой указан в поле lpfnHook.
    OFN_ENABLETEMPLATE Если указан этот флаг, для создания диалоговой панели Windows будет использовать шаблон, определяемыйй содержимым полей hInstance и lpTemplateName.
    OFN_ENABLETEMPLATEHANDLE При использоваении этого флага поле hInstance используется для идентификации блока памяти, содержащего предварительно загруженный шаблон диалоговой панели. В этом случае содержимое поля lpTemplateName игнорируется.
    OFN_EXTENSIONDIFFERENT Устанавливается после возвращения из функции и указывает, что расширение файла отличается от заданного в поле lpstrDefExt. Этот флаг не устанавливается, если перед вызовом функции в поле lpstrDefExt было записано значение NULL, или если файл не имеет расширения имени.
    OFN_FILEMUSTEXIST Можно выбирать только имена файлов, которые существуют. Если в поле "File Name" ("Имя файла") диалоговойц панели набрать имя несуществующего файла, на экране появится диалоговая панель с предупреждающим сообщением.
    OFN_HIDEREADONLY Убрать переключатель "Read Only" ("Только чтение").
    OFN_NOCHANGEDIR Для выбора используется каталог, который был текущем при вызове функции.
    OFN_NOREADONLYRETURN Выбранные файлы не могут иметь атрибут "только чтение" или располагаться в защищённом от записи каталоге.
    OFN_NOTESTFILECREATE Перед завершением работы диалоговой панели создание файла не выполняется. Не выполняются и проверки на переполнение диска, защиту записи или наличия доступа в сети.
    OFN_NOVALIDATE В возвращаемом имени файла могут присутствовать неразрешённые символы.
    OFN_OVERWRITEPROMPT Используется для диалоговой панели "Save as…". Если выбранный файл существует, на экран выводится диалоговая панель с предупреждением.
    OFN_PATHMUSTEXIST Можно вводить только существующие пути к файлам.
    OFN_READONLY После вызова функции переключатель "Read Only" ("Только чтение") будет находиться во включённом состоянии.
    OFN_SHAREWARE Флаг устанавливается после возвращения из функции и указывает, что при вызове функции OpenFile произошла ошибка при совместном доступе к файлу в сети.
    OFN_SHOWHELP Если указан этот флаг, то в диалоговой панели будет создана кнопка "Help" ("Справка"). Если указан это флаг, поле hwndOwner не должно содержать значения NULL.

    9.6. Приложение № III

    /* Файл INIT.CPP */
    /**********************************************************
     * Каркас приложений Windows,
     * на основе которого можно строить более
     * сложные приложения MS WINDOWS.
     * Каркас использует правила для написани
     * программ на платформе Turbo C++ 3.1
     * 16-ти разрядных версий Windows.
     *
     * Более подробную информацию о "низкоуровневом" написании
     * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
     * Фролов, "Операционная система Microsoft Windows 3.1.
     * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
     * книги этих авторов.
    **********************************************************/
    #define STRICT
    #include <windows.h>
    #include <mem.h>
    // Прототипы функций
    // Первая функция - для инициализации
    // приложения Windows, вторая функция -
    // для обработки системных сообщений.
    BOOL InitApp(HINSTANCE);
    LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
    /* Значения класса и заголовка впоследствии нужно заменить */
    // Имя класса окна
    char const szClassName[]   = "WindowAppClass";
    // Заголовок окна
    char const szWindowTitle[] = "Window Application";
    // =====================================
    /***************************************
     * Функция WinMain
     * Получает управление при запуске
     * приложени
    ***************************************/
    // =====================================
    #pragma argsused
    int PASCAL
    WinMain(HINSTANCE hInstance,     // идентификатор текущей
    				 // копии приложени
    	HINSTANCE hPrevInstance, // идентификатор предыдущей
    				 // копии приложени
    	LPSTR     lpszCmdLine,   // указатель на командную строку
    	int       nCmdShow)      // способ отображения главного
    	                         // окна приложени
    {
      MSG  msg;   // структура для работы с сообщениями
      HWND hwnd;  // идентификатор главного окна приложени
      // Проверяем, не запускалось ли это приложение ранее
    //  if(!hPrevInstance)
    //  {
        // Если не запускалось, вызываем функцию InitApp
        // для инициализации приложения.
    /*****************************************************
     * Вызываем функцию InitApp
     * для инициализации приложения.
     * Если инициализацию выполнить не удалось,
     * завершаем приложение
    *****************************************************/
        if(!InitApp(hInstance))
          return FALSE;
    //  }
    /****************************************************
     * После успешной инициализации приложения создаём
     * главное окно приложени
    ****************************************************/
      hwnd = CreateWindow(
        szClassName,         // имя класса окна (см. Выше )
        szWindowTitle,       // заголовок окна (см. Выше)
        WS_OVERLAPPEDWINDOW, // стиль окна
    /****************************************************
     * В данном случае это перекрывающееся окно, но эту
     * опцию можно изменить для других типов окон
    *****************************************************/
        CW_USEDEFAULT,       // задаём размеры и расположение
        CW_USEDEFAULT,       // окна, принятые по умолчанию
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        0,                   // идентификатор родительского окна
    			// Для главного окна его менять нельз
        0,                   // идентификатор меню
    /**********************************************************
     * В случае, если у окна необходимо создать меню, вместо
     * нуля сюда вставляется идентификатор меню (тип HMENU),
     * созданный с помощью функции LoadMenu.
     *
     * Если меню подключается как ресурс приложения в функции
     * InitApp, в этом поле также нужно оставить 0
    **********************************************************/
        hInstance,           // идентификатор приложени
        NULL);               // указатель на дополнительные
    			 // параметры
    /**********************************************************
     * Далее код лучше не менять *
    **********************************************************/
      // Если создать окно не удалось, завершаем приложение
      if(!hwnd)
        return FALSE;
    /**********************************************************
     * В случае если Вам не нужно рисовать главное окно
     * приложения (например, Вы пишете программу мастер)
     * две нижеперечисленные функции:  ShowWindow и
     * UpdateWindow, указывать не надо
    **********************************************************/
      // Рисуем окно. Для этого после функции ShowWindow, рисующей
      // окно, вызываем функцию UpdateWindows, посылающую
      // сообщение WM_PAINT в функцию окна
      ShowWindow(hwnd, nCmdShow);
      UpdateWindow(hwnd);
    /**********************************************************
     * Далее до конца функции код лучше не менять *
    **********************************************************/
      // Запускаем цикл обработки сообщений
      while(GetMessage(msg, 0, 0, 0))
      {
        DispatchMessage(msg);
      }
      // Возвращаем значение WParam, переданное
      // в качестве параметра функции PostQuitMessage
      // в процессе инициирования завершения работы
      // приложения из функции окна.
      // Затем завершаем работу приложени
      return msg.wParam;
    }
    /* Конец функции WinMain *|
    // =====================================
    /**********************************************************
     * Функция InitApp
     * Вызывается из функции WinMain дл
     * инициализации приложения.
     * Выполняет регистрацию класса окна
    **********************************************************/
    // =====================================
    BOOL InitApp(HINSTANCE hInstance)
    {
      ATOM aWndClass; // атом для кода возврата
      WNDCLASS wc;    // структура для регистрации
                      // класса окна
      // Записываем нулевые значения во все поля структуры
      memset(wc, 0, sizeof(wc));
      // Стиль окна
    /**********************************************************
     * Поле style задаёт стиль класса окна и задаётся в виде
     * констант, описанных в файле <windows.h>. Описани
     * констант стилей начинается с префикса CS_. Стиль окна
     * задаёт реакцию окна на изменения его размера, на
     * выполнение в окне операции двойного щелчка мышью, а
     * также задаёт другие характеристики окна.
     * Если в главное окно предполагается вывод информации,
     * необходимо указать, по крайней мере:
     *   wc.style = CS_HREDRAW | CS_REDRAW;
     * в противном случае записать:
     *   wc.style = 0;
    **********************************************************/
      wc.style = 0;
      // Указатель на функцию окна, обрабатывающую
      // сообщения, предназначенные для всех окон,
      // созданных на основе данного класса
      /* Желательно не менять! */
      wc.lpfnWndProc = (WNDPROC) WndProc;
      // Размер дополнительной области данных,
      // зарезервированной в описании класса окна
      /* Желательно не менять! */
      wc.cbClsExtra = 0;
      // Размер дополнительной области данных,
      // зарезервированной для каждого окна,
      // созданного на основе данного класса
      /* Желательно не менять! */
      wc.cbWndExtra = 0;
      // Идентификатор приложения, которое
      // создало данный класс
      /* Желательно не менять! */
      wc.hInstance = hInstance;
      // Идентификатор пиктограммы, используемой
      // для окно данного класса
    /**********************************************************
     * Иконки создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadIcon.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется иконка (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * пиктограммы. Если Вы не уверены, то этот параметр
     * менять не нужно.
    **********************************************************/
      wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      // Идентификатор курсора, используемого
      // для окна данного класса
    /**********************************************************
     * Курсоры создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadCursor.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется курсор (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * курсора. Если Вы не уверены, то этот параметр менять
     * не нужно (оставляем стандартный курсор в виде стрелки).
    **********************************************************/
      wc.hCursor = LoadCursor(NULL, IDC_ARROW);
      // Цвет фона окна
      /* Желательно не менять, оставить системный цвет */
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
      // Идентификатор меню
    /**********************************************************
     * В случае если у окна необходимо создать меню, в это
     * поле нужно указать адрес текстовой строки, содержащей
     * имя шаблона меню в файле ресурсов. Все перекрывающиеся и
     * временные окна, созданные на базе этого класса, будут
     * иметь меню, определённое данным шаблоном. Пример:
     *  wc.lpszMenuName = "APP_MENU";
     * Если для идентификации шаблона использовать целые
     * числа, необходимо использовать макрокоманду
     * MAKEINTRESOURCE. Например, в файле описания ресурсов и в
     * файле исходного приложения определена константа:
     * #define APP_MENU 123
     * В этом случае строка примет вид:
     *  wc.lpszMenuName = MAKEINTRESOURCE( APP_MENU );
     * Если в окне меню не нужно, оставьте параметр без
     * изменения.
    **********************************************************/
      wc.lpszMenuName = (LPSTR)NULL;
      /* Желательно не менять остальные операторы до конца
         функции */
      // Имя, которое присваивается создаваемому
      // классу и используется при создании
      // окон данного класса
      wc.lpszClassName = (LPSTR)szClassName;
      // Регистрация класса
      aWndClass = RegisterClass(wc);
      // Возвращаем результат регистрации класса
      return (aWndClass != 0);
    }
    /* Файл WinProc.cpp */
    #define STRICT
    #include <windows.h>
    #include <mem.h>
    // =====================================
    /**********************************************************
     * Функция WndProc
     * НЕ ВЫЗЫВАЕТСЯ ни из одной функции приложения.
     * Эту функцию вызывает Windows в процессе
     * обработки сообщений. Для этого адрес функции WndProc
     * указывается при регистрации класса окна.
     * Функция выполняет обработку сообщений главного
     * окна приложени
     *
     * Более подробную информацию о "низкоуровневом" написании
     * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
     * Фролов, "Операционная система Microsoft Windows 3.1.
     * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
     * книги этих авторов.
    **********************************************************/
    // =====================================
    LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      // Выполняем обработку сообщений. Идентификатор
      // сообщения передаётся через параметр msg
      switch (msg)
      {
    /**********************************************************
     * Это сообщение приходит, когда создаётся окно приложени
     * Здесь нужно вызвать контекст экрана, сохранить в
     * переменных его метрики и освободить его.
    **********************************************************/
    
        case WM_CREATE:
        {
          // Получаем контекст отображения,
          // необходимый для определения метрик.
    	return 0;
        }
    /**********************************************************
     * Это сообщение приходит, когда "рисуется" окно приложения.
     * Здесь нужно вызвать контекст экрана, вывести необходимые
     * данные на экран, и освободить контекст.
    **********************************************************/
    
        case WM_PAINT:
        {
          // Инициализируем текущую позицию вывода текста
          // Получаем контекст экрана
          // Освобождаем контекст экрана
             return 0;
        }
    /*********************************************************
        // Это сообщение приходит, когда вы поместили курсор
        // мыши в область главного окна приложения и нажали
        // левую клавишу мыши
        case WM_LBUTTONDOWN:
          {
    	return 0;
          }
        // Это сообщение приходит, когда вы поместили курсор
        // мыши в область главного окна приложения и нажали
        // правую клавишу мыши
        case WM_RBUTTONDOWN:
          {
    	return 0;
          }
    **********************************************************/
    /**********************************************************
     * Это сообщение приходит, когда вы завершаете
     * работу приложения стандартным дл
     * Windows способом
    **********************************************************/
        case WM_DESTROY:
        {
          // Инициируем завершение работы приложения,
          // помещая в очередь приложения сообщение
          // WM_QUIT. Это приведёт к завершению
          // цикла обработки сообщений в функции WinMain
          PostQuitMessage(0);
          return 0;
        }
      }
      // Все сообщения, которые не обрабатываются нашей
      // функцией окна, ДОЛЖНЫ передаваться функции
      // DefWindowProc
      return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    /* Файл WINDOW.DEF */
    ; =============================
    ; Файл определения модул
    ; =============================
    ; Имя приложени
    NAME WINDOW
    ; Описание приложени
    DESCRIPTION 'Приложение WINDOW, (C) 1994, Frolov A.V.'
    ; Определение типа загрузочного модуля как
    ; приложения Windows
    EXETYPE windows
    ; Программа, которая будет записана в начало файла
    ; приложения. Эта программа получит управление
    ; при попытке запуска приложения в среде MS-DOS
    STUB 'winstub.exe'
    ; Размер стека в байтах
    STACKSIZE 5120
    ; Размер локальной кучи памяти приложения в байтах
    HEAPSIZE 1024
    ; Атрибуты сегмента кода
    CODE preload moveable discardable
    ; Атрибуты сегмента данных
    DATA preload moveable multiple

    9.7. Приложение № IV

    /* Файл INIT.CPP */
    /**********************************************************
     * Каркас приложений Windows,
     * на основе которого можно строить более
     * сложные приложения MS WINDOWS.
     * Каркас использует правила для написани
     * программ на платформе Turbo C++ 3.1
     * 16-ти разрядных версий Windows.
     *
     * Более подробную информацию о "низкоуровневом" написании
     * программ для Microsoft Windows смотри А.В. Фролов, Г.В.
     * Фролов, "Операционная система Microsoft Windows 3.1.
     * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др.
     * книги этих авторов.
    **********************************************************/
    #define STRICT
    #include <windows.h>
    #include <mem.h>
    // Прототипы функций
    // Первая функция - для инициализации
    // приложения Windows, вторая функция -
    // для обработки системных сообщений.
    BOOL InitApp(HINSTANCE);
    LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
    /* Значения класса и заголовка впоследствии нужно заменить */
    // Имя класса окна
    char const szClassName[]   = "WindowAppClass";
    // Заголовок окна
    char const szWindowTitle[] = "Window Application";
    // =====================================
    /***************************************
     * Функция WinMain
     * Получает управление при запуске
     * приложени
    ***************************************/
    // =====================================
    #pragma argsused
    int PASCAL
    WinMain(HINSTANCE hInstance,     // идентификатор текущей
    				 // копии приложени
    	HINSTANCE hPrevInstance, // идентификатор предыдущей
    				 // копии приложени
    	LPSTR     lpszCmdLine,   // указатель на командную строку
    	int       nCmdShow)      // способ отображения главного
    	                         // окна приложени
    {
      MSG  msg;   // структура для работы с сообщениями
      HWND hwnd;  // идентификатор главного окна приложени
      // Проверяем, не запускалось ли это приложение ранее
    //  if(!hPrevInstance)
    //  {
        // Если не запускалось, вызываем функцию InitApp
        // для инициализации приложения.
    /*****************************************************
     * Вызываем функцию InitApp
     * для инициализации приложения.
     * Если инициализацию выполнить не удалось,
     * завершаем приложение
    *****************************************************/
        if(!InitApp(hInstance))
          return FALSE;
    //  }
    /****************************************************
     * После успешной инициализации приложения создаём
     * главное окно приложени
    ****************************************************/
      hwnd = CreateWindow(
        szClassName,         // имя класса окна (см. Выше )
        szWindowTitle,       // заголовок окна (см. Выше)
        WS_OVERLAPPEDWINDOW, // стиль окна
    /****************************************************
     * В данном случае это перекрывающееся окно, но эту
     * опцию можно изменить для других типов окон
    *****************************************************/
        CW_USEDEFAULT,       // задаём размеры и расположение
        CW_USEDEFAULT,       // окна, принятые по умолчанию
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        0,                   // идентификатор родительского окна
    			// Для главного окна его менять нельз
        0,                   // идентификатор меню
    /**********************************************************
     * В случае если у окна необходимо создать меню, вместо
     * нуля сюда вставляется идентификатор меню (тип HMENU),
     * созданный с помощью функции LoadMenu.
     *
     * Если меню подключается как ресурс приложения в функции
     * InitApp, в этом поле также нужно оставить 0
    **********************************************************/
        hInstance,           // идентификатор приложени
        NULL);               // указатель на дополнительные
    			 // параметры
    /**********************************************************
     * Далее код лучше не менять *
    **********************************************************/
      // Если создать окно не удалось, завершаем приложение
      if(!hwnd)
        return FALSE;
    /**********************************************************
     * В случае если Вам не нужно рисовать главное окно
     * приложения (например, Вы пишете программу-мастер)
     * две нижеперечисленные функции:  ShowWindow и
     * UpdateWindow, указывать не надо
    **********************************************************/
      // Рисуем окно. Для этого после функции ShowWindow, рисующей
      // окно, вызываем функцию UpdateWindows, посылающую
      // сообщение WM_PAINT в функцию окна
      ShowWindow(hwnd, nCmdShow);
      UpdateWindow(hwnd);
    /**********************************************************
     * Далее до конца функции код лучше не менять *
    **********************************************************/
      // Запускаем цикл обработки сообщений
      while(GetMessage(msg, 0, 0, 0))
      {
        DispatchMessage(msg);
      }
      // Возвращаем значение WParam, переданное
      // в качестве параметра функции PostQuitMessage
      // в процессе инициирования завершения работы
      // приложения из функции окна.
      // Затем завершаем работу приложени
      return msg.wParam;
    }
    /* Конец функции WinMain *|
    // =====================================
    /**********************************************************
     * Функция InitApp
     * Вызывается из функции WinMain дл
     * инициализации приложения.
     * Выполняет регистрацию класса окна
    **********************************************************/
    // =====================================
    BOOL InitApp(HINSTANCE hInstance)
    {
      ATOM aWndClass; // атом для кода возврата
      WNDCLASS wc;    // структура для регистрации
                      // класса окна
      // Записываем нулевые значения во все поля структуры
      memset(wc, 0, sizeof(wc));
      // Стиль окна
    /**********************************************************
     * Поле style задаёт стиль класса окна и задаётся в виде
     * констант, описанных в файле <windows.h>. Описани
     * констант стилей начинается с префикса CS_. Стиль окна
     * задаёт реакцию окна на изменения его размера, на
     * выполнения в окне операции двойного щелчка мышью, а
     * также задаёт другие характеристики окна.
     * Если в главное окно предполагается вывод информации,
     * необходимо указать, по крайней мере:
     *   wc.style = CS_HREDRAW | CS_REDRAW;
     * в противном случае записать:
     *   wc.style = 0;
    **********************************************************/
      wc.style = 0;
      // Указатель на функцию окна, обрабатывающую
      // сообщения, предназначенные для всех окон,
      // созданных на основе данного класса
      /* Желательно не менять! */
      wc.lpfnWndProc = (WNDPROC) WndProc;
      // Размер дополнительной области данных,
      // зарезервированной в описании класса окна
      /* Желательно не менять! */
      wc.cbClsExtra = 0;
      // Размер дополнительной области данных,
      // зарезервированной для каждого окна,
      // созданного на основе данного класса
      /* Желательно не менять! */
      wc.cbWndExtra = 0;
      // Идентификатор приложения, которое
      // создало данный класс
      /* Желательно не менять! */
      wc.hInstance = hInstance;
      // Идентификатор пиктограммы, используемой
      // для окно данного класса
    /**********************************************************
     * Иконки создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadIcon.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется иконка (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * пиктограммы. Если Вы не уверены, то этот параметр
     * менять не нужно.
    **********************************************************/
      wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      // Идентификатор курсора, используемого
      // для окно данного класса
    /**********************************************************
     * Курсоры создаются или "подгружаются" из специальных
     * файлов с "ресурсами", с помощью команды LoadCursor.
     * Первый параметр функции содержит идентификатор
     * приложения, в котором ищется курсор (значение NULL дл
     * системных областей), второй параметр задаёт имя ресурса-
     * курсора. Если Вы не уверены, то этот параметр менять
     * не нужно (оставляем стандартный курсор в виде стрелки).
    **********************************************************/
      wc.hCursor = LoadCursor(NULL, IDC_ARROW);
      // Цвет фона окна
      /* Желательно не менять, оставить системный цвет */
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
      // Идентификатор меню
    /**********************************************************
     * В случае если у окна необходимо создать меню, в это
     * поле нужно указать адрес текстовой строки, содержащей
     * имя шаблона меню в файле ресурсов. Все перекрывающиеся и
     * временные окна, созданные на базе этого класса, будут
     * иметь меню, определённое данным шаблоном. Пример:
     *  wc.lpszMenuName = "APP_MENU";
     * Если для идентификации шаблона использовать целые
     * числа, необходимо использовать макрокоманду
     * MAKEINTRESOURCE. Например, в файле описания ресурсов и в
     * файле исходного приложения определена константа:
     * #define APP_MENU 123
     * В этом случае строка примет вид:
     *  wc.lpszMenuName = MAKEINTRESOURCE( APP_MENU );
     * Если в окне меню не нужно, оставьте параметр без
     * изменения.
    **********************************************************/
      wc.lpszMenuName = (LPSTR)NULL;
      /* Желательно не менять остальные операторы до конца
         функции */
      // Имя, которое присваивается создаваемому
      // классу и используется при создании
      // окон данного класса
      wc.lpszClassName = (LPSTR)szClassName;
      // Регистрация класса
      aWndClass = RegisterClass(wc);
      // Возвращаем результат регистрации класса
      return (aWndClass != 0);
    }
    /* Файл TEXTW.CPP */
    /**********************************************************
     * Функция WndProc
    **********************************************************/
    #define STRICT
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
    // Задание максимальной длины символьного буфера строки
    // для вывода в окно
    #ifndef SCREEN_BUFSIZE
    #define SCREEN_BUFSIZE	80
    #endif
    // Прототип функции для печати строки символов
    void Print(HDC, char *, int);
    void PrintLn(void);
    /**********************************************************
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
    **********************************************************/
    static int cxChar, cyChar;
    static int cxCurrentPosition;
    static int cyCurrentPosition;
    LRESULT CALLBACK _export
    WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      HDC hdc;              // индекс контекста устройства
      PAINTSTRUCT ps;       // структура для рисовани
      static TEXTMETRIC tm; // структура для записи метрик
                            // шрифта
      switch (msg)
      {
        case WM_CREATE:
        {
          // Получаем контекст отображения,
          // необходимый для определения метрик шрифта
          hdc = GetDC(hwnd);
          // Заполняем структуру информацией
          // о метрике шрифта, выбранного в
          // контекст отображени
          GetTextMetrics(hdc, tm);
          // Запоминаем значение ширины дл
          // самого широкого символа
          cxChar = tm.tmMaxCharWidth;
          // Запоминаем значение высоты букв с
          // учётом межстрочного интервала
          cyChar = tm.tmHeight + tm.tmExternalLeading;
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
          // Освобождаем контекст
          ReleaseDC(hwnd, hdc);
          return 0;
        }
        case WM_PAINT:
        {
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
          hdc = BeginPaint(hwnd, ps);
          // Выводим последовательно строки:
          Print(hdc, "Первая строка", 0); PrintLn();
          Print(hdc, "Вторая строка", 0); PrintLn();
          Print(hdc, "Третья строка( смещённая )", 10); PrintLn();
          EndPaint(hwnd, ps);
          return 0;
        }
        case WM_DESTROY:
        {
          PostQuitMessage(0);
          return 0;
        }
      }
      return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    /**********************************************************
     * Функция Print
     * Функция предназначена для вывода текста
     * в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * HDC hdc -- индекс контекста устройства;
     * char *str -- указатель на выводимую строку;
     * int iOFFSET -- смещение горизонтальной позиции
     * вывода текста в окно, указанное в символах;
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void Print(HDC hdc, char *str, int iOFFSET )
    {
      char buf[SCREEN_BUFSIZE];
      int i;
    /* Проверяем смещение на неравенство единице
       и корректируем его */
      if( iOFFSET < 0 ) iOFFSET = 0;
      // Подготавливаем в рабочем буфере
      i = strlen(str);
      // Проверка, что строка умещается в буфере
      if( i < SCREEN_BUFSIZE - 1 )
      // и выводим строку в зависимости от проверки
    	sprintf(buf, "%s", str);
      else
    	sprintf(buf, "%.*s", SCREEN_BUFSIZE-1, str);
      // Выводим текст в окно, начиная с текущей позиции
      // вывода текста + смещение в максимальном
      // количестве символов
      TextOut(hdc,
        cxCurrentPosition + iOFFSET * cxChar,
        cyCurrentPosition,
        buf, i);
    }
    /**********************************************************
     * Функция PrintLn
     * Функция предназначена для перевода на новую строку
     * при выводе в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * Не имеет.
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void PrintLn( void )
    {
      // Увеличиваем текущую позицию по
      // вертикали на высоту символа
      cyCurrentPosition += cyChar;
    }
    /* Файл TEXTWN.DEF*/
    ; =============================
    ; Файл определения модул
    ; =============================
    ; Имя приложени
    NAME TEXTWIN
    ; Описание приложени
    DESCRIPTION 'Приложение WINDOW, (C) 1994, Frolov A.V.'
    ; Определение типа загрузочного модуля как
    ; приложения Windows
    EXETYPE windows
    ; Программа, которая будет записана в начало файла
    ; приложения. Эта программа получит управление
    ; при попытке запуска приложения в среде MS-DOS
    STUB 'winstub.exe'
    ; Размер стека в байтах
    STACKSIZE 5120
    ; Размер локальной кучи памяти приложения в байтах
    HEAPSIZE 1024
    ; Атрибуты сегмента кода
    CODE preload moveable discardable
    ; Атрибуты сегмента данных
    DATA preload moveable multiple

    9.8. Приложение № V

    Примечание: Для создания данного приложения средствами Microsoft Visual Studio 2008 вначале создайте "пустой проект", а затем заполните его этими файлами.

    /* stdafx.cpp*/
    // stdafx.cpp : исходный файл, который включает в себя стандартные заголовочные файлы.
    // WINDOW.pch будет заголовком предпроцессора
    // stdafx.obj будет содержать информацию предварительной компиляции
    #include "stdafx.h"
    // Поместите сюда всю дополнительную информацию, которая Вам нужна,
    // в этот файл, а ни где-либо ещё.
    /* stdafx.h */
    // stdafx.h : заголовочный файл, со стандартными системными заголовочными файлами
    // или специфичные для всего проекта часто используемые заголовочные файлы,
    // но изменяемые не часто
    //
    #pragma once
    #pragma once
    // Измените следующие определения, если Вы используете платформу из тех, что обозначена ниже.
    // Укажите MSDN последнюю информацию на соответствующее значение для разных платформ.
    #ifndef WINVER				// Позволяет использовать особенности, характерные для Windows XP и поздних версий.
    #define WINVER 0x0501		// Измените значение на соответствующую величину текущей версии Windows.
    #endif
    #ifndef _WIN32_WINNT		// Позволяет использовать особенности, характерные для Windows XP и поздних версий.
    #define _WIN32_WINNT 0x0501	// Измените значение на соответствующую величину текущей версии Windows.
    #endif
    #ifndef _WIN32_WINDOWS		// Позволяет использовать особенности, характерные для Windows 98 и поздних версий.
    #define _WIN32_WINDOWS 0x0410 // Измените значение на соответствующую величину текущей версии Windows Me or later.
    #endif
    #ifndef _WIN32_IE			// Позволяет использовать особенности, характерные для  IE 6.0 и поздних версий.
    #define _WIN32_IE 0x0600	// Измените значение на соответствующую величину текущей версии IE.
    #endif
    #define WIN32_LEAN_AND_MEAN		// Не допущение ранее используемого наполнения из заголовка Windows.
    // Заголовочный файл Windows:
    #include <windows.h>
    // Заголовочные файлы C RunTime
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <tchar.h>
    // TODO: разместите дополнительные заголовки модулей, необходимых для Вашего проекта, здесь
    /* WINDOW.h*/
    #pragma once
    #include "resource.h"
    /* WINDOW.cpp */
    // WINDOW.cpp : Определяет точку входа для приложения.
    //
    #include "stdafx.h"
    #include "WINDOW.h"
    #define MAX_LOADSTRING 100
    // Глобальные переменные:
    HINSTANCE hInst;								// текущий экземпляр класса
    TCHAR szTitle[MAX_LOADSTRING];					// Текст главного меню
    TCHAR szWindowClass[MAX_LOADSTRING];			// имя класса главного окна
    // Далее идут объявления функций, включённых в модуль Code:
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
    	// Отмена определения параметров hPrevInstance (предыдущий
    	// Экземпляр приложения) и lpCmdLine (командная строка)
    	UNREFERENCED_PARAMETER(hPrevInstance);
    	UNREFERENCED_PARAMETER(lpCmdLine);
     	// TODO: Поместите свой код здесь.
    	MSG msg;
    	HACCEL hAccelTable;
    	// Инициализация глобальных настроек
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_WINDOW, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
    	// Подготовить инициализацию приложения:
    	if (!InitInstance (hInstance, nCmdShow))
    	{
    		return FALSE;
    	}
    	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOW));
    	// Основной цикл сообщений:
    	while (GetMessage(msg, NULL, 0, 0))
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg))
    		{
    			TranslateMessage(msg);
    			DispatchMessage(msg);
    		}
    	}
    	return (int) msg.wParam;
    }
    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Регистрирует класс окна.
    //
    //  COMMENTS:
    //
    //    Эта функция и её использование необходимо только
    //    в том случае, если Вы хотите, чтобы этот код
    //    был совместим с кодом системы Win32 прежде, чем функция 'RegisterClassEx'
    //   была добавлена в Windows 95. Очень важно использовать эту функцию так
    //    чтобы это приложение давала "правильно оформленными" иконками, ассоциированных с ними
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
    	wcex.cbSize = sizeof(WNDCLASSEX);
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc	= WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance		= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOW));
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_WINDOW);
    	wcex.lpszClassName	= szWindowClass;
    	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    	return RegisterClassEx(wcex);
    }
    //
    //   FUNCTION: InitInstance(HINSTANCE, int)
    //
    //
    //   PURPOSE: Сохраняет экземпляр класса и создаёт основное окно
    //
    //   COMMENTS:
    //
    //        В этой функции мы сохраняем дескриптор экземпляр класса в глобальную переменную и
    //        создаёт и показывает основное окно программы..
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
       hInst = hInstance; // Store instance handle in our global variable
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
       if (!hWnd)
       {
          return FALSE;
       }
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
       return TRUE;
    }
    //
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  PURPOSE:  Обработка сообщений для главного окна.
    //
    //  WM_COMMAND	- обрабатывает меню приложени
    //  WM_PAINT	- Рисует основное окно
    //  WM_DESTROY	- Посылает завершающее сообщение и выход
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;
    	HDC hdc;
    	switch (message)
    	{
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		// Сканирует раздел меню:
    		switch (wmId)
    		{
    		case IDM_ABOUT:
    			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
    			break;
    		case IDM_EXIT:
    			DestroyWindow(hWnd);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, ps);
    		// TODO: Добавьте сюда любой "рисующий" код...
    		EndPaint(hWnd, ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    // Дескриптор сообщения окна About.
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	UNREFERENCED_PARAMETER(lParam);
    	switch (message)
    	{
    	case WM_INITDIALOG:
    		return (INT_PTR)TRUE;
    	case WM_COMMAND:
    		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
    		{
    			EndDialog(hDlg, LOWORD(wParam));
    			return (INT_PTR)TRUE;
    		}
    		break;
    	}
    	return (INT_PTR)FALSE;
    }

    9.9. Приложение № VI

    Примечание: Для создания данного приложения средствами Microsoft Visual Studio 2008 вначале создайте "пустой проект", а затем заполните его этими файлами.

    /* stdafx.cpp*/
    // stdafx.cpp : исходный файл, который включает в себя стандартные заголовочные файлы.
    // textwin.pch будет заголовком предпроцессора
    // stdafx.obj будет содержать информацию предварительной компиляции
    #include "stdafx.h"
    // Поместите сюда всю дополнительную информацию, которая Вам нужна,
    // в этот файл, а ни где-либо
    /* stdafx.h */
    // stdafx.h : заголовочный файл, со стандартными системными заголовочными файлами
    // или специфичные для всего проекта часто используемые заголовочные файлы,
    // но изменяемые не часто
    //
    #pragma once
    #define WIN32_LEAN_AND_MEAN		// Использовать ранее использованный шаблон заголовков Windows
    // Windows Заголовочный файл Windows:
    #include <windows.h>
    // Общие заголовки языка Си
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <tchar.h>
    // TODO: Укажите здесь дополнительные заголовочные файлы
    // для Вашей программы
    /* textwin.h */
    #pragma once
    #include "resource.h"
    /* textwin.cpp*/
    // textwin.cpp : Определение точек входа в программу.
    //
    #include "stdafx.h"
    #include "textwin.h"
    #define MAX_LOADSTRING 100
    // Файлы с описанием функций
    #ifndef __STDIO_H
    #include <stdio.h>
    #endif
    #ifndef __STRING_H
    #include <string.h>
    #endif
    /* Глобальные константы */
    // Задание максимальной длины символьного буфера строки
    // для вывода в окно
    #ifndef SCREEN_BUFSIZE
    #define SCREEN_BUFSIZE	80
    #endif
    // Прототип функции для печати строки символов
    void Print(HDC, char *, int);
    void PrintLn(void);
    /* Глобальные переменные */
    /**********************************************************
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
    **********************************************************/
    static int cxChar, cyChar;
    static int cxCurrentPosition;
    static int cyCurrentPosition;
    // Global Variables:
    HINSTANCE hInst;								// current instance
    TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
    // Далее находятся описания функций, включённых в модули кода
    ATOM				MyRegisterClass(HINSTANCE hInstance);
    BOOL				InitInstance(HINSTANCE, int);
    LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
     	// TODO: Поместите код здесь
    	MSG msg;
    	HACCEL hAccelTable;
    	// Инициализация глобальных строк
    	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    	LoadString(hInstance, IDC_TEXTWIN, szWindowClass, MAX_LOADSTRING);
    	MyRegisterClass(hInstance);
    	// Подготовка к инициализации приложения:
    	if (!InitInstance (hInstance, nCmdShow))
    	{
    		return FALSE;
    	}
    	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TEXTWIN);
    	// Основной цикл сообщений:
    	while (GetMessage(msg, NULL, 0, 0))
    	{
    		if (!TranslateAccelerator(msg.hwnd, hAccelTable, msg))
    		{
    			TranslateMessage(msg);
    			DispatchMessage(msg);
    		}
    	}
    	return (int) msg.wParam;
    }
    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Регистрация класса окна.
    //
    //  COMMENTS:
    //
    //    Эта функция и её использование необходима только
    //    в том случае, если Вы хотите, чтобы этот код
    //    был совместим с кодом системы Win32 прежде, чем функция 'RegisterClassEx'
    //    была добавлена в Windows 95. Очень важно использовать эту функцию так
    //    чтобы это приложение давала "правильно оформленными" иконками, ассоциированных с ними
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wcex;
    	wcex.cbSize = sizeof(WNDCLASSEX);
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    	wcex.lpfnWndProc		= (WNDPROC)WndProc;
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hInstance			= hInstance;
    	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_TEXTWIN);
    	wcex.hCursor			= LoadCursor(NULL, IDC_ARROW);
    	wcex.hbrBackground		= (HBRUSH)(COLOR_WINDOW+1);
    	wcex.lpszMenuName		= (LPCTSTR)IDC_TEXTWIN;
    	wcex.lpszClassName		= szWindowClass;
    	wcex.hIconSm			= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
    	return RegisterClassEx(wcex);
    }
    //
    //   FUNCTION: InitInstance(HANDLE, int)
    //
    //   PURPOSE: Сохраняет экземпляр класса и создаёт основное окно
    //
    //   COMMENTS:
    //
    //        В этой функции мы сохраняем дескриптор экземпляр класса в глобальную переменную и
    //        создаём и показываем основное окно программы..
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;
       hInst = hInstance;	// Сохраняем дескриптор экземпляра класса 			// в нашу глобальную переменную
       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
       if (!hWnd)
       {
          return FALSE;
       }
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
       return TRUE;
    }
    //
    //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
    //
    //  PURPOSE:  Обработка сообщений для главного окна.
    //
    //  WM_COMMAND	- обрабатывает меню приложени
    //  WM_PAINT	- Рисует основное окно
    //  WM_DESTROY	- Посылает завершающее сообщение и выход
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	int wmId, wmEvent;
    	PAINTSTRUCT ps;        // структура для рисовани
    	HDC hdc;               // индекс контекста устройства
        static TEXTMETRIC tm;  // структура для записи метрик
                               // шрифта
    	switch (message)
    	{
        case WM_CREATE:
        {
          // Получаем контекст отображения,
          // необходимый для определения метрик шрифта
          hdc = GetDC(hWnd);
          // Заполняем структуру информацией
          // о метрике шрифта, выбранного в
          // контекст отображени
          GetTextMetrics(hdc, tm);
          // Запоминаем значение ширины дл
          // самого широкого символа
          cxChar = tm.tmMaxCharWidth;
          // Запоминаем значение высоты букв с
          // учётом межстрочного интервала
          cyChar = tm.tmHeight + tm.tmExternalLeading;
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
          // Освобождаем контекст
          ReleaseDC(hWnd, hdc);
          return 0;
        }
    	case WM_COMMAND:
    		wmId    = LOWORD(wParam);
    		wmEvent = HIWORD(wParam);
    		// Сканируем секцию меню:
    		switch (wmId)
    		{
    		case IDM_ABOUT:
    			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
    			break;
    		case IDM_EXIT:
    			DestroyWindow(hWnd);
    			break;
    		default:
    			return DefWindowProc(hWnd, message, wParam, lParam);
    		}
    		break;
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, ps);
    		// TODO: Добавляем код для рисования здесь...
          // Инициализируем текущую позицию
          // вывода текста
          cxCurrentPosition = cxChar;
          cyCurrentPosition = cyChar;
    	  // Выводим последовательно строки:
          Print(hdc, "Первая строка", 0); PrintLn();
          Print(hdc, "Вторая строка", 0); PrintLn();
          Print(hdc, "Третья строка( смещённая )", 10); PrintLn();
    		EndPaint(hWnd, ps);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    // Дескриптор диалогового окна сообщения: About.
    LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	switch (message)
    	{
    	case WM_INITDIALOG:
    		return TRUE;
    	case WM_COMMAND:
    		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
    		{
    			EndDialog(hDlg, LOWORD(wParam));
    			return TRUE;
    		}
    		break;
    	}
    	return FALSE;
    }
    /**********************************************************
     * Функция Print
     * Функция предназначена для вывода текста
     * в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * HDC hdc -- индекс контекста устройства;
     * char *str -- указатель на выводимую строку;
     * int iOFFSET -- смещение горизонтальной позиции
     * вывода текста в окно, указанное в символах;
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void Print(HDC hdc, char *str, int iOFFSET )
    {
      char buf[SCREEN_BUFSIZE];
      int i;
    /* Проверяем смещение на неравенство единице
       и корректируем его */
      if( iOFFSET < 0 ) iOFFSET = 0;
      // Подготавливаем в рабочем буфере
      i = strlen(str);
      // Проверка, что строка умещается в буфере
      if( i < SCREEN_BUFSIZE - 1 )
      // и выводим строку в зависимости от проверки
    	sprintf(buf, "%s", str);
      else
    	sprintf(buf, "%.*s", SCREEN_BUFSIZE-1, str);
      // Выводим текст в окно, начиная с текущей позиции
      // вывода текста + смещение в максимальном
      // количестве символов
      TextOut(hdc,
        cxCurrentPosition + iOFFSET * cxChar,
        cyCurrentPosition,
        buf, i);
    }
    /**********************************************************
     * Функция PrintLn
     * Функция предназначена для перевода на новую строку
     * при выводе в окно.
     *
     * ВХОДНЫЕ ЗНАЧЕНИЯ:
     * Не имеет.
     *
     * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ:
     * cxChar -- значение ширины для самой широкой литеры
     * cyChar -- max высота литеры с учётом междустрочного
     *           интервала.
     * cxCurrentPosition -- текущая гориз. позиция вывода текста
     * cyCurrentPosition -- текущая верт. позиция вывода текста
     *
     * ФУНКЦИЯ ВОЗВРАЩАЕТ:
     * 	Возвращаемых значений нет.
     *
     * ПРИМЕЧАНИЕ:
     * Эта функция может быть переписана Вами под Ваши
     * нужды для вывода не только текста, но и числовых
     * значений, а также для форматирования в строке вывода.
     *
    **********************************************************/
    void PrintLn( void )
    {
      // Увеличиваем текущую позицию по
      // вертикали на высоту символа
      cyCurrentPosition += cyChar;
    }
    Вернуться к учебному плану