Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Последовательность поиска ресурсов в DLL-расширении
Если Вы создаете динамически связываемое клиентское приложение на базе MFC, многие стандартные ресурсы MFC-библиотеки (строки сообщений об ошибках, шаблоны диалоговых окон для предварительного просмотра печатью и др.) хранятся в DLL-модулях MFC (mfc42.dll и т. д.); но и у вашего приложения есть свои ресурсы. Когда Вы вызываете MFC-функцию вроде CString::LoadString() или CBitmap::LoadBitmap(), каркас приложения ищет сначала ресурсы ЕХЕ-файла, а потом ресурсы DLL MFC. Если же программа включает в себя DLL-расширение, то последовательность поиска такова: сначала ЕХЕ-файл, затем DLL-расширение и, наконец, DLL MFC. При наличии, скажем, уникального идентификатора строкового ресурса MFC-библиотека найдет именно его, а если в ЕХЕ-файле и файле DLL-расширения какие-то идентификаторы строковых ресурсов дублируются, MFC-библиотека загрузит строку из ЕХЕ-файла. Если же ресурс загружает DLL-расширение, то последовательность поиска такова: сначала DLL-расширение, затем DLL MFC и, наконец, ЕХЕ-файл. При необходимости последовательность поиска можно изменить. Допустим, Вы хотите в ЕХЕ-коде сначала искать ресурсы DLL-расширения. Это можно сделать так: HINSTANCE hInstResourceClient = AfxGetResourceHandle(); // используем описатель экземпляра DLL AfxSetResourceHandle(::GetModuleHandle("mydllname.dll")); CString strRes; strRes.LoadString(IDS_MYSTRING); // восстанавливает описатель экземпляра клиентской программы AfxSetResourceHandle(hInstResourceClient);
Использовать здесь AfxGetInstanceHandle() вместо ::GetModuleHandle() нельзя, потому что в DLL-расширении описатель экземпляра ЕХЕ-, а не DLL-модуля.
Разработка библиотеки Здесь описан процесс создания обычной DLL в MVS 6.0. В целом он не сильно отличается от создания такой же библиотеки в MVS-2005. Шаг 1. Воспользуйтесь мастером File►New►Projects►MFC AppWizard (dll), дайте проекту имя RegDLL (регулярная DLL), нажмите ОК и убедитесь в том, что в следующем появившемся окне выбран тип библиотеки «Regular DLL using shared MFC DLL». Закончите диалог с мастером. Шаг 2. В конец файла добавьте какую-нибудь функцию, которую будет экспортировать библиотека, и опишите какую-нибудь переменную, которую библиотека также будет экспортировать. Таким образом, конец файла RegDLL.cpp может выглядеть так: CRegDLLApp theApp; /* Эта строка сгенерирована мастером, а остальные вы должны ввести сами */ extern "C" __declspec(dllexport) double DefaultVal=123; CString msg="Ну не могу я извлечь корень из отрицательного числа!"; extern "C" __declspec(dllexport) double SquareRoot(double d) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); TRACE("Entering SquareRoot\n"); if (d >= 0.0) { return sqrt(d); } AfxMessageBox(msg); return 0.0; }
Я эту функцию позаимствовал из работы [1], а вы сможете, естественно, написать какую-нибудь свою более полезную. Обратите внимание на то, что в библиотечной функции можно вывести окно сообщения, например, с помощью функции AfxMessageBox(). Строку AFX_MANAGE_STATE(AfxGetStaticModuleState()) Microsoft рекомендует добавлять в библиотечные функции для повышения их же надежности, причем до первого обращения к какой-либо функции MFC. Разумеется, что если вы используете в своей функции какую-либо другую библиотечную функцию, вам понадобится подключить соответствующий заголовочный файл, в данном примере Math.h. Обратите внимание на описание переменной DefaultVal, которая должна экспортироваться библиотекой. В данном примере ей присвоено начальное значение, хотя это и необязательно. Эта переменная может использоваться программным модулем, подключающим данную библиотеку. Кроме того, в библиотеке можно описывать и глобальные переменные, которые не экспортируются: в приведенном выше фрагменте файла RegDLL.cpp это переменная msg. Шаг 3. Откомпилируйте и скомпонуйте библиотеку. В результате в каталоге Debug, если вы выбрали эту конфигурацию активной, должны появиться файлы Regdll.dll и Regdll.lib. Файл с библиотекой импорта Regdll.lib нужен для того, чтобы подключить библиотеку к клиентскому приложению неявным образом (неявное связывание – implicit linking). При явном (explicit linking) файл импорта не используется, и программист должен в нужное время самостоятельно загрузить библиотеку с помощью функции LoadLibrary() (см. подраздел «Явное и неявное связывание» в главе 22 [1]).
Разработка клиентского приложения, использующего библиотеку DLL Здесь описан процесс создания клиентского приложения для обычной DLL в MVS 6.0. В целом он не сильно отличается от создания такого же приложения в MVS-2005. Шаг 1. Воспользуемся мастером File►New►Projects►MFC AppWizard (exe), дадим проекту имя UseRegDLL. На следующем шаге диалога с мастером выберем тип приложения Dialog based и на всех последующих шагах можно все оставить без изменений или отказаться от всех излишеств, для данного примера, предлагаемых мастером. Разумеется, мы можем подключать библиотеку к приложения любого типа, а не только Dialog based. Шаг 2. Теперь, когда у нас появился каталог с клиентским приложением, скопируем в него файлы Regdll.dll и Regdll.lib из каталога Debug проекта библиотеки. В принципе файл Regdll.lib можно было бы и не копировать, но тогда далее пришлось бы указывать к нему полный путь. Альтернативно, файл Regdll.dll можно было бы скопировать в каталог Windows, но такой файл вряд ли целесообразно туда помещать (обратите внимание на подраздел «Порядок поиска DLL клиентской программой» в главе 22 [1]). Шаг 3. Теперь надо как-то сообщить компоновщику о нашем желании использовать ценную библиотеку. Для этого выполните команду Project►Settings, т.е. вызовите окно с установками проекта, выберите вкладку Link, значение General в окне Category и введите имя библиотеки импорта RegDLL.lib в окне Object/Library modules (рис.2).
Рис. 2. Добавление библиотеки импорта в список входных библиотек компоновщика
Шаг 4. Сконструируйте главное и единственное окно приложения примерно так, как показано на рис.3.
Рис. 3. Диалоговое окно
Шаг 5. С помощью ClassWizard свяжите переменные m_dInput и m_dOutput типа double с соответствующими полями ввода данных и сгенерируйте обработчик нажатия кнопки Calculate.
Шаг 6. В начало файла с определением класса диалога UseRegDLLDlg.cpp, перед конструктором, добавьте объявления: extern "C" __declspec (dllimport) double SquareRoot(double); extern "C" __declspec (dllimport) double DefaultVal;
Эти объявления позволяют получить доступ к переменной DefaultVal и функции SquareRoot(), импортируемым из библиотеки RegDll.dll. Добавим в функцию CUseRegDLLDlg::OnInitDialog() инициализацию поля ввода исходной величины значением переменной DefaultVal из библиотеки: BOOL CUseRegDLLDlg::OnInitDialog() { CDialog::OnInitDialog(); SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); // TODO: Add extra initialization here m_dInput=DefaultVal; UpdateData(FALSE); return TRUE; }
И, наконец, добавим код в функцию CUseRegDLLDlg::OnButtonCompute(): void CUseRegDLLDlg::OnButtonCompute() { UpdateData(TRUE); m_dOutput = SquareRoot(m_dInput); UpdateData(FALSE); }
Теперь проект можно откомпилировать, собрать и выполнить его ходовые испытания.
|
|||||||
Последнее изменение этой страницы: 2018-04-12; просмотров: 389. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |