Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Последовательность поиска ресурсов в 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 не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...