Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
otvety_po_OAiPR.doc
Скачиваний:
3
Добавлен:
01.03.2025
Размер:
1.23 Mб
Скачать

202. Для добавления элементов к панели, созданную в предыдущей процедуре, перетащите элементы управления из раздела Редактор ленты на панели Панель элементов в представлении конструирования.

Сначала добавьте кнопку Печать. Кнопка Печать будет содержать подменю, содержащее команду Быстрая печать, выводящей с помощью принтера по умолчанию. Обе команды уже определены для этого приложения. Они расположены в меню приложения.

Для создания кнопки Печать, перетащите инструмент кнопки на панели.

В окне Свойства измените свойство Идентификатор к ID_FILE_PRINT, которое должно быть уже определена. Изменение подпись к Печать. Изменениеиндекс образа до 4.

Для создания кнопки Быстрая печать, щелкните столбец значение свойства рядом с элементы меню, а затем нажмите кнопку с многоточием (###…). ВРедактор элементов, нажмите кнопку немеченая Добавить для создания пункта меню. В окне Свойства, изменении подпись к Быстрая печать,Идентификатор к ID_FILE_PRINT_DIRECT и Изображение к wType. Свойство образа указывает быстрый значок печати в ресурс растрового изображения IDB_FILESMALL.

Для проверки того, что были добавлены на панель кнопок ленты, чтобы построить приложение и выполните его. Для построения приложения в менюПостроение выберите команду Построить решение. Если построение приложения выполнено успешно, запустите приложение, нажав кнопку Начать отладку в меню Отладка. Кнопка Печать и поле со списком на панели Избранное на вкладке Настраиваемый на ленте должны отображаться.

203. Все Windows-программы должны содержать специальную функцию, которая не используется в самой программе, но вызывается самой операционной системой. Эту функцию обычно называют функцией окна , или процедурой окна . Она вызывается Windows, когда системе необходимо передать сообщение в программу. Именно через нее осуществляется взаимодействие между программой и системой. Функция окна передает сообщение в своих аргументах. Согласно терминологии Windows, функции, вызываемые системой, называются функциями обратного вызова . Таким образом, функция окна является функцией обратного вызова.

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

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

204. Практически невозможно создать приложение Windows, в котором не использовались бы библиотеки DLL. В DLL содержатся все функции Win32 API и несчетное количество других функций операционных систем Win32.

Вообще говоря, DLL ґ это просто наборы функций, собранные в библиотеки. Однако, в отличие от своих статических родственников (файлов . lib), библиотеки DLL не присоединены непосредственно к выполняемым файлам с помощью редактора связей. В выполняемый файл занесена только информация об их местонахождении. В момент выполнения программы загружается вся библиотека целиком. Благодаря этому разные процессы могут пользоваться совместно одними и теми же библиотеками, находящимися в памяти. Такой подход позволяет сократить объем памяти, необходимый для нескольких приложений, использующих много общих библиотек, а также контролировать размеры ЕХЕ-файлов.

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

Чаще всего проект подключается к DLL статически, или неявно, на этапе компоновки. Загрузкой DLL при выполнении программы управляет операционная система. Однако, DLL можно загрузить и явно, или динамически, в ходе работы приложения.

Библиотеки импортирования

При статическом подключении DLL имя .lib-файла определяется среди прочих параметров редактора связей в командной строке или на вкладке «Link¬ диалогового окна «Project Settings¬ среды Developer Studio. Однако .lib-файл, используемый при неявном подключении DLL, ґ это не обычная статическая библиотека. Такие .lib-файлы называются библиотеками импортирования (import libraries). В них содержится не сам код библиотеки, а только ссылки на все функции, экспортируемые из файла DLL, в котором все и хранится. В результате библиотеки импортирования, как правило, имеют меньший размер, чем DLL-файлы. К способам их создания вернемся позднее. А сейчас рассмотрим другие вопросы, касающиеся неявного подключения динамических библиотек.

Согласование интерфейсов

При использовании собственных библиотек или библиотек независимых разработчиков придется обратить внимание на согласование вызова функции с ее прототипом.

Если бы мир был совершенен, то программистам не пришлось бы беспокоиться о согласовании интерфейсов функций при подключении библиотек ґ все они были бы одинаковыми. Однако мир далек от совершенства, и многие большие программы написаны с помощью различных библиотек без C++.

По умолчанию в Visual C++ интерфейсы функций согласуются по правилам C++. Это значит, что параметры заносятся в стек справа налево, вызывающая программа отвечает за их удаление из стека при выходе из функции и расширении ее имени. Расширение имен (name mangling) позволяет редактору связей различать перегруженные функции, т.е. функции с одинаковыми именами, но разными списками аргументов. Однако в старой библиотеке С функции с расширенными именами отсутствуют.

Хотя все остальные правила вызова функции в С идентичны правилам вызова функции в C++, в библиотеках С имена функций не расширяются. К ним только добавляется впереди символ подчеркивания (_).

Если необходимо подключить библиотеку на С к приложению на C++, все функции из этой библиотеки придется объявить как внешние в формате С:

extern "С" int MyOldCFunction(int myParam);

Объявления функций библиотеки обычно помещаются в файле заголовка этой библиотеки, хотя заголовки большинства библиотек С не рассчитаны на применение в проектах на C++. В этом случае необходимо создать копию файла заголовка и включить в нее модификатор extern "C" к объявлению всех используемых функций библиотеки. Модификатор extern "C" можно применить и к целому блоку, к которому с помощью директивы #tinclude подключен файл старого заголовка С. Таким образом, вместо модификации каждой функции в отдельности можно обойтись всего тремя строками:

extern "С" { #include "MyCLib.h" }

В программах для старых версий Windows использовались также соглашения о вызове функций языка PASCAL для функцийWindows API. В новых программах следует использовать модификатор winapi, преобразуемый в _stdcall. Хотя это и не стандартный интерфейс функций С или C++, но именно он используется для обращений к функциям Windows API. Однако обычно все это уже учтено в стандартных заголовках Windows.

Загрузка неявно подключаемой DLL

При запуске приложение пытается найти все файлы DLL, неявно подключенные к приложению, и поместить их в область оперативной памяти, занимаемую данным процессом. Поиск файлов DLL операционной системой осуществляется в следующей последовательности.

  • Каталог, в котором находится ЕХЕ-файл.

  • Текущий каталог процесса.

  • Системный каталог Windows.

Если библиотека DLL не обнаружена, приложение выводит диалоговое окно с сообщением о ее отсутствии и путях, по которым осуществлялся поиск. Затем процесс отключается.

Если нужная библиотека найдена, она помещается в оперативную память процесса, где и остается до его окончания. Теперь приложение может обращаться к функциям, содержащимся в DLL.

Динамическая загрузка и выгрузка DLL

Вместо того, чтобы Windows выполняла динамическое связывание с DLL при первой загрузке приложения в оперативную память, можно связать программу с модулем библиотеки во время выполнения программы (при таком способе в процессе создания приложения не нужно использовать библиотеку импорта). В частности, можно определить, какая из библиотек DLL доступна пользователю, или разрешить пользователю выбрать, какая из библиотек будет загружаться. Таким образом можно использовать разные DLL, в которых реализованы одни и те же функции, выполняющие различные действия. Например, приложение, предназначенное для независимой передачи данных, сможет в ходе выполнения принять решение, загружать ли DLL для протокола TCP/IP или для другого протокола.

Загрузка обычной DLL

Первое, что необходимо сделать при динамической загрузке DLL, - это поместить модуль библиотеки в память процесса. Данная операция выполняется с помощью функции ::LoadLibrary, имеющей единственный аргумент Ї имя загружаемого модуля. Соответствующий фрагмент программы должен выглядеть так:

HINSTANCE hMyDll; ЏЏ if((hMyDll=::LoadLibrary(«MyDLL¬))==NULL) { /* не удалось загрузить DLL */ } else { /* приложение имеет право пользоваться функциями DLL через hMyDll */ }

Стандартным расширением файла библиотеки Windows считает .dll, если не указать другое расширение. Если в имени файла указан и путь, то только он будет использоваться для поиска файла. В противном случае Windows будет искать файл по той же схеме, что и в случае неявно подключенных DLL, начиная с каталога, из которого загружается exe-файл, и продолжая в соответствии со значением PATH.

Когда Windows обнаружит файл, его полный путь будет сравнен с путем библиотек DLL, уже загруженных данным процессом. Если обнаружится тождество, вместо загрузки копии приложения возвращвется дескриптор уже подключенной библиотеки.

Если файл обнаружен и библиотека успешно загрузилась, функция ::LoadLibrary возвращает ее дескриптор, который используется для доступа к функциям библиотеки.

Перед тем, как использовать функции библиотеки, необходимо получить их адрес. Для этого сначала следует воспользоваться директивой typedef для определения типа указателя на функцию и определить переменую этого нового типа, например:

// тип PFN_MyFunction будет объявлять указатель на функцию, // принимающую указатель на символьный буфер и выдающую значение типа int typedef int (WINAPI *PFN_MyFunction)(char *); ЏЏ PFN_MyFunction pfnMyFunction;

Затем следует получить дескриптор библиотеки, при помощи которого и определить адреса функций, например адрес фунции с именем MyFunction:

hMyDll=::LoadLibrary(«MyDLL¬); pfnMyFunction=(PFN_MyFunction)::GetProcAddress(hMyDll,¬MyFunction¬); ЏЏ int iCode=(*pfnMyFunction)(«Hello¬);

Адрес функции определяется при помощи функции ::GetProcAddress, ей следует передать имя библиотеки и имя функции. Последнее должно передаваться в том виде, в котором эксаортируется из DLL.

Можно также сослаться на функцию по порядковому номеру, по которому она экспортируется (при этом для создания библиотеки должен использоваться def-файл, об этом будет рассказано далее):

pfnMyFunction=(PFN_MyFunction)::GetProcAddress(hMyDll, MAKEINTRESOURCE(1));

После завершения работы с библиотекой динамической компоновки, ее можно выгрузить из памяти процесса с помощью функции ::FreeLibrary:

::FreeLibrary(hMyDll);

Загрузка MFC-расширений динамических библиотек

При загрузке MFC-расширений для DLL (подробно о которых рассказывается далее) вместо функций LoadLibraryиFreeLibrary используются функции AfxLoadLibrary и AfxFreeLibrary. Последние почти идентичны функциям Win32API. Они лишь гарантируют дополнительно, что структуры MFC, инициализированные расширением DLL, не были запорчены другими потоками.

Ресурсы DLL

Динамическая загрузка применима и к ресурсам DLL, используемым MFC для загрузки стандартных ресурсов приложения. Для этого сначала необходимо вызвать функцию LoadLibrary и разместить DLL в памяти. Затем с помощью функцииAfxSetResourceHandle нужно подготовить окно программы к приему ресурсов из вновь загруженной библиотеки. В противном случае ресурсы будут загружаться из файлов, подключенных к выполняемому файлу процесса. Такой подход удобен, если нужно использовать различные наборы ресурсов, например для разных языков.

Замечание. С помощью функции LoadLibrary можно также загружать в память исполняемые файлы (не запускать их на выполнение!). Дескриптор выполняемого модуля может затем использоваться при обращении к функциям FindResource иLoadResource для поиска и загрузки ресурсов приложения. Выгружают модули из памяти также при помощи функцииFreeLibrary.

205. Первая строка включает необходимый файл заголовка с описанием классов, функций и переменных, он ссылается ещё на кучу других, а они на другие и так до windows.h. Вот почему windows.h нам и не понадобился. В каждой программе на С++ есть главная функция программы, в Dos это main(), в Windows - WinMain(). Эта функция обеспечивает запуск программы. Она проверяет операционную среду, выполняет некоторые настройки и, если все нормально, непосредственно передает управление вашему коду. Но у нас-то её нет ! В MFC есть класс CWinApp, который и включает главную функцию программы. Естественно, что в приложении она может быть только одна.

Мы с вами создали CMyApp, как производный от CWinApp и унаследовали все его свойства, методы и т.д. В своем классе мы объявили конструктор по умолчанию (без параметров). Он необходим, иначе вы не скомпилируете программу. Здесь все логично мы в коде объявляем статический класс производный от нашего CMyApp в строке CMyApp theApp;. Как видите он тоже без параметров.

CWinApp имеет виртуальный метод InitInstance(). Виртуальный он потому, что это только заглушка. Мы с вами написали свой метод в виде функции. Этот метод должен возвращать ненулевое значение, если инициализация прошла нормально, а иначе 0. Он предназначен, чтобы вы могли описать класс окна программы и отобразить окно на экране.

Дальше мы должны знать, что в CWinApp есть указатель на класс окна - m_pMainWnd. Этот указатель общедоступный и вы могли догадаться, так как он нигде не объявлен. Ситуация с ним такая - Если по окончанию InitInstance() он будет равен нулю, то приложение завершится. И естественно, когда приложение завершается он обнуляется. Строкой m_pMainWnd=new CMainWnd(); мы присваиваем этому указателю адрес класса C MainWnd, который порожден от CFrameWnd. Последний из них отвечает за работу окна программы в стиле одного документа (SDI - single document interface). Он создает окно, управляет сообщениями и т.д. В конструкторе этого класса мы вызвали функцию создания окна, в которой указали кучу параметров.

Первый параметр указывает на класс Windows, он нам не нужен, пока не нужен и поэтому NULL, дальше указали имя окна программы, WS_OVERLAPPEDWINDOW указывает, что окно имеет заголовок и рамку, rectDefaultговорит о том, что размер окна присвоит Windows, и еще некоторые параметры, ими всеми мы займемся позже. Далее следует ASSERT(m_pMainWnd);. Очень хорошая и простая функция. Если создание объекта произойдет, то m_pMainWnd будет отличаться от нуля и всё будет нормально, а иначе вы получите сообщение о том, что в таком файле на такой-то строке ошибка. Вообще это намного лучше, чем смотреть дизассемблированный код или оказаться в исходном коде библиотеки MFC, если не повесим Windows конечно.

206. О принципах устройства приложения рассказывалось выше. Теперь рассмотрим, как оно создается с помощью Visual C++. Сначала разберем одно важное понятие - проект . До сих пор приложение рассматривалось, как только как совокупность объектов базовых и производных классов. Но для обеспечения работы приложения требуется нечто большее - наряду с описанием классов необходимо описание ресурсов, связанных с приложением, нужна справочная система и т.п. Термин "проект" как раз и используется, когда имеется в виду такой более общий взгляд на приложение.

В среде Visual C++ можно строить различные типы проектов. Такие проекты после их создания можно компилировать и запускать на исполнение. Фирма Microsoft разработала специальный инструментарий, облегчающий и ускоряющий создание проектов в среде Visual C++. Например, мастер MFC AppWizard (exe) позволяет создать проект Windows-приложения которое имеет однодокументный, многодокументный или диалоговый интерфейс и использует библиотеку MFC.

Создаваемый остов приложения составлен так, что в дальнейшей работе с проектом можно использовать другое инструментальное средство - ClassWizard (мастер классов), предназначенное для создания остовов новых производных классов. Еще одно основное назначение ClassWizard в том, что он создает остовы для переопределяемых методов. Он позволяет показать все сообщения, приходящие классу, и создать остов обработчика любого из этих сообщений. Это только две основные функции ClassWizard. Он не всесилен, но его возможности довольно велики.

207. Добавьте в меню элементы верхнего уровня. С помощью контекстного меню соответствующего элемента откройте окно Properties (Свойства) и заполните поле Caption (Подпись), например, Файл, Помощь. Проверьте установку свойства Pop-up: если флажок установлен, то элемент меню будет иметь вложенные элементы, если нет – он будет конечной командой. Элементам меню с установленным свойством Pop-up идентификаторы не присваиваются.

Добавьте в разделы меню верхнего уровня команды (Выход, О программе и т. д.). С помощью контекстного меню элемента и команды Properties (Свойства) каждой команде присвойте идентификатор (поле ID), например, ID_EXIT для команды Выход, ID_ABOUT для команды О программе. Заполните поле Caption (Подпись). Для создания вложенного меню в соответствующем элементе установите свойство Pop-up. Свойство Separator (Сепаратор, или разделитель) разделяет пункты меню горизонтальной линией.

Свяжите меню с классом соответствующего диалогового окна с помощью ClassWizard.

Свяжите каждый пункт меню с кодом программы, для этого используйте ClassWizard и сообщение COMMAND, возникающее при выборе команды меню. В окне ClassWizard установите соответствие между идентификатором меню, например, ID_EXIT, сообщением COMMAND и функцией, обрабатывающий сообщения, например, OnExit().

Свяжите меню с диалоговой панелью, для этого с помощью диаграммы ResourceView следует вызвать окно Свойства диалоговой панели, и в окне Menu выбрать идентификатор меню, например, IDR_MENU1.

208. Как уже упоминалось, 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, обычно не содержат слишком специфических элементов из арсенала С++, для их написания тем не менее требуются солидные знания в данной области.

209. В результате тестирования системы можно сказать, что данный программный продукт соответствует всем указанным требованиям. И те цели и задачи, которые ставились перед выполнением данного проекта, по большему счёту достигнуты.

Методика тестирование включает в себя тестирование основных действий пользователя по работе с программой (use-case). Основными методами являются:

– вывод данных на экран;

– вывод на экран информации о результатах тестирования;

– добавление записи в базу данных;

– удаление записи;

– редактирование записи;

– прохождение теста;

Одним из главных преимуществ данной программы является доступность, простота в обращении и наглядный интерфейс. Разработанная система позволяет пользователю легко и быстро получить нужную информацию.

Данный программный продукт был протестирован на общую работоспособность и функциональное соответствие поставленным задачам. В результате тестирование были найдены и исправлены ошибки ввода пользователем некорректной с точки зрения программы информации.

210. Во многих простых приложениях, созданных на основе форм, не требуется создание документов. Если ваше приложение более сложное, возможно вам потребуется использовать документ в качестве посредника между базой данных, а также хранить объекты CDatabase или CDaoDatabase, подключающиеся к источнику данных. Приложения, создаваемые на основе форм, обычно сохраняют указатель на объект набора записей в представлении. Другие приложения баз данных сохраняют наборы записей и объекты CDatabase или CDaoDatabase в документе. Далее рассматриваются некоторые возможности использования документов в приложениях баз данных:

  • Если вы обращаетесь к набору записей в локальном контексте, создайте объект CRecordset или CDaoRecordset локально в функциях-членах документа или представления по мере необходимости.

Объявите объект набора записей как локальную переменную в функции. Передайте NULL конструктору, после чего платформа создаст и откроет временный объект CDatabase или CDaoDatabase. Как альтернативный вариант, передайте указатель объекту CDatabase или CDaoDatabase. Используйте этот набор записей в функции и задайте его автоматическое удаление по прекращении выполнения функции.

При передаче NULL конструктору набора записей платформа использует информацию, возвращаемую функцией-членом GetDefaultConnect этого набора записей, для создания и открытия объекта CDatabase или CDaoDatabase. Мастер выполнит реализацию GetDefaultConnect.

  • Если вы обращаетесь к набору записей во время существования документа, внедрите в документ один или более объектов CRecordset илиCDaoRecordset.

Создайте объекты набора записей либо при инициализации документа, либо по мере необходимости. Можно написать функцию, возвращающую указатель в набор записей, если он уже существует, либо создающую и открывающую набор записей, если он еще не существует. Закройте, удалите или повторно создайте набор записей по мере необходимости, либо вызовите его функцию-член Requery для обновления записей.

  • Если вы обращаетесь к источнику данных во время существования документа, внедрите объект CDatabase или CDaoDatabase, либо сохраните указатель в объект CDatabase или CDaoDatabase внутри него.

Объект CDatabase или CDaoDatabase управляет подключением к источнику данных. Объект будет создан автоматически во время создания документа. Вызовите его функцию-член Open при инициализации документа. При создании объектов наборов записей в функциях-членах документа передайте указатель объекту CDatabase или CDaoDatabase этого документа. Тем самым каждый набор записей будет ассоциирован со своим источником данных.Объект базы данных обычно удаляется при закрытии документа. Объекты набора записей обычно удаляются при выходе за пределы области действия функции.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]