Действительно, что такое «приложение» в Windows? Универсальная модель приложения Microsoft отвечает на этот вопрос

Это удивительно, но у Windows никогда не было определения приложения. «Вы знаете об этом, когда видите, но это никогда не записывается», — сказал Эндрю Клиник, менеджер групповых программ в Microsoft, во время своей сессии в Build 2016. На самом деле ничего не было определено, но за эти годы было множество рекомендаций. По словам Microsoft, на самом деле было очень сложно создать модель приложения, и она не была реально применена.

Модель универсального приложения для Windows
Если мы пытаемся проследить путь, мы знаем, что все началось с .exe, но у нас никогда не было ответов на вопрос, как его установить, как сохранить состояние, как долго работает приложение, как вы интегрируетесь с ним. ОС или с другими приложениями и так далее и тому подобное.
Вот почему нам нужна модель приложения, а модель приложения универсальной платформы Windows (UWP) пытается ответить на эти вопросы.
Универсальная модель приложений Windows унифицирована для всех устройств Windows, масштабируясь от IoT до Mobile, от ПК до Xbox и Hololens. Он определяет полный жизненный цикл приложения для всех приложений в Windows, от колыбели до могилы: установка, среда выполнения, управление ресурсами, обновление, модель данных и удаление.
Проект Столетие
Хотя модель приложения включает в себя все приложения, работающие в Windows, и ориентирована на универсальные приложения Windows, разработчики должны запускать существующие приложения, будь то телефоны, Windows 8.1 или классическая Windows. Project Centennial позволяет разработчикам преобразовывать классические приложения Windows в универсальные приложения Windows и стремится определить модель приложения для классических приложений Windows, поскольку до сих пор не было систематического определения приложения в Windows.
Вы можете быть удивлены, почему сейчас нужна модель приложения для рабочего стола. Подавляющее большинство проблем заключается в росте и фрагментации реестра. Ваш компьютер все больше и больше накапливается в реестре и файловой системе, что приводит к гниению Windows. Кроме того, как испытал каждый из нас — потребители и разработчики — практически 100% удаление практически невозможно. Вы остаетесь с файлами и реестром мусора и других битов по всей вашей системе.
Современный установщик программного обеспечения
В 2015 году Microsoft представила .appX как общий установочный пакет для приложений UWP, позволяющий ПК, телефону, HoloLens и IoT использовать одну и ту же технологию. В настоящее время Microsoft расширяет технологию установки, чтобы сделать ее еще более доступной для существующих настольных приложений и Xbox. Ноябрьский выпуск 2015 года расширен, где вы можете использовать .appX, и по умолчанию включил установку из любого места, а не только из Магазина Windows. До этого вы могли загружать файлы из любой точки мира, но для этого требовались специалисты по PowerShell.
Цель Microsoft — сделать .appX лучшим установщиком в экосистеме Windows. Хотя MSI почти наверняка не исчезнет в ближайшее время, новая модель приложения позволяет вам добавить в ваши приложения новый набор функций — таких как интеграция в Cortana и другие приложения — при этом внося свой код без каких-либо существенных изменений.
На Build 2016 Microsoft объявила, что компания инвестирует в то, чтобы сделать современный установщик де-факто установочным стеком для Windows. На данный момент он не обладает всеми возможностями MSI или ClickOnce, но идея состоит в том, чтобы со временем улучшаться. Это обеспечит полноценную платформу для создания возможностей установки, предоставляя отличные возможности установки как из Магазина Windows, так и из пользовательских каналов распространения, позволяя конвертировать настольные приложения для установки и включая платформу расширений.
Нижняя линия
С Windows 10 Microsoft переворачивает новый лист, а модель приложения универсальной платформы Windows обеспечивает целостность экосистемы Windows на всех устройствах. Он определяет четкую модель развертывания и предоставляет лучший способ установки / удаления и обновления приложения. Хотя это улучшает гигиену приложений и потребители получают выгоду от ожидаемого поведения приложений и привычного взаимодействия с пользователем, оно также помогает поддерживать работоспособность Windows и предотвращать гниение со временем.
Первое знакомство
Данный раздел называется “первое знакомство”. Здесь вы действительно познакомитесь с первым приложением для Windows. Но не думайте, что это знакомство только с простейшим приложением. Здесь вы познакомитесь с некоторыми основными идеями, заложенными в системы типа Windows, а также с их влиянием на работу (и написание) приложений. Простейшее приложение оказывается лишь поводом для серьезного знакомства с целым классом систем.
Не ищите здесь подробных обсуждений тех или иных вопросов — здесь будут встречаться только обзоры, а более полные сведения вы сможете найти в последующих разделах. Такая структура принята потому, что программирование в Windows требует использования функций и инструментов из самых разных подсистем, так что последовательное рассмотрение Windows API практически невозможно.
Так, например, даже в простейшем приложении надо осуществлять вывод данных в окно. Для этого необходимо изучить графический интерфейс устройств (GDI) и контекст устройства. Но для этого надо уже быть знакомым с диспетчером памяти, с описанием ресурсов приложения, с использованием стандартных диалогов, с обработкой сообщений и многим другим. При рассмотрении любого из перечисленных пунктов пришлось бы ссылаться на другие разделы, в том числе на тот же графический интерфейс.
Такие разные операционные системы
Сразу оговоримся — в Windows возможно запускать приложения (application) двух разных типов — приложения Windows и приложения MS – DOS. Методы разделения ресурсов, применяемые этими приложениями существенно различаются, как различаются и методы доступа к ресурсам. В этой ситуации мы будем, говоря о приложении вообще, подразумевать приложение Windows. Если разговор зайдет о приложениях MS – DOS, то это будет оговорено отдельно.
Рассматривая работу приложения в среде Windows надо отталкиваться от того факта, что Windows является многозадачной средой. В этом случае в системе может выполняться одновременно 1 несколько разных приложений. Каждое приложение для своей работы требует некоторых ресурсов системы — дискового пространства, оперативной памяти, времени процессора, устройств ввода и вывода информации и пр. Соответственно Windows должен выполнять функции арбитра, осуществляющего разделение ресурсов между приложениями и контролирующего корректность работы приложений с выделенными им ресурсами.
С этой точки зрения можно рассмотреть развитие операционных систем, начиная от простейших (типа MS – DOS) и заканчивая достаточно сложными (как Windows NT, Unix, OpenVMS), для того что бы лучше понять возможности и ограничения разных реализаций Windows.
Простейшие однопользовательские однозадачные операционные системы являются, одновременно, примитивными арбитрами. Операционная система предоставляет набор средств для выполнения тех или иных операций по работе с ресурсами и организует запуск приложений. При этом приложению передается управление и система ожидает, пока оно завершит работу. Во время работы это приложение может обращаться к системе для получения ресурсов, а может это делать и в обход системы. Корректность работы приложения никак не контролируется — система только лишь предоставляет примитивный, часто неоптимальный и необязательный метод доступа к ресурсу. Приложение пользуется всеми ресурсами практически без ограничений (за исключением тех, которые заняты самой системой) и имеет непосредственный доступ к аппаратуре компьютера.
Такой подход типичен для операционных систем небольших компьютеров: сравнительно слабая поддержка периферийных устройств, простая файловая система и уникальная открытость, почти вседозволенность для приложений — так как конфликтовать им не с кем. Яркий пример — MS DOS первых версий.
Практически такие операционные среды мало применимы и, если система оказалась удачной, то она начинает развиваться в сторону поддержки многозадачного режима. Более того — обработка прерываний в однозадачной системе — неизбежный “многозадачный минимум”. Резидентная программа в однозадачной среде — еще одна попытка приближения к многозадачности. Те, кто пытался создать сколько – нибудь сложную резидентную программу обязательно сталкивался с трудностями разделения ресурсов, так как эффективных механизмов для этого однозадачные ОС не содержат. А благодаря своей открытости такие системы оказались благодатной почвой для развития вирусов.
Наиболее мощными представляются многозадачные, многопользовательские ОС, особенно в мультипроцессорных системах. Работа такой системы основана на параллельном исполнении нескольких приложений. Приложение может выполняется либо на отдельном процессоре, либо в режиме разделения времени — в определенные временные интервалы.
Приложение не знает, и практически не наблюдает присутствия и выполнения других приложений. Все проблемы бесконфликтного разделения ресурсов между разными задачами лежат на системе. Приложение не знает, в какой момент времени ее выполнение будет прервано, не знает когда будет возобновлено и вообще не регистрирует факта прерывания. Для одной задачи процесс выполнения представляется непрерывным.
Многопользовательские многозадачные системы обычно встречаются на более производительных компьютерах, при этом они содержат мощные средства взаимодействия с периферией, практически исключающие необходимость доступа приложений непосредственно к аппаратуре. Кроме того операционная система имеет очень гибкую и эффективную систему распределения ресурсов, привилегий и пределов доступа ко всем ресурсам компьютера, а также содержит средства защиты от несанкционированного доступа к ним. В качестве примеров можно привести OpenVMS, Unix, в несколько меньшей мере Windows NT (реализована для персонального компьютера).
Однако такие удобные и мощные ОС часто не имеет смысл реализовывать на персональном компьютере для которого (по идее его использования) не нужна многопользовательская система, и поэтому его открытость далеко не всегда является уязвимостью, но часто даже повышает эффективность его использования. Понятно также, что с ростом мощности персонального компьютера, появляется необходимость создания простых многозадачных ОС, ориентированных на работу одного пользователя.
Такая система занимает промежуточное положение между однозадачной и многопользовательской многозадачной системами. Очевидно, что ее ядро будет обладать большей открытостью, большей возможностью доступа к аппаратуре и относительно простыми методами разделения ресурсов, чем в сложных системах.
В качестве иллюстраций к этому можно привести Windows 3.x, разделение ресурсов в которой в значительной мере основано на методах MS – DOS, а также Windows – 95, которая занимает промежуточное положение между Windows NT и Windows 3.x, предоставляя существенно упрощенные методы доступа к ресурсам, чем Windows NT и, в то же время, обеспечивая качественно лучшую защиту, чем Windows 3.x.
Краткие сведения о разделении ресурсов в Windows
Для того, что бы Windows мог успешно разделять ресурсы, на разрабатываемые программы накладывают ряд требований 2 . Понятно, что первым таким требованием является требование не использования аппаратуры непосредственно. Вы можете использовать только средства Windows для выполнения всех своих задач, но не осуществлять доступ к аппаратуре непосредственно.
Например, приложение не должно обращаться к видеопамяти, средствам BIOS и т.д. Если приложение должно вывести на дисплей какое – либо изображение оно обязано воспользоваться существующими функциями Windows.
Конечно, ограничение на доступ к аппаратуре — не самое приятное ограничение, но оно имеет и свою оборотную, причем приятную, сторону: пользователь (и разработчик) может не думать о том, с чем конкретно он имеет дело — об этом заботиться Windows. То есть Windows сам обеспечивает выполнение всех требуемых операций на имеющемся оборудовании, причем используя практически все возможности этого оборудования.
Интересно обзорно рассмотреть методы разделения основных ресурсов компьютера между задачами, принятыми в Windows, и влияние этих методов на правила написания программ. Причем для первого знакомства отталкиваться мы будем от наиболее простой системы — Windows 3.x.
К основным разделяемым ресурсам несомненно относятся дисплей, клавиатура, мышь, оперативная память, процессор и диск. Стоит коротко отметить методы разделения каждого из этих ресурсов.
Дисплей
Для разделения дисплея между разными задачами в Windows используются окна (window). Каждой задаче назначено, по меньшей мере, одно окно, и осуществлять вывод приложение может (точнее должно) только в это окно.
Приложение может обладать несколькими окнами. В этом случае, обычно, одно окно является родительским (parent), а другие являются дочерними (child) окнами по отношению к родительскому окну. Как правило, приложение имеет только одно окно, не имеющее родителей — это так называемое главное окно приложения (main window). Все остальные окна приложения являются дочерними по отношению к этому окну.
Окна могут перемещаться по экрану, перекрывая полностью или частично другие окна. Окна могут находиться в максимизированном (“распахнутом” на весь экран, maximized, zoomed), нормальном или минимизированном (minimized, iconed) состоянии. В минимизированном состоянии окно заменяется на специальную небольшую картинку, называемую пиктограммой (иконой, icon), либо помещается в специальный список окон (taskbar или systray для Windows – 95 и Windows NT 4.0).
Основная логика использования перекрывающихся окон реализована в Windows, хотя программистам остается достаточно много работы — приложение вынуждено перерисовывать окно каждый раз, когда возникает в этом необходимость (например, при увеличении размеров окна, если ранее скрытое окно становится видимым и в других случаях).
То, что не вся работа по перерисовке перекрывающихся окон выполняется системой, связано с использованием графического режима отображения окон. Для полной автоматизации необходимо было бы “виртуализовать” всю работу с окнами — то есть в обычной оперативной памяти должна находиться копия изображения окна. Тогда Windows мог бы полностью или частично восстанавливать изображение при появлении ранее невидимой части окна по этой копии. Однако общий размер нескольких копий (для каждого окна своя копия) может быть сопоставим с объемом всей оперативной памяти компьютера. Скажем для режима 1280×1024, 16 бит/пиксель (это далеко не самый хороший) битмап экрана занимает примерно 2.5MB. Кроме того, размер окна может быть больше экрана и таких окон может быть несколько. Таким образом Windows практически не может использовать виртуальные окна — ресурсов компьютера для этого явно не хватает (их еще надо разделять с выполняемыми приложениями и с компонентами самой системы).
Строго говоря, окно в Windows является тем самым объектом, для которого частично реализован объектно – ориентированный подход. Интересно, что в документации Windows термин “объект” никогда не применяется к окну, а то, что называется “объектами”, ни в коей мере не является объектами ООП.
Клавиатура и мышь
Эти устройства относятся к устройствам ввода данных. Разделение этих устройств между разными задачами легко можно разбить на два круга вопросов:
- определение, к какой задаче относятся данные, полученные от устройства ввода.
- передача полученных от устройства данных требуемой задаче.
Для мыши определение, к какой задаче относятся данные, вполне очевидно: так как каждая задача имеет по крайней мере одно окно, то информация от мыши должна использоваться окном, на фоне которого находится курсор мыши.
Для клавиатуры дело обстоит несколько сложнее: нам придется ввести понятие активное окно (active window). В данный момент времени обязательно существует только одно активное окно, это окно выделяется цветом заголовка, рамки или подписи (если окно минимизировано). Активное окно является пользователем клавиатуры в данный момент времени. Для того, что бы другая задача могла получать данные, необходимо сделать активным окно, принадлежащее этой задаче.
Передача полученных от устройства данных требуемой задаче. Хотя интуитивно кажется, что здесь не должно быть особых сложностей, но именно здесь очень ярко проявляются особенности организации Windows. Мы к этому вернемся, рассматривая метод разделения процессора.
Для разделения дискового пространства используется файловая система. Здесь Windows 3.x просто пользуется уже имеющимся — файловой системой DOS; Windows – 95 использует слегка модернизированную файловую систему DOS (поддерживаются имена файлов длиной до 256 символов и возможно использование так называемого FAT32 вместо FAT16 или FAT12). И только Windows NT предоставляет собственную файловую систему — NTFS, хотя может работать и с FAT. NTFS отличается от FAT существенно более сложной организацией, позволяющей создавать единые тома из нескольких дисков, организовывать зеркальные тома или тома с избыточностью для хранения важных данных, а также задавать права доступа к отдельным файлам конкретным пользователям. Естественно, более сложная система оказывается более чувствительной к сбоям (несмотря на специально принятые меры) и менее производительной (несмотря на специальную оптимизацию).
Для доступа к файлам Windows предоставляет свои собственные функции. В случае Windows 3.x эти функции в основном соответствуют функциям DOS для доступа к файлам и разделения доступа. Для нормальной работы Windows надо устанавливать программу SHARE.EXE до запуска Windows 3.1, либо, в случае Windows 3.11, будет использован специальный компонент Windows — VSHARE.386. Более того, по версию Windows 3.0 включительно, имел место любопытный нюанс: Windows имел собственную функцию для открытия файлов (OpenFile), но совершенно не предоставлял средств для чтения/записи — они были просто не декларированы, хотя внутри самого Windows содержались. Программисту рекомендовалось либо применять функции Run – Time библиотеки принятого языка (что можно было делать лишь ограниченно), либо написать свои процедуры на ассемблере. Либо, что делалось гораздо чаще, использовать не декларированные функции Windows для работы с файлами. С тех пор Microsoft просто декларировал эти функции.
Для приложений, работающих в Win32 про функции DOS надо просто забыть — Win32 предоставляет более богатый набор операций над файлами, поддерживает работу с разными файловыми системами 3 а, кроме того, исключает возможность применения прерываний DOS.
Память
Реализация методов разделения памяти в Windows API и Win32 API качественно различаются. Для этого придется рассмотреть историю развития диспетчера памяти, что будет сделано позже. Сейчас надо обратить внимание только на некоторые общие идеи разделения памяти.
В обоих API память делится на отдельные блоки. Однако деление осуществляется совершенно разными методами.
Windows API
Коротко можно отметить, что вся доступная для Windows память называется глобальной (иногда глобальный хип, глобальная куча, global heap). Эта глобальная память делится на отдельные блоки, которые могут быть перемещаемыми в памяти. В виде блоков глобальной памяти в Windows представляются даже программы — в этом случае каждому программному сегменту соответствует один блок глобальной памяти.
Сегмент данных программы, представленный в виде блока глобальной памяти, может содержать свою локальную кучу (локальный хип, local heap). Эта память также может делиться на блоки, называемыми локальными. Термин локальный применяется к памяти, если она принадлежит сегменту данных программы.
Windows предоставляет программные средства для манипуляции с блоками обоих видов — и глобальными, и локальными. Каждый блок может быть фиксированным, перемещаемым или удаляемым в/из памяти. Это обеспечивает возможность как выделения больших непрерывных блоков данных (за счет перемещения других блоков), так и возможность удаления части блоков при недостатке памяти.
Win32 API
В Windows – 95 и в Windows NT используется так называемая виртуальная память. Для каждого запущенного приложения выделяется собственное адресное пространство, размером 4Г, которым приложение владеет монопольно. В этом пространстве не находится никаких данных или кода других приложений. Таким образом приложения Win32 изолированы друг от друга. Необходимо учесть, что “адресное пространство” не соответствует реально выделяемой памяти — это тот диапазон адресов, в котором может размещаться память, реально выделенная приложению. Очевидно, что из возможных 4Г адресного пространства используются обычно только несколько мегабайт, занимаемые кодом и данными приложения и необходимыми компонентами системы.
Адресное пространство приложения делится на отдельные фрагменты, содержащие код, данные, служебную информацию и пр., необходимые для этого приложения. Однако такое деление статично — перемещение фрагментов в адресном пространстве не происходит. Оптимизация доступа к памяти осуществляется не с помощью перемещения блоков или их удаления, а с помощью механизма отображения виртуального адресного пространства на физически доступную память компьютера (упрощенно можно считать, что виртуальное адресное пространство приложения — это специальный файл подкачки страниц; оперативная память при этом выполняет роль кэша, в котором находятся только активно используемые код и данные).
Помимо этого в адресном пространстве приложения могут выделяться одна или несколько куч (хипов), разделяемых на отдельные блоки. Вот эти – то блоки могут перемещаться внутри своей кучи и даже удаляться из памяти. Сама куча в адресном пространстве приложения перемещаться не будет. Для каждого приложения выделяется по меньшей мере одна куча, называемая стандартной (default heap). Все функции Windows API, работающие с глобальной или локальной кучами перенесены в Win32 API так, что они работают именно с этой стандартной кучей. При этом нет никакой разницы между глобальной и локальной кучами.
Процессор
Выше, при рассмотрении разных типов операционных систем, было выделено два “чистых” типа систем: однопользовательские однозадачные и многопользовательские многозадачные. Windows во всех его версиях занимает некоторые промежуточные положения между двумя этими крайними типами. Так версии Windows 3.x приближаются к простейшему типу однопользовательских однозадачных систем (с очень ограниченной реализацией некоторых возможностей как многопользовательской работы, так и многозадачного режима), а наиболее сложная Windows NT является истинно многозадачной системой с развитыми средствами разделения доступа пользователей.
Windows API и объектно – ориентированное программирование
Методы разделения процессора, применяемые разными реализациями Windows, интересно рассмотреть в их развитии — от простого к сложному. Так в идеальной однозадачной среде, приложение, раз начавшись, выполняется без перерывов до полного завершения. В истинно многозадачной среде приложение выполняется за много шагов, причем само приложение не знает, когда его прервут для обработки других приложений — этим ведает только система 4 .
Промежуточным решением является среда, получившая название псевдомногозадачной (невытесняющая многозадачность, non – preemptive multitasking). В такой среде, подобно однозадачной, система не прерывает выполнения приложения. Однако само приложение должно быть разделено на небольшие, быстро выполняемые фрагменты. После выполнения такого фрагмента система может перейти к выполнению другого приложения. При этом приложение само уведомляет систему, где ее можно прервать для выполнения других задач.
В Windows 3.x это может быть реализовано двумя разными методами:
- обычно приложение разбивается на набор небольших, быстро выполняемых функций. В этом случае система просто вызывает нужные функции для выполнения требуемых задач. После завершения обработки одной функции система может вызвать другую функцию другого приложения, осуществляя таким образом выполнение нескольких приложений как – бы одновременно.
- можно воспользоваться специальной функцией, передающей управление системе, и возвращающей его назад приложению после обработки других приложений. Таких функций в Windows 3.x две — Yield и DirectYield. Однако этот путь используется в очень специальных случаях, например при разработке отладчиков, из – за довольно жестких ограничений на применение этих функций.
При написании нормальных приложений для Windows 3.x разбиение программы на отдельные функции производится не механически, скажем через 100 строк, а функционально — каждая функция выполняет определенные действия. При этом система, вызывая соответствующую функцию, передает ей некоторые данные, которые указывают, что надо сделать.
Это очень важный момент.
До сих пор все программы состояли из алгоритма, управляющего данными. На практике это означало, что алгоритм, описывающий программу, предусматривал когда, где и в какой мере возможно получение данных и управляющих воздействий, и как и куда направлять вывод результатов.
Например, при необходимости ввода данных с клавиатуры, программа включала в себя вызов к операционной системе (или BIOS, на худой конец), который и возвращал требуемые данные.
Еще раз: обычная программа генерирует вызовы к операционной среде для получения и вывода данных: алгоритм управляет данными
В рассмотренном нами случае получается совершенно иная ситуация: поступающие от системы данные управляют поведением программы. Часто такими данными являются управляющие воздействия пользователя (например, изменение размеров окна, вызов меню и др.). Эти воздействия, вообще говоря, не синхронны с работой вашей программы, то есть получается, что данные управляют алгоритмом — один из основных принципов объектно – ориентированного программирования (ООП).
Введем новые понятия:
- данные, передаваемые от системы к соответствующей функции называются сообщением (message).
- процесс обращения к требуемой функции называется посылкой (post) или передачей (send) сообщения.
- функция, обрабатывающая сообщения, называется процедурой обработки сообщений (message handler).
Таким образом, когда вы создаете программу, работающую в псевдомногозадачной среде (здесь: Windows 3.x), вы должны написать требуемые процедуры обработки сообщений. Далее Windows будет передавать вашим процедурам сообщения для их обработки.
С точки зрения ООП все объекты должны обладать 3 мя свойствами:
инкапсуляция — объединение в единое целое алгоритмов и необходимых данных;
наследование — возможность порождения новых объектов, основываясь на существующих, наследуя их свойства;
полиморфизм — разность реакций на одинаковые воздействия; наследники одного объекта могут отличаться своими свойствами друг от друга и от предка.
С точки зрения этих свойств объект, определенный процедурой обработки сообщений, удовлетворяет всем этим требованиям. Процедура обработки сообщений может пользоваться специфичными, сгруппированными в каких – либо структурах, данными (инкапсуляция). Мы можем создавать новый объект со своей процедурой обработки сообщений, которая может ссылаться на процедуру ранее описанного объекта (наследование), а также выполнять обработку дополнительных сообщений или иначе обрабатывать прежние сообщения (полиморфизм).
Обычно говорят, что процедура обработки сообщений определяет свойства объекта, так как задает реакцию этого объекта на воздействия (сообщения). Именно с такой трактовкой объекта возникли первые языки ООП.
В Windows объектом ООП является окно. Соответственно говорят, что сообщения направлены не процедуре, а окну. Процедура обработки сообщений определяет окно с конкретными свойствами, даже больше — одна процедура может обслуживать несколько разных окон, но тогда эти окна будут иметь одинаковую реакцию на одинаковые воздействия. То есть процедура обработки сообщений определяет не одно окно, а целый класс (class) окон.
Сообщения, которые Windows направляет окну, отражают то, что происходит с этим окном. Например, есть сообщения, информирующие об изменении размеров окна, или о перемещении мыши, или нажатии на клавишу и др. Передача сообщений является механизмом разделения многих ресурсов, не только процессора. Так, с помощью одних сообщений, реализовано разделение мыши или клавиатуры между задачами, другие сообщения, получаемые окном, помогают осуществить разделение дисплея и т.д.
Таким образом псевдомногозадачный метод разделения процессора оказался основой для построения объектно – ориентированной среды и попутно перевернул всю привычную нам философию написания программ — мы теперь создаем не управляющий алгоритм, а набор процедур, обеспечивающий реакцию нашего окна (то есть нашей программы) на внешние события.
Обработка сообщений является очень распространенным способом организации ООП – библиотек или ООП – языков. Существенное отличие (причем не в лучшую сторону) Windows 3.x заключается в том, что обработка сообщений является методом разделения процессора в псевдомногозадачной среде. Так как система не прерывает выполнение приложения в процессе обработки сообщения, то его обработка не должна занимать много времени
Это сильно затрудняет применение Windows 3.x для расчетных задач — либо мы должны их выполнить быстро, либо разбить на быстро выполняемые части, и понемногу обрабатывать по мере получения сообщений. Понятно, что обычно приходится разбивать на части, а это существенно замедляет вычисления. Вообще говоря, при обработке сообщения лучше укладываться в интервал менее 1 секунды, что бы задержка в реакции Windows на управляющие воздействия не была очень большой; критичной является задержка порядка 1 – 2 минуты — при этом Windows 3.x может просто дать сбой или зависнуть (что очень сильно зависит от наличия других работающих приложений).
Win32 API
В более сложном Win32 API применяется так называемая истинная многозадачность (вытесняющая, preemptive multitasking). В этом случае разделение процессора осуществляется по определенным временным интервалам (квантам времени). Обработка сообщений перестала быть методом разделения процессора, и в процессе обработки сообщения система может передавать управление другим приложениям. Сама же идея применения объектно – ориентированного подхода к окнам осталась неизменной.
Однако надо отметить, что реализация истинной многозадачности оказалась неполной. В рамках Win32 API могут работать как настоящие Win32 приложения, так и их 16 ти разрядные собратья, написанные для Windows API. При запуске таких 16 ти разрядных приложений под Win32 для них запускается специальная виртуальная 16 ти разрядная Windows – машина, причем в Windows – 95 для всех 16 ти разрядных приложений используется одна общая виртуальная машина. Это значит, что истинная многозадачность реализована только между Win32 приложениями, в то время как 16 ти разрядные приложения между собой используют обработку сообщений для разделения отведенного им процессорного времени. В случае Windows NT для каждого 16 ти разрядного приложения запускается собственная Windows – машина, что позволяет им разделять процессор общим способом с приложениями Win32.
Истинная многозадачность в Win32 позволила реализовать так называемые многопотоковые приложения (multithread application). При этом выделяют два новых понятия — процесс (proccess) и поток (thread). Процессы в Win32 API примерно эквивалентны приложениям в Windows API. Для каждого процесса выделяются определенные системные ресурсы — адресное пространство, приоритеты и права доступа к разделяемым ресурсам и прочее, но не процессорное время. Процесс только лишь описывает запущенную задачу, как она есть, без непосредственных вычислений. Для разделения процессора используются не процессы, а потоки, которым и выделяется процессорное время. В рамках каждого процесса выделяется свой поток, называемый первичным (primary thread), создаваемый по умолчанию при создании процесса. При необходимости в пределах одного процесса может быть создано много потоков, конкурирующих между собой (и с потоками других процессов) за процессорное время, но не за адресное пространство.
Как написать приложение для Windows
Пока мы рассмотрели только основную идею использования сообщений для реализации объектно – ориентированной операционной среды. Сейчас надо перейти к особенностям организации приложения, работающего в такой среде.
Каждое приложение открывает по меньшей мере одно окно (в принципе могут существовать приложения вообще без окон, но как небольшие специализированные процедуры, не требующие никакого управления). Свойства окна определяются процедурой обработки сообщений этого окна. Таким образом, что бы определить свойства нужного окна, надо написать процедуру обработки сообщений, посылаемых этому окну (оконную процедуру или оконную функцию — window procedure, она же процедура обработки сообщений, message handler).
Одна процедура может обслуживать сообщения, посылаемые разным окнам с одинаковыми свойствами. Говорят, что окна, имеющие одну и ту же оконную функцию, принадлежат к одному классу окон. Вы должны эту процедуру зарегистрировать — это называется регистрацией класса окон.
Далее необходимо предусмотреть средства для создания и отображения окна зарегистрированного класса. С таким окном пользователь будет работать — передвигать его по экрану, изменять размеры, вводить текст и т.д. Вам необходимо обеспечить реакцию этого окна (то есть вашего приложения) на действия пользователя. Фактически вы должны запустить механизм, обеспечивающий доставку сообщений, адресованных вашему окну, до получателя — оконной процедуры. Этот механизм должен работать, пока работает ваше приложение. Такой механизм называется циклом обработки сообщений (message loop).
Таким образом вы должны выполнить несколько шагов для создания собственного приложения:
- написать оконную функцию;
- зарегистрировать эту функцию (класс) в Windows, присвоив классу уникальное имя;
- создать окно, принадлежащее данному классу;
- обеспечить работу приложения, организовав цикл обработки сообщений.
Чуть подробнее рассмотрим, что происходит с приложением за время его “жизни” — от запуска до завершения — перед тем, как перейдем к рассмотрению конкретного примера.
Когда вы запускаете приложения для Windows, система сначала находит исполняемый файл и загружает его в память. После этого приложение осуществляет инициализацию необходимых объектов, регистрирует необходимые ему оконные классы, создает нужные окна. можно считать, что, начиная с этого момента, приложение способно нормально взаимодействовать с пользователем и необходимым образом реагировать на его действия. В это время должен работать цикл обработки сообщений, который будет распределять поступающие сообщения конкретным окнам.
Сообщения, которые будет получать окно, информируют приложение о всех действиях, которые предпринимает пользователь при работе с данным окном. Так, существуют сообщения, информирующие о создании окна, изменении его положения, размеров, вводе текста, перемещении курсора мыши через область окна, выборе пунктов меню, закрытии окна и т.д. Для удобства работы системы все сообщения имеют уникальные номера, по которым определяется назначение этого сообщения; а для удобства разработки приложений для всех сообщений определяются символические названия. Например:
#define WM_MOVE 0x0003
#define WM_SIZE 0x0005
В большинстве случаев названия сообщений начинаются на WM_, однако названия некоторых сообщений имеют префиксы BM_, EM_, LBM_, CBM_ и другие.
Для начала выделим четыре сообщения, с которыми мы будем знакомится первыми. Это сообщения применяются при создании окна (WM_CREATE), при закрытии 5 (WM_DESTROY и WM_QUIT) и при его перерисовывании (WM_PAINT).
В тот момент, когда приложение создает новое окно, оконная процедура получает специальное сообщение WM_CREATE, информирующее окно о его создании. При этом окно создается с помощью вызова специальной функции (CreateWindow, CreateWindowEx и некоторые другие), которая выполняет все необходимые действия; сообщение при этом имеет лишь “информационный” характер — оно информирует окно о том, что его создают. Однако реальное создание происходит не в обработчике этого сообщения, а в той функции, которую вызвали для создания окна.
На сообщении перерисовки окна WM_PAINT надо остановиться чуть подробнее. Дело в том, что какая – либо часть окна может быть скрыта от пользователя (например, перекрыта другим окном). Далее в процессе работы эта часть может стать видимой, например вследствие перемещения других окон. Сама система при этом не знает, что должно быть нарисовано в этой, ранее невидимой части окна. В этой ситуации приложение вынуждено позаботиться о перерисовке нужной части окна самостоятельно, для чего ему и посылается это сообщение каждый раз, как видимая область окна изменяется.
Когда окно закрывается, оно получает сообщение WM_DESTROY, информирующее о закрытии окна. Как и в случае создания, сообщение о закрытии является информационным; реальное закрытие осуществляется специальной функцией (обычно DestroyWindow), которая, среди прочего, и известит окно о его уничтожении.
Все время, пока пользователь работает с приложением, работает цикл обработки сообщений этого приложения, обеспечивающий доставку сообщений окнам. В конце работы приложения этот цикл, очевидно, должен завершиться. В принципе, можно сделать так, что бы в цикле проверялось наличие окон у приложения. При закрытии всех окон цикл тоже должен завершить свою работу. Однако можно несколько упростить задачу — и в Windows именно так и сделано — вместо проверки наличия окон можно предусмотреть специальный метод завершения цикла при получении последним окном (обычно это главное окно приложения) сообщения о его уничтожении (WM_DESTROY). Для этого применяется специальное сообщение WM_QUIT, которое посылается не какому – либо окну, а всему приложению в целом. При извлечении этого сообщения из очереди цикл обработки сообщений завершается. Для посылки такого сообщения предусмотрена специальная функция — PostQuitMessage.
После завершения цикла обработки сообщений приложение уничтожает оставшиеся ненужные объекты и возвращает управление операционной системе.
Сейчас в качестве примера мы рассмотрим простейшее приложение для Windows, традиционную программу “Hello, world!”. После этого подробнее рассмотрим, как это приложение устроено. Здесь же можно заметить, что при создании практически любых, написанных на “C”, приложений для Windows этот текст может использоваться в качестве шаблона.
Пример 1A — первое приложение
Файл 1a.cpp
#define STRICT
#include <windows.h>
#define UNUSED_ARG(arg) (arg)=(arg)
static char szWndClass[] = «test window»;
LRESULT WINAPI _export WinProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
<
UNUSED_ARG( wParam );
UNUSED_ARG( lParam );
PAINTSTRUCT ps;
switch ( uMsg ) <
case WM_CREATE:
return 0L;
case WM_PAINT:
BeginPaint( hWnd, &ps );
TextOut( ps.hdc, 0, 0, «Hello, world!», 13 );
EndPaint( hWnd, &ps );
return 0L;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0L;
default:
break;
>
return DefWindowProc( hWnd, uMsg, wParam, lParam );
>
static BOOL init_instance( HINSTANCE hInstance )
<
WNDCLASS wc;
wc.style = 0L;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szWndClass;
return RegisterClass( &wc ) == NULL ? FALSE : TRUE;
>
int PASCAL WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow )
<
UNUSED_ARG( lpszCmdLine );
MSG msg;
HWND hWnd;
if ( !hPrevInst ) <
if ( !init_instance( hInst ) ) return 1;
>
hWnd= CreateWindow(
szWndClass, «window header», WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInst, NULL
);
if ( !hWnd ) return 1;
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
while ( GetMessage( &msg, NULL, NULL, NULL ) ) <
TranslateMessage( &msg );
DispatchMessage( &msg );
>

Рисунок 1 . Приложение 1a.cpp в среде Windows 3.x или Windows NT 3.x (слева) или в среде Windows – 95 или Windows NT 4.0 (справа).
В зависимости от платформы, на которой запускается это приложение, внешний вид окна может несколько изменяться. Это связано с изменившимся интерфейсом пользователя при переходе от Windows 3.x и Windows NT 3.x к Windows – 95 и Windows NT 4.0.
Далее мы рассмотрим исходный текст более подробно. При первом взгляде на него обращают на себя внимание сразу несколько необычных (по сравнению с программами для DOS) вещей:
- новые типы данных
- странные имена переменных
- обилие используемых функций и передаваемых им параметров
Примерно в таком порядке мы и рассмотрим эти вопросы.
Новые типы данных
Итак, еще раз рассмотрим первое Windows – приложение (1a.cpp).
Обычно в начале “С” – программы помещается директива препроцессора #include для включения файла, содержащего основные определения и прототипы функций. При написании Windows – приложений вы должны включить файл WINDOWS.H. Этот файл содержит определения типов, констант и функций, используемых в Windows 6 .
В приложении перед включением WINDOWS.H определяется специальный символ STRICT:
#define STRICT
#include <windows.h>
Он указывает, что необходимо осуществлять строгую проверку типов. То есть использование вместо переменной одного типа переменной какого – либо другого, даже сходного, типа будет рассматриваться компилятором как ошибка.
Для большей части обычных типов Windows предлагает свои собственные определения — что объясняется возможностью реализации на разных вычислительных платформах и, соответственно, Windows – приложения должны быть переносимыми хотя бы на уровне исходного текста.
Для 16 ти и 32 х разрядных платформ существенно различаются режимы адресации. Например, для 32 х разрядных машин практически не применяются near и far модификаторы адреса (Win32 требует, что бы приложения разрабатывались в 32 х разрядной flat – модели памяти, где на все про все отводится один 32 х разрядный сегмент, размером до 4Г). Кроме того, стандартом C предполагается, что тип данных int имеет длину одно слово. То есть для 16 ти разрядных машин он совпадает с типом short int, а для 32 х разрядных с типом long int. Это приводит к частичной непереносимости С – программ с одной платформы на другую.
Из большого количества определяемых типов выделим несколько, с которыми нам придется столкнуться в самом начале. Те, которые мы будем вводить позже, будут объясняться по мере поступления.
Значение для Windows API
Значение для Win32 API
Символы (#define)
FAR
NEAR
PASCAL
LONG
VOID
NULL
WINAPI
CALLBACK
far
near
pascal
long
void
0
pascal far
pascal far
Типы (typedef)
BOOL
BYTE
WORD
DWORD
UINT
NPSTR
PSTR
LPSTR
LPCSTR
WPARAM
LPARAM
LRESULT
FARPROC
HANDLE
HFILE
HWND
HINSTANCE
HDC
int
unsigned char
unsigned short int
unsigned long int
unsigned int
char near*
char *
char far*
const char far*
UINT
LONG
LONG
(far pascal *)(void)
unsigned int
HANDLE
HANDLE
HANDLE
HANDLE
int
unsigned char
unsigned short int
unsigned long int
unsigned int
char *
char *
char *
const char *
UINT
LONG
LONG
(pascal *)( void )
unsigned int
HANDLE
HANDLE
HANDLE
HANDLE
Практически для всех определенных типов существуют типы “указатель на. ”. Ближние указатели строятся с помощью префикса NP, а дальние — LP, указатели, соответствующие принятой модели памяти, строятся с помощью префикса P. Например, BYTE — тип, представляющий отдельный байт, LPBYTE — дальний указатель на байт, а NPBYTE — ближний указатель. Исключение — тип VOID, он имеет только дальний указатель LPVOID.
Внимательнее разберемся с типом HANDLE (и со всеми “производными” от него): Дело в том, что Windows создает специальные структуры данных, описывающих требуемые объекты (например окно). Эта структура данных зачастую принадлежит не вашему приложению, а самой системе. Для того, что бы этот объект можно было идентифицировать, вводится специальное понятие хендл (дескриптор, handle). Хендл в Windows — это просто целое число, иногда номер, присвоенный данному объекту, причем значение NULL указывает на несуществующий объект. Единственное исключение — HFILE, для которого определено специальное значение — HFILE_ERROR, равное -1 (это связано с тем, что хендл файла первоначально был заимствован у DOS, где хендл 0 обозначает стандартное устройство вывода stdout). Понятие хендла в Windows используется очень широко, а для облегчения контроля типов используется большое количество производных от хендла типов.
Win32
Здесь же надо еще раз отметить, что для Win32 API всегда применяется 32 х разрядная flat – модель памяти. В этом случае модификаторы far и near не применяются. Кроме того хендл, соответствующий типу unsigned int, становится 32 х разрядным. Это на самом деле приводит к изрядным сложностям при переходе с платформы на платформу. Дело в том, что в Windows API хендл часто объединяется с какими – либо дополнительными данными и размещается в одном двойном слове, передаваемом в качестве параметра функции или сообщения, а в Win32 такое уже не получится — хендл сам занимает все двойное слово.
Кроме того, в Win32 API для работы с файлами используется опять – таки хендл, но уже не типа HFILE, а HANDLE. При этом нулевое значение по – прежнему является допустимым и обозначает стандартное устройство вывода, а значение -1 — неверный хендл. Для обозначения неверного хендла файла определен символ INVALID_HANDLE_VALUE, равный -1. Для других хендлов, кроме хендлов файлов, этот символ не применяется, так как для индикации ошибки применяется значение 0. При этом тип HFILE и символ HFILE_ERROR определены также, как и в 16 ти разрядных Windows — в виде 16 ти разрядного целого числа. В принципе допустимо простое приведение типов, однако в будущих реализациях Windows API ситуация может измениться, так как тип HANDLE соответствует 32 х разрядному числу.
Венгерская нотация
При чтении текстов C — программ и документации Вы обратите внимание на несколько странное написание имен переменных и функций. Например:
Разработчики Windows рекомендуют применять специфичные правила описания имен переменных, которые получили название “венгерская нотация” по национальности программиста Charles Simonyi из Microsoft, предложившего ее. Применение венгерской нотации улучшает читаемость программ и уменьшает вероятность ошибки. Хотя, конечно, это дается ценой увеличения длины имен переменных.
Хорошим программистским правилом является использование мнемонических имен переменных. Венгерская нотация предполагает не только применение мнемоники для определения смысла переменной (как, например, FileSize), но и включение ее типа в имя. Например lpszFileName обозначает дальний указатель на ASCIIZ 7 строку символов, содержащую имя файла.
Как видно из примера, перед мнемоническим именем переменной пишется небольшой префикс, указывающий ее тип. Каким образом строится префикс? Из небольшой таблицы можно получить представление об обозначении основных типов данных:
Введение.
Эти главы являются некоторым пособием для тех, кто хочет познакомиться с языком программирования C++ и Visual C++.
В связи с тем, что сегодня уровень сложности программного обеспечения очень высок, разработка приложений Windows с использованием только какого-либо языка программирования (например, языка C) значительно затрудняется. Программист должен затратить массу времени на решение стандартных задач по созданию многооконного интерфейса. Реализация технологии связывания и встраивания объектов — OLE — потребует от программиста еще более сложной работы.
Чтобы облегчить работу программиста практически все современные компиляторы с языка C++ содержат специальные библиотеки классов. Такие библиотеки включают в себя практически весь программный интерфейс Windows и позволяют пользоваться при программировании средствами более высокого уровня, чем обычные вызовы функций. За счет этого значительно упрощается разработка приложений, имеющих сложный интерфейс пользователя, облегчается поддержка технологии OLE и взаимодействие с базами данных.
Современные интегрированные средства разработки приложений Windows позволяют автоматизировать процесс создания приложения. Для этого используются генераторы приложений. Программист отвечает на вопросы генератора приложений и определяет свойства приложения — поддерживает ли оно многооконный режим, технологию OLE, трехмерные органы управления, справочную систему. Генератор приложений, создаст приложение, отвечающее требованиям, и предоставит исходные тексты. Пользуясь им как шаблоном, программист сможет быстро разрабатывать свои приложения.
Подобные средства автоматизированного создания приложений включены в компилятор Microsoft Visual C++ и называются MFC AppWizard. Заполнив несколько диалоговых панелей, можно указать характеристики приложения и получить его тексты, снабженные обширными комментариями. MFC AppWizard позволяет создавать однооконные и многооконные приложения, а также приложения, не имеющие главного окна, -вместо него используется диалоговая панель. Можно также включить поддержку технологии OLE, баз данных, справочной системы.
Конечно, MFC AppWizard не всесилен. Прикладную часть приложения программисту придется разрабатывать самостоятельно. Исходный текст приложения, созданный MFC AppWizard, станет только основой, к которой нужно подключить остальное. Но работающий шаблон приложения — это уже половина всей работы. Исходные тексты приложений, автоматически полученных от MFC AppWizard, могут составлять сотни строк текста. Набор его вручную был бы очень утомителен.
Нужно отметить, что MFC AppWizard создает тексты приложений только с использованием библиотеки классов MFC (Microsoft Foundation Class library). Поэтому только изучив язык C++ и библиотеку MFC, можно пользоваться средствами автоматизированной разработки и создавать свои приложения в кратчайшие сроки.
Некоторые сведения о программировании Windows-приложений
MFC — это базовый набор (библиотека) классов, написанных на языке С++ и предназначенных для упрощения и ускорения процесса программирования под Windows. Перед изучением библиотеки MFC и ее использованием для создания Windows-приложений, следует вспомнить, как работает сама Windows и каковы принципы взаимодействия программ с ней, какова структура типичной Windows-программы.
Программная среда Windows
Рассмотрим наиболее важные моменты работы Windows и принципы взаимодействия программ с ней.
Интерфейс вызовов функций в Windows
Благодаря данному интерфейсу доступ к системным ресурсам осуществляется через целый рад системных функций. Совокупность таких функций называется прикладным программным интерфейсом, или API (Application Programming Interfase). Для взаимодействия с Windows приложение запрашивает функции API, с помощью которых реализуются все необходимые системные действия, такие как выделение памяти, вывод на экран, создание окон и т.п.
Библиотека MFC инкапсулирует многие функции API. Хотя программам и разрешено обращаться к ним напрямую, все же чаще это будет выполняться через соответствующие функции-члены. Как правило, функции-члены либо аналогичны функциям API, либо непосредственно обращаются к нужной части интерфейса.
Библиотеки динамической загрузки (DLL)
Поскольку API состоит из большого числа функций, может сложиться впечатление, что при компиляции каждой программы, написанной для Windows, к ней подключается код довольно значительного объема. В действительности это не так. Функции API содержатся в библиотеках динамической загрузки (Dynamic Link Libraries, или DLL), которые загружаются в память только в тот момент, когда к ним происходит обращение, т.е. при выполнении программы. Рассмотрим, как осуществляется механизм динамической загрузки.
Динамическая загрузка обеспечивает ряд существенных преимуществ. Во-первых, поскольку практически все программы используют API-функции, то благодаря DLL-библиотекам существенно экономится дисковое пространство, которое в противном случае занималось бы большим количеством повторяющегося кода, содержащегося в каждом из исполняемых файлов. Во-вторых, изменения и улучшения в Windows-приложениях сводятся к обновлению только содержимого DLL-библиотек. Уже существующие тексты программ не требуют перекомпиляции.
Win16 или Win32
В настоящее время широко распространены две версии API. Первая называется Win16 и представляет собой 16-разрядную версию, используемую в Windows 3.1. Вторая, 32-разрядная версия, называется Win32 и используется в Windows 95 и Windows NT. Win32 является надмножеством для Win16 (т.е. фактически включает в себя этот интерфейс), так как большинство функций имеет то же название и применяется аналогичным образом. Однако, будучи в принципе похожими, оба интерфейса все же отличаются друг от друга. Win32 поддерживает 32-разрядную линейную адресацию, тогда как Win16 работает только с 16-разрядной сегментированной моделью памяти. Это привело к тому, что некоторые функции были модифицированы таким образом, чтобы принимать 32-разрядные аргументы и возвращать 32-разрядные значения. Часть из них пришлось изменить с учетом 32-разрядной архитектуры. Была реализована поддержка потоковой многозадачности, новых элементов интерфейса и прочих нововведений Windows.
Так как Win32 поддерживает полностью 32-разрядную адресацию, то логично, что целые типы данных (intergers) также объявлены 32-разрядными. Это означает, что переменные типа int и unsignerd будут иметь длину 32 бита, а не 16, как в Windows 3.1. Если же необходимо использовать переменную или константу длиной 16 бит, они должны быть объявлены как short. (дальше будет показано, что для этих типов определены независимые typedef-имена.) Следовательно, при переносе программного кода из 16-разрядной среды необходимо убедиться в правильности использования целочисленных элементов, которые автоматически будут расширены до 32 битов, что целочисленных элементов, которые автоматически будут расширены до 32 битов, что может привести к появлению побочных эффектов.
Другим следствием 32-разрядной адресации является то, что указатели больше не нужно объявлять как near и far. Любой указатель может получить доступ к любому участку памяти. В Windows 95 и Windows NT константы near и far объявлены (с помощью директивы #define)пустыми.
Интерфейс GDI
Одним из подмножеств API является GDI (Graphics Device Interfase — интерфейс графического устройства). GDI — это та часть Windows, которая обеспечивает поддержку аппаратно-независимой графики. Благодаря функциям GDI Windows-приложение может выполняться на самых различных компьютерах.
Многозадачность в Windows
Как известно, все версии Windows поддерживают многозадачность. В Windows 3.1 имеется только один тип многозадачности — основанный на процессах. В более передовых системах, таких как Windows 95 и Windows NT, поддерживается два типа многозадачности: основанный на процессах и основанный на потоках. Давайте рассмотрим их чуть подробнее.
Процесс — это программа, которая выполняется. При многозадачности такого типа две или более программы могут выполняться параллельно. Конечно, они по очереди используют ресурсы центрального процессора и с технической точки зрения, выполняются неодновременно, но благодаря высокой скорости работы компьютера это практически незаметно.
Поток — это отдельная часть исполняемого кода. Название произошло от понятия «направление протекания процесса». В многозадачности данного типа отдельные потоки внутри одного процесса также могут выполняться одновременно. Все процессы имеют по крайней мере один поток, но в Windows 95 и Windows NT их может быть несколько.
Отсюда можно сделать вывод, что в Windows 95 и Windows NT допускается существование процессов, две или более частей которых выполняются одновременно. Оказывается, такое предположение верно. Следовательно, при работе в этих операционных системах возможно параллельное выполнение, как программ, так и отдельных частей самих программ. Это позволяет писать очень эффективные программы.
Есть и другое существенное различие между многозадачностями Windows 3.1 и Windows 95/NT. В Windows 3.1 используется неприоритетная многозадачность. Это означает, что процесс, выполняющийся в данный момент, получает доступ к ресурсам центрального процессора и удерживает их в течение необходимого ему времени. Таким образом, неправильно выполняющаяся программа может захватить все ресурсы процессора и не давать выполняться другим процессам. В отличие от этого в Windows 95 и Windows NT используется приоритетная многозадачность. В этом случае каждому активному потоку предоставляется определенный промежуток времени работы процессора. По истечению данного промежутка управление автоматически передается следующему потоку. Это не дает возможность программам полностью захватывать ресурсы процессора. Интуитивно должно быть понятно, что такой способ более предпочтителен.
Взаимодействие программ и Windows
Во многих операционных системах взаимодействие между системой и программой инициализирует программа. Например, в DOS программа запрашивает разрешение на ввод и вывод данных. Говоря другими словами, не- Windows-программы сами вызывают операционную систему. Обратного процесса не происходит. В Windows все совершенно наоборот: именно система вызывает программу. Это осуществляется следующим образом: программа ожидает получения сообщения от Windows. Когда это происходит, то выполняется некоторое действие. После его завершения программа ожидает следующего сообщения.
Windows может посылать программе сообщения множества различных типов. Например, каждый раз при щелчке мышью в окне активной программы посылается соответствующее сообщение. Другой тип сообщений посылается, когда необходимо обновить содержимое активного окна. Сообщения посылаются также при нажатии клавиши, если программа ожидает ввода с клавиатуры. Необходимо запомнить одно: по отношению к программе сообщения появляются случайным образом. Вот почему Windows-программы похожи на программы обработки прерываний: невозможно предсказать, какое сообщение появиться в следующий момент.
Основы программирования под Windows
Поскольку архитектура Windows-программ основана на принципе сообщений, все эти программы содержат некоторые общие компоненты. Обычно их приходится в явном виде включать в исходный код. Но, к счастью, при использовании библиотеки MFC это происходит автоматически; нет необходимости тратить время и усилия на их написание. Тем не менее, чтобы до конца разобраться, как работает Windows-программа, написанная с использованием MFC, и почему она работает именно так, необходимо в общих чертах понять назначение этих компонентов.
Функция WinMain()
Все Windows-программы начинают выполнение с вызова функции WinMain(). При традиционном методе программирования это нужно делать явно. С использованием библиотеки MFC такая необходимость отпадает, но функция все-таки существует.
Функция окна
Все Windows-программы должны содержать специальную функцию, которая не используется в самой программе, но вызывается самой операционной системой. Эту функцию обычно называют функцией окна, или процедурой окна. Она вызывается Windows, когда системе необходимо передать сообщение в программу. Именно через нее осуществляется взаимодействие между программой и системой. Функция окна передает сообщение в своих аргументах. Согласно терминологии Windows, функции, вызываемые системой, называются функциями обратного вызова. Таким образом, функция окна является функцией обратного вызова.
Помимо принятия сообщения от Windows, функция окна должна вызывать выполнение действия, указанного в сообщении. Конечно, программа не обязана отвечать на все сообщения, посылаемые Windows. Поскольку их могут быть сотни, то большинство сообщений обычно обрабатывается самой системой, а программе достаточно поручить Windows выполнить действия, предусмотренные по умолчанию.
В большинстве Windows-программ задача создания функции окна лежит на программисте. При использовании библиотеки MFC такая функция создается автоматически. В этом заключается одно из преимуществ библиотеки. Но в любом случае, если сообщение получено, то программа должна выполнить некоторое действие. Хотя она может вызывать для этого одну или несколько API-функций, само действие было инициировано Windows. Поэтому именно способ взаимодействия с операционной системой через сообщения диктует общий принцип построения всех программ для Windows, написанных как с использованием MFC, так и без нее.
Цикл сообщений
Как объяснялось выше, Windows взаимодействует с программой, посылая ей сообщения. Все приложения Windows должны организовать так называемый цикл сообщений (обычно внутри функции WinMain()). В этом цикле каждое необработанное сообщение должно быть извлечено из очереди сообщений данного приложения и передано назад в Windows, которая затем вызывает функцию окна программы с данным сообщением в качестве аргумента. В традиционных Windows-программах необходимо самостоятельно создавать и активизировать такой цикл. При использовании MFC это также выполняется автоматически. Однако важно помнить, что цикл сообщений все же существует. Он является неотъемлемой частью любого приложения Windows.
Процесс получения и обработки сообщений может показаться чересчур сложным, но тем не менее ему должны следовать все Windows-программы. К счастью, при использовании библиотеки MFC большинство частных деталей скрыты от программиста, хотя и продолжают неявно присутствовать в программе.
Класс окна
Как будет показано дальше, каждое окно в Windows-приложении характеризуется определенными атрибутами, называемыми классом окна. (Здесь понятие «класс» не идентично используемому в С++. Оно, скорее, означает стиль или тип.) В традиционной программе класс окна должен быть определен и зарегистрирован прежде, чем будет создано окно. При регистрации необходимо сообщить Windows, какой вид должно иметь окно и какую функцию оно выполняет. В то же время регистрация класса окна еще не означает создание самого окна. Для этого требуется выполнить дополнительные действия. При использовании библиотеки MFC создавать собственный класс окна нет необходимости. Вместо этого можно работать с одним из заранее определенных классов, описанных в библиотеке. В этом еще одно ее преимущество.
Специфика программ для Windows
Структура Windows-программ отличается от структуры программ других типов. Это вызвано двумя обстоятельствами: во-первых, способом взаимодействия между программой и Windows, описанным выше; во-вторых, правилами, которым следует подчиняться для создания стандартного интерфейса Windows-приложения (т.е. чтобы сделать программу «похожей » на Windows-приложение).
Цель Windows — дать человеку, который хотя бы немного знаком с системой, возможность сесть за компьютер и запустить любое приложение без предварительной подготовки. Для этого Windows предоставляет дружественный интерфейс пользователя. Теоретически, если пользователь сумел запустить одно Windows-приложение, то он сумеет запустить и любое другое. Конечно, на практике придется немного потренироваться, чтобы научиться использовать большинство программ с максимальной эффективностью. Однако это связано исключительно с тем, что программа делает, а не с тем, как ею пользоваться. Ведь, фактически, значительная часть кода Windows-приложения предназначена именно для организации интерфейса с пользователем.
Хотя создание удобного интерфейса «под Windows» является основной задачей при написании любой Windows-программы, такой интерфейс не создается автоматически. То есть вполне можно написать программу, в которой элементы интерфейса используются неэффективно. Чтобы этого избежать, необходимо целенаправленно применять методику, описанную в данной книге. Только программы, написанные таким способом, будут выглядеть и работать действительно так, как надлежит Windows-программам.
Чтобы отойти от философии создания традиционного Windows-интерфейса, должны быть достаточно веские основания. Иначе пользователи этой программы будут разочарованы. В общем, если программист собирается писать приложения для Windows, то он должен дать пользователям возможность работать с обычным интерфейсом и руководствоваться стандартной методикой разработки.
Типы данных в Windows
В Windows-программах вообще (и в использующих библиотеку MFC в частности) не слишком широко применяются стандартные типы данных из С или С++, такие как int или char*. Вместо них используются типы данных, определенные в различных библиотечных (header) файлах. Наиболее часто используемыми типами являются HANDLE, HWND, BYTE, WORD, DWORD, UNIT, LONG, BOOL, LPSTR и LPCSTR. Тип HANDLE обозначает 32-разрядное целое, используемое в качестве дескриптора. Есть несколько похожих типов данных, но все они имеют ту же длину, что и HANDLE, и начинаются с литеры Н. Дескриптор — это просто число, определяющее некоторый ресурс. Например, тип HWND обозначает 32-разрядное целое — дескриптор окна. В программах, использующих библиотеку MFC, дескрипторы применяются не столь широко, как это имеет место в традиционных программах. Тип BYTE обозначает 8-разрядное беззнаковое символьное значение, тип WORD — 16-разрядное беззнаковое короткое целое, тип DWORD — беззнаковое длинное целое, тип UNIT — беззнаковое 32-разрядное целое. Тип LONG эквивалентен типу long. Тип BOOL обозначает целое и используется, когда значение может быть либо истинным, либо ложным. Тип LPSTR определяет указатель на строку, а LPCSTR — константный (const) указатель на строку.
Преимущества использования MFC
Как уже упоминалось, MFC — это базовый набор (библиотека) классов, написанных на языке С++ и предназначенных для упрощения и ускорения процесса программирования для Windows. Библиотека содержит многоуровневую иерархию классов, насчитывающую около 200 членов. Они дают возможность создавать Windows-приложения на базе объектно-ориентированного подхода. С точки зрения программиста, MFC представляет собой каркас, на основе которого можно писать программы для Windows.
Библиотека MFC разрабатывалась для упрощения задач, стоящих перед программистом. Как известно, традиционный метод программирования под Windows требует написания достаточно длинных и сложных программ, имеющих ряд специфических особенностей. В частности, для создания только каркаса программы таким методом понадобится около 75 строк кода. По мере же увеличения сложности программы ее код может достигать поистине невероятных размеров. Однако та же самая программа, написанная с использованием MFC, будет примерно в три раза меньше, поскольку большинство частных деталей скрыто от программиста.
Одним из основных преимуществ работы с MFC является возможность многократного использования одного и того же кода. Так как библиотека содержит много элементов, общих для всех Windows-приложений, нет необходимости каждый раз писать их заново. Вместо этого их можно просто наследовать (говоря языком объектно-ориентированного программирования). Кроме того, интерфейс, обеспечиваемый библиотекой, практически независим от конкретных деталей, его реализующих. Поэтому программы, написанные на основе MFC, могут быть легко адаптированы к новым версиям Windows (в отличие от большинства программ, написанных обычными методами).
Еще одним существенным преимуществом MFC является упрощение взаимодействия с прикладным программным интерфейсом (API) Windows. Любое приложение взаимодействует с Windows через API, который содержит несколько сот функций. Внушительный размер API затрудняет попытки понять и изучить его целиком. Зачастую даже сложно проследить, как отдельные части API связанны друг с другом! Но поскольку библиотека MFC объединяет (путем инкапсуляции) функции API в логически организованное множество классов, интерфейсом становится значительно легче управлять.
Поскольку MFC представляет собой набор классов, написанных на языке С++, поэтому программы, написанные с использованием MFC, должна быть в то же время программами на С++. Для этого необходимо владеть соответствующими знаниями. Для начала необходимо уметь создавать собственные классы, понимать принципы наследования и уметь переопределять виртуальные функции. Хотя программы, использующие библиотеку MFC, обычно не содержат слишком специфических элементов из арсенала С++, для их написания тем не менее требуются солидные знания в данной области.
Замечание. Небольшое число классов, определенных в библиотеке, не связанно непосредственно с программированием под Windows. Это, в частности, классы, предназначенные для создания строк, управления файлами и обработки особых ситуаций. Иногда называемые классами общего назначения, они могут использоваться как Windows-, так и не- Windows-приложениями.
Обзор среды Microsoft Developer Studio
Студия разработчика фирмы Microsoft (Microsoft Developer Studio) — это интегрированная среда для разработки, позволяющая функционировать различным средам разработки, одна из которых Visual C++, другая — Visual J++. В дальнейшем будет идти речь только о среде разработки Visual C++.
В студии разработчика можно строить обычные программы на C и С++, создавать статические и динамические библиотеки, но основным режимом работы является создание Windows-приложений с помощью инструмента MFC AppWizard (Application Wizard — мастер приложений) и библиотеки базовых классов MFC (Microsoft Foundation Class Library). Такие приложения называются MFC-приложениями. Главная особенность этих Windows-приложений состоит в том, что они работают как совокупность взаимодействующих объектов, классы которых определены библиотекой MFC.
Библиотека MFC
Главная часть библиотеки MFC состоит из классов, используемых для построения компонентов приложения. С каждым MFC-приложением связывается определяющий его на верхнем уровне объект theApp, принадлежащий классу, производному от CWinApp.
Как правило, структура приложения определяется архитектурой Document-View (документ-облик). Это означает, что приложение состоит из одного или нескольких документов — объектов, классы которых являются производными от класса CDocument (класс «документ»). С каждым из документов связаны один или несколько обликов — объектов классов, производных от CView (класс «облик «) и определяющих облик документа.
Класс CFrameWnd («окна-рамки») и производные от него определяют окна-рамки на дисплее. Элементы управления, создаваемые при проектировании интерфейса пользователя, принадлежат семейству классов элементов управления. Появляющиеся в процессе работы приложения диалоговые окна — это объекты классов, производных от CDialog.
Классы CView, CFrameWnd, CDialog и все классы элементов управления наследуют свойства и поведение своего базового класса CWnd («окно»), определяющего по существу Windows-окно. Этот класс в свою очередь является наследником базового ласса CObject («объект»).
Одна из трудностей в понимании принципов устройства MFC-приложения, заключается в том, что объекты, из которых оно строится, наследуют свойства и поведение всех своих предков, поэтому необходимо знать базовые классы.
Архитектура приложения
У всех Windows-приложений фиксированная структура, определяемая функцией WinMain. Структура приложения, построенного из объектов классов библиотеки MFC, является еще более определенной.
Приложение состоит из объекта theApp, функции WinMain, и некоторого количества других объектов. Сердцевина приложения — объект theApp — отвечает за создание всех остальных объектов и обработку очереди сообщений. Объект theApp является глобальным и создается еще до начала работы функции WinMain. Работа функции WinMain заключается в последовательном вызове двух методов объекта theApp: InitInstance и Run. В терминах сообщений можно сказать, WinMain посылает объекту theApp сообщение InitInstance, которое приводит в действие метод InitInstance.
Получив сообщение InitInstance, theApp создает внутренние объекты приложения. Процесс создания выглядит как последовательное порождение одних объектов другими. Набор объектов, порождаемых в начале этой цепочки, определен структурой MFC практически однозначно — это главная рамка, шаблон, документ, облик. Их роли в работе приложения будут обсуждаться позже.
Следующее сообщение, получаемое theApp, — Run — приводит в действие метод Run. Оно как бы говорит объекту: «Начинай работу, начинай процесс обработки сообщений из внешнего мира». Объект theApp циклически выбирает сообщения из очереди и инициирует обработку сообщений объектами приложения.
Некоторые объекты имеют графический образ на экране, с которым может взаимодействовать пользователь. Эти интерфейсные объекты обычно связаны с Windows-окном. Среди них особенно важны главная рамка и облик. Именно им объект прежде всего распределяет сообщения из очереди через механизм Windows-окон и функцию Dispatch.
Когда пользователь выбирает команду меню окна главной рамки, то возникают командные сообщения. Они отправляются сначала объектом theApp объекту главная рамка, а затем обходят по специальному маршруту целый ряд объектов, среди которых первыми являются документ и облик, информируя их о пришедшей от пользователя команде.
При работе приложения возникают и обычные вызовы одними объектами методов других объектов. В объектно-ориентированной терминологии такие вызовы могут называться сообщениями. В Visual C++ некоторым методам приписан именно этот статус (например, методу OnDraw).
Важное значение имеют также объекты документ, облик и главная рамка. Здесь отметим только, что документ содержит данные приложения, облик организует представление этих данных на экране, а окно главной рамки — это окно, внутри которого размещены все остальные окна приложения.
Каркас приложения
Наследование — одна из фундаментальных идей объектно-ориентированного программирования. Именно этот механизм наследования позволяет программисту дополнять и переопределять поведение базового класса, не вторгаясь в библиотеку MFC, которая остается неизменной. Все изменения делаются в собственном производном классе. Именно в этом и заключается работа программиста.
Объекты, их которых состоит приложение, являются объектами классов, производных от классов библиотеки MFC. Разработка приложения состоит в том, что программист берет из библиотеки MFC классы CWinApp, CFrameWnd, CDocument, CView и т.д. и строит производные классы. Приложение создается как совокупность объектов этих производных классов. Каждый объект несет в себе как наследуемые черты, определяемые базовыми классами, так и новые черты, добавленные программистом. Наследуемые черты определяют общую схему поведения, свойственную таким приложениям. Новые же черты позволяют реализовать специфические особенности поведения приложения, необходимые для решения стоящей перед ним задачи.
При определении производного класса программист может:
- переопределить некоторые методы базового класса, причем те методы, что не были переопределены, будут наследоваться в том виде, в каком они существуют в базовом классе;
- добавить новые методы;
- добавить новые переменные.
Приложение, построенное на основе библиотеки MFC, — «айсберг», большая часть которого невидима, но является основой всего приложения. Часть приложения, лежащую в библиотеке MFC, — framework — называется каркасом приложения. Рассмотрим работу приложения как процесс взаимодействия между каркасом и частью приложения, разработанной программистом. Совершенно естественно, что в методах, определенных программистом, могут встречаться вызовы методов базового класса, что вполне можно рассматривать как вызов функции из библиотеки. Важнее, однако, что и метод производного класса, определенный программистом, может быть вызван из метода родительского класса. Другими словами, каркас и производный класс в этом смысле равноправны — их методы могут вызывать друг друга. Такое равноправие достигается благодаря виртуальным методам и полиморфизму, имеющимся в арсенале объектно-ориентированного программирования.
Если метод базового класса объявлен виртуальным и разработчик переопределил его в производном классе, это значит, что при вызове данного метода в некоторой полиморфной функции базового класса в момент исполнения будет вызван метод производного класса и, следовательно, каркас вызывает метод, определенный программистом. Точнее говоря, обращение к этому методу должно производиться через ссылку на производный объект либо через объект, являющийся формальным параметром и получающий при вызове в качестве своего значения объект производного класса. Когда вызывается виртуальный метод М1, переопределенный разработчиком, то согласно терминологии Visual C++, каркас посылает сообщение М1 объекту производного класса, а метод М1 этого объекта обрабатывает это сообщение. Если сообщение М1 послано объекту производного класса, а обработчик этого сообщения не задан программистом, объект наследует метод М1 ближайшего родительского класса, в котором определен этот метод. Если же обработчик такого сообщения создан программистом, он автоматически отменяет действия, предусмотренные родительским классом в отсутствие этого обработчика.
Каркас приложений
С Visual C++ тесно связано еще одно понятие — каркас приложений, которое близко и созвучно понятию каркаса приложения, но в отличие от него относится не к одному конкретному приложению, а к библиотеке, с помощью которой строятся многие приложения. Каркас приложений — это библиотека классов, из которых программист берет не только набор классов, играющих роль дополнительных типов данных, но и классы, служащие строительными блоками приложения на самом верхнем уровне. С этой точки зрения, каркас приложения является частью каркаса приложений, относящейся к данному приложению. Примеры каркасов приложений — библиотеки классов MFC и OWL.
Проект приложения
О принципах устройства приложения рассказывалось выше. Теперь рассмотрим, как оно создается с помощью Visual C++. Сначала разберем одно важное понятие — проект. До сих пор приложение рассматривалось, как только как совокупность объектов базовых и производных классов. Но для обеспечения работы приложения требуется нечто большее — наряду с описанием классов необходимо описание ресурсов, связанных с приложением, нужна справочная система и т.п. Термин «проект» как раз и используется, когда имеется в виду такой более общий взгляд на приложение.
В среде Visual C++ можно строить различные типы проектов. Такие проекты после их создания можно компилировать и запускать на исполнение. Фирма Microsoft разработала специальный инструментарий, облегчающий и ускоряющий создание проектов в среде Visual C++. Например, мастер MFC AppWizard (exe) позволяет создать проект Windows-приложения которое имеет однодокументный, многодокументный или диалоговый интерфейс и использует библиотеку MFC.
Создаваемый остов приложения составлен так, что в дальнейшей работе с проектом можно использовать другое инструментальное средство — ClassWizard (мастер классов), предназначенное для создания остовов новых производных классов. Еще одно основное назначение ClassWizard в том, что он создает остовы для переопределяемых методов. Он позволяет показать все сообщения, приходящие классу, и создать остов обработчика любого из этих сообщений. Это только две основные функции ClassWizard. Он не всесилен, но его возможности довольно велики.
Использование средств разработки
В состав компилятора Microsoft Developer Studio встроены средства, позволяющие программисту облегчить разработку приложений. В первую очередь к ним относятся MFC AppWisard, ClassWizard и редактор ресурсов.
Благодаря MFC AppWizard среда разработчика позволяет быстро создавать шаблоны новых приложений. При этом программисту не приходится писать ни одной строчки кода. Достаточно ответить на ряд вопросов, касающихся того, какое приложение требуется создать, и исходные тексты шаблона приложения вместе с файлами ресурсов готовы. Эти тексты можно оттранслировать и получить готовый загрузочный модуль приложения.
Конечно, никакие средства автоматизированной разработки не смогут создать программу полностью без участия программиста. Прикладную часть приложения придется разрабатывать ему.
Для создания ресурсов приложения предназначен редактор ресурсов. Он позволяет быстро создавать новые меню, диалоговые панели, добавлять кнопки к панели управления toolbar и т.д.
Средство ClassWizard позволяет подключить к созданным и отредактированным ресурсам управляющий ими код. Большую часть работы по описанию и определению функций, обрабатывающих сообщения от меню, органов управления диалоговых панелей и т.д., также берет на себя средство ClassWizard.
Типы мастеров проектов
В среде Visual C++ можно строить различные типы проектов. Такие проекты после их создания можно компилировать и запускать на исполнение. Фирма Microsoft разработала специальный инструментарий, облегчающий и ускоряющий создание проектов в среде Visual C++.
Рассмотрим некоторые типы проектов, которые можно создавать при помощи различных средств (мастеров проектов) Microsoft Visual C++:
- MFC AppWizard (exe) — при помощи мастера приложений можно создать проект Windows-приложения которое имеет однодокументный, многодокументный или диалоговый интерфейс. Однодокументное приложеие может предоставлять пользователю в любой момент времени работать только с одним файлом. Многодокументное приложение, напротив, может одновременно представлять несколько документов, каждый в собственном окне. Пользовательский интерфейс диалогового приложения представляет собой единственное диалоговое окно.
- MFC AppWizard (dll) — этот мастер приложений позволяет создать структуру DLL, основанную на MFC. При помощи него можно определить характеристики будующей DLL.
- AppWizard ATL COM — это средство позволяет создать элемент управления ActiveX или сервер автоматизации, используя новую библиотеку шаблонов ActiveX (ActiveX Template Library — ATL). Опции этого мастера дают возможность выбрать активный сервер (DLL) или исполняемый внешний сервер (exe-файл).
- Custom AppWizard — при помощи этого средства можно создать пользовательские мастера AppWizard. Пользовательский мастер может базироваться на стандартных мастерах для приложений MFC или DLL, а также на существующих проектах или содержать только определеямые разработчиком шаги.
- DevStudio Add-in Wizard — мастер дополнений позволяет создавать дополнения к Visual Studio. Библиотека DLL расширений может поддерживать панели инструментов и реагировать на события Visual Studio.
- MFC ActiveX ControlWizard — мастер элементов управления реализует процесс создания проекта, содержащего один или несколько элементов управления ActiveX, основанных на элементах управления MFC.
- Win32 Application — этот мастер позволяет создать проект обычного Window-приложения. Проект создается незаполненным, файлы с исходным кодом в него следует добавлять вручную.
- Win32 Console Application — мастер создания проекта консольного приложения. Консольная приложение — это программа, которая выполняется из командной cтроки окна DOS или Windows и не имеет графического интерфейса (окон). Проект консольного приложения создается пустым, предполагая добавление файлов исходного текста в него вручную.
- Win32 Dynamic-Link Library — создание пустого проекта динамически подключаемой библиотеки. Установки компилятора и компоновщика будут настроены на создание DLL. Исходные файлы следует добавлять вручную.
- Win32 Static Library — это средство создает пустой проект, предназначенный для генерации статической (объектной) библиотеки. Файлы с исходным кодом в него следует добавлять вручную.
Преимущества мастеров проектов
Рассмотрим преимущества использования мастеров в процессе создания приложений. Прежде всего, нужно отметить, что создание проекта — это не только творчество, но и большой объем технической работы, требующей внимания и аккуратности.
Например, все Windows-приложения имеют достаточно общую структуру, и, следовательно, можно построить некоторые шаблонные заготовки, подходящие для того или иного типа проектов. Построению таких заготовок способствует то, что приложения, создаваемые на основе MFC, строятся из элементов фиксированных классов. Логическим развитием этой идеи было введение специальных классов и специальной архитектуры построения приложения, которая подходила бы широкому классу приложений. О такой архитектуре уже упоминалось, когда речь шла о библиотеке MFC, — это архитектура Document-View. Она является основной, но не единственной при построении проектов в среде Visual C++.
Суть этой архитектуры в том, что работу многих приложений можно рассматривать как обработку документов. При этом можно отделить сам документ, отвечающий за представление и хранение данных, от образа этого документа, видимого на экране и допускающего взаимодействие с пользователем, который просматривает и (или) редактирует документ. В соответствии с этой архитектурой библиотека MFC содержит два семейства классов, производных от базовых классов CDocument и CView.
В результате появилась двухэтапная технология создания проектов. Вначале создается некая заготовка проекта с общими свойствами, подходящими для многих проектов этого типа. На втором этапе производится уже настройка, учитывающая специфику задачи. Для каждого этапа фирма Microsoft разработала свое инструментальное средство.
Начальная заготовка — остов приложения — создается в диалоге с пользователем инструментальным средством AppWizard. В процессе диалога пользователь определяет тип и характеристики проекта, который он хочет построить. Определив, какие классы из MFC необходимы для этого проекта, AppWizard строит остовы всех нужных производных классов. Построенный AppWizard остов приложения содержит все необходимые файлы для создания стартового приложения, которое является законченным приложением и обладает разумными функциональными свойствами, общими для целого класса приложений. Естественно, никаких специфических для данного приложения свойств остов не содержит. Они появятся на следующем этапе, когда программист начнет работать с остовом, создавая из заготовки свое собственное приложение. Тем не менее стартовое приложение можно транслировать и запускать на исполнение.
Термин остов (приложения, класса, функции) применяется для заготовок, создаваемых инструментальными средствами AppWizard и ClassWizard. Нужно подчеркнуть — остов приложения и каркас приложения — разные понятия.
Создаваемый остов приложения составлен так, что в дальнейшей работе с проектом можно использовать другое инструментальное средство — ClassWizard (мастер классов).
Обзор возможностей ClassWizard
Средство ClassWizard предоставляет широкий спектр услуг. Он позволяет не только добавлять к существующему классу новые методы и данные.
Создание нового класса. При помощи ClassWizard можно добавить новый класс, созданный на основе базовых классов. В качестве базового класса можно использовать классы, наследованные от класса CCmdTarget или класса CRecordset. Для наследования классов от других базовых классов использовать средства ClassWizard нельзя. Такие классы надо создавать вручную, непосредственно в текстовом редакторе.
Объекты, порожденные от класса CCmdTarget, могут обрабатывать сообщения Windows и команды, поступающие от меню, кнопок, акселераторов. Класс CCmdTarget и другие наследованные от него классы имеют таблицу сообщений (Message Map) — набор макрокоманд, позволяющий сопоставить сообщения Windows и команды метода класса.
Полученная заготовка класса полностью работоспособна. Ее можно дополнить по своему усмотрению новыми методами и данными. Эту работу можно выполнить вручную, но гораздо лучше и проще воспользоваться услугами ClassWizard. За счет использования ClassWizard процедура создания собственного класса значительно ускоряется и уменьшается вероятность совершить ошибку во время объявления методов.
Включение в класс новых методов. Очень удобно использовать ClassWizard для включения в состав класса новых методов. Можно добавлять к классу методы, служащие для обработки сообщений Windows и команд от объектов, а также методы, переопределяющие виртуальные методы базовых классов.
ClassWizard не только позволяет добавить в класс новые методы, но и удалить их. ClassWizard самостоятельно удалит объявление метода из класса.
Включение в класс новых элементов данных. ClassWizard позволяет включать в класс не только новые методы, но и элементы данных, связанные с полями диалоговых панелей, форм просмотра и форм для просмотра записей баз данных и полей наборов записей. ClassWizard использует специальные процедуры, чтобы привязать созданные им элементы данных к класса к полям диалоговых панелей. Эти процедуры носят названия «обмен данными диалоговой панели» и «проверка данных диалоговой панели» (Dialog Data Exchange and Dialog Data Validation — DDX/DDV). Чтобы привязать поля из наборов записей к переменным, используется процедура обмена данными с полями записей (Record Field Exchange — RFX).
Процедуры DDX/DDV и RFX значительно упрощают программисту работу с диалоговыми панелями. Они позволяют связать поля диалоговых панелей и переменные. Когда пользователь редактирует поля диалоговых панелей, процедуры DDV проверяют введенные значения и блокируют ввод запрещенных значений. Затем процедуры DDX автоматически копируют содержимое полей диалоговых панелей в привязанные к ним элементы данных класса. И наоборот, когда приложение изменяет элементы данных класса, привязанные к полям диалоговой панели, процедуры DDX могут сразу отобразить новые значения полей на экране компьютера.
Имена, используемые в MFC
Библиотека MFC содержит большое количество классов, структур, констант и т.д. Для того, чтобы текст MFC-приложений был более легким для понимания, принято применять ряд соглашений для используемых имен и комментариев.
Названия всех классов и шаблонов классов библиотеки MFC начинаются с заглавной буквы C. При наследовании классов от классов MFC можно давать им любые имена. Рекомендуется начинать их названия с заглавной буквы C. Это сделает исходный текст приложения более ясным для понимания.
Чтобы отличить элементы данных, входящих в класс, от простых переменных, их имена принято начинать с префикса m_. Названия методов классов, как правило, специально не выделяются, но обычно их начинают с заглавной буквы.
Библиотека MFC включает в себя, помимо классов, набор служебных функций. Названия этих функций начинаются с символов Afx, например AfxGetApp. Символы AFX являются сокращением от словосочетания Application FrameworkX, означающих основу приложения, его внутреннее устройство.
Символы AFX встречаются не только в названии функций MFC. Многие константы, макрокоманды и другие символы начинаются с этих символов. В общем случае AFX является признаком, по которому можно определить принадлежность того или иного объекта (функция, переменная, ключевое слово или символ) к библиотеке MFC.
Когда приложение разрабатывается средствами MFC AppWizard и ClassWizard, они размещают в исходном тексте приложения комментарии следующего вида:
Такие комментарии образуют блок кода программы, который управляется только средствами MFC AppWizard и ClassWizard. Пользователь не должен вручную вносить изменения в этом блоке. Для этого необходимо употреблять средства ClassWizard.
В следующей таблице представлено краткое описание некоторых блоков //< MFC AppWizard и ClassWizard помогают разрабатывать приложения. Они создают все классы и методы, необходимые для его работы. Программисту остается дописать к ним свой код. В тех местах, где можно вставить свой код, MFC AppWizard и ClassWizard, как правило помещают комментарии: Для того что бы перейти к Visual C++, целесообразно получить некоторое представление о просто языке C++, так как он является базовым. Что бы начать обучение вам нужно сначала поставить какую-нибудь версию Visual C++. Лучше, конечно, если у вас есть место на HDD, поставить Visual C++ версии 6. Но можно поставить версию 5 или 4. Все мои примеры написаны на шестой версии, но они должны работать и на младших версиях. Многие думают, что если они поставили Visual C++, то могут писать программы только под Windows, но это не правильно. Visual C++ позволяет писать программы и на простом C++, как бы под DOS. Ну вот, я думаю, и можно начинать. Приложение Люди является простой адресной книгой, которая по умолчанию есть в Windows. Затем вы можете использовать адресную книгу как для отправки электронных сообщений, так и для звонков со своего телефона. Но обо всем по порядку. Запустить приложение Люди можно из секции часто используемых приложений в меню Пуск. Интерфейс программы очень простой — в левой колонке будут в алфавитном порядке находится имена людей, которых я добавил в адресную книгу, а в правой части будет появляться подробная информация о контакте, если мы его выберем в левой колонке. Поскольку у меня нет ни одной записи, то нажму на кнопку «+», чтобы добавить первый контакт. Если у вас еще не была выбрана учетная запись, с которой будет синхронизироваться адресная книга, то появится соответствующее окно, в котором мы должны указать эту учетную запись или аккаунт. Дело в том, что контакты, также как и календарь, синхронизируются через учетную запись и будут поддерживаться в актуальном состоянии на всех ваших устройствах, использующих Windows 10. В Google-аккаунте есть возможность не только управлять почтой, но и планировать свой день с помощью календаря, а также вести адресную книгу. Поэтому кроме стандартного аккаунта Outlook, который создается вместе с учетной записью Майкрософт, мы можем использовать и Gmail. Такой вариант является альтернативой, если вы не хотите использовать учетную запись Майкрософт. В дальнейшем для каждой записи в адресной книге мы можем задать свой аккаунт. В открывшемся окне мы можем задать имя, телефон, email, адрес и другую информацию о контакте, выбрав ее из соответствующего списка. Само собой, не обязательно заполнять все поля. Вы можете указать только то, что вам известно, например, если вам известен только рабочий адрес электронной почты человека, то указываем его, а затем поменяем тип с «Личный» на «Рабочий». Также можно добавить несколько адресов электронной почты при такой необходимости. Если у вас есть фото человека, то можно его выбрать и установить. При этом фотография может быть где-то на вашем компьютере или в облачном сервисе OneDrive. После того, как вся информация заполнена, сохраняем ее и контакт появляется в программе. При необходимости мы можем изменить контакт, нажав на значок с карандашом: Также мы можем из этой панели инструментов удалять контакты или поделиться им с помощью других программ. Мы можем воспользоваться программой Почта. Для этого выбираем ту учетную запись, с которой хотим контакт отправить и далее будет автоматически сформировано письмо, в которое будет вставлен файл-визитка. Пользователь, которому вы пошлете это сообщение, сможет запустить файл-визитку и информация из нее автоматически добавится в его адресную книгу. С помощью адресной книги очень просто отправлять электронную почту — находим нужного человека и щелкаем по его адресу электронной почты. Выбираем программу, с которой отправим сообщение: Далее выбираем почтовый аккаунт, с которого сообщение будет отослано: Автоматически создастся новое письмо, в котором ящик электронной почты уже будет подставлен. Также если мы используем программу Почта и пишем новое сообщение, то контакты из адресной книги будут нам автоматически предлагаться, как только мы начнем ввод адреса электронной почты или имени человека в поле «Кому». Если в адресной книге есть несколько контактов, в имени или email-адресе, которых содержатся введенное вами сочетание символов, то все они будут отображаться в выпадающем списке и вы можете мышью выбрать тот, который вам нужен в этот момент. Ну и в заключение скажу пару слов о поиске контактов. Со временем в вашей адресной книге появится множество контактов. Чтобы быстро найти человека в вашей адресной книге, достаточно воспользоваться окном поиска и ввести его имя. Также можно щелкнуть по букве каталога и тогда перед нами откроется алфавитный указатель и мы сможем выбрать ту букву, на которую начинается искомый нами контакт. Если вы не нашли себя в использовании Приложение Windows People очень много, вы можете удалить значок приложения и панель с панели задач. Это очень легко сделать, и вы можете сделать это, выполнив следующие действия: После этого значок «Люди» будет удален с панели задач. Вы также можете узнать, как удалить Windows 10, в нашей статье. Кроме того, вы можете использовать простую настройку реестра, чтобы удалить Приложение Windows People значок из вашей панели задач. Просто следуйте этим шагам: Внимание: перед удалением настоятельно рекомендую создать точку восстановления на всякий случай. Откроется консоль, вставляем в нее команду для удаления приложения Люди: Get-AppxPackage *People* | Remove-AppxPackage Вставили команду, потом нажимаем энтер и начнется процесс удаления: Приложение Люди — что это вообще такое? Это простая адресная книга, которая присутствует в Windows по умолчанию. В этой книге вы можете создавать контакты, записывать данные о человеке, например номер телефона, адрес почты, где проживает, день рождение и другую информацию. Приложения Люди, Почта и Календарь работают вместе так, чтобы можно было отправить сообщение по электронной почте важным для вас людям и назначить им встречу. По факту не особо нужное приложение. Собственно внешний вид приложения Люди (People): Также при желании вы можете удалить и другие приложения, вот команды для некоторых: Напомню, что при удалении приложений — все таки лучше создавать заранее точку восстановления, это минутное дело, но если что — поможет сохранить нервы и время. Надеюсь информация оказалась полезной. Удачи и добра, до новых встреч, друзья! Приложение Windows 10 People это больше, чем просто приложение для контактов, поскольку Microsoft постепенно создает его, чтобы стать социальным центром для вашего устройства. Приложение Windows People имеет прямую интеграцию с приложениями Почта и Календарь, что делает его основным социальным приложением для вашего устройства. Microsoft давно организовала единую адресную книгу на основе Windows Live . Так, отправляя письмо из Hotmail / Outlook.com или предоставляя доступ к файлам на SkyDrive, вы пользуетесь одной и той же адресной книгой. В Windows Phone список контактов сразу подтягивается, а импортированные с SIM-карты контакты добавляются в него и синхронизируются с облаком. Однако в ОС Windows исторически все было вовсе не так удобно. В оболочке Windows Vista появилось управление контактами, которые представляли собой новый тип файла — .contact. Папка «Контакты» одновременно служила адресной книгой для почтового клиента Windows Mail, встроенного в систему. Этот снимок экрана, взятый из русской справки Windows Vista, как бы намекает на проблемы встроенных контактов
Блок
Описание
// <
Включает объявление элементов данных класса. Используется в описании классов диалоговых панелей.
// <
Включает инициализацию элементов данных класса. Используется в файле реализации классов диалоговых панелей.
// <
Включает макрокоманды DDX, предназначенные для связывания элементов данных класса и органов управления диалоговых панелей. Используется в файле реализации классов диалоговых панелей.
// <
Включает описание методов, которые предназначены для обработки сообщений. Этот блок используется при описании класса.
// <
Включает макрокоманды таблицы сообщений класса. Используются совместно с AFX_MSG.
// <
Включает описание переопределенных виртуальных методов класса. Блок AFX_VIRTUAL используется при описании класса.
Что такое приложение Windows 10 People и как его удалить?
В адресной книге вы можете создавать контакты, записывая данные о человеке, например, его телефон, ящик электронной почты, адрес проживания и множество другой информации (дни рождения, веб-сайты, должности, организации и т.д.).













Как удалить приложение Windows 10 People?

Как удалить Люди в Windows 10 полностью? (People)
Покажу легкий и простой способ удаления при помощи консоли PowerShell, которую нужно запустить от имени администратора, сделать это можно двумя вариантами:


Информацию о приложении можно узнать на официальном сайте Microsoft.
Что такое приложение Microsoft People?

История вопроса

