|
|
|
| Давно мечтаю засовать свои наработоки в динамические библиотеки, но всегда как-то страшно с ними было работать, да и как-то не удобно их соединять с программой через проект... а тут копаясь в MSDN обнаружил функцию LoadLibrary() - вроде выглядит не страшно. Правильно ли я понимаю, что можно просто в любой момент подключиться к DLL, а потом отсоединиться и не надо библиотеку прописывать в связях проекта? cheops, если не сложно покажите как с ней работать? Ну если конечно "hellow world!" для этого примера не нужно дней пять писать :-) Работаем понятно в Visual Studio. | |
|
|
|
|
|
|
|
для: asker++
(28.01.2012 в 09:36)
| | В общем да, в имеется две стратегии: связывание на этапе построения, когда вы добавляете DLL-библиотеку в проект или динамическое связывание во время работы программы. Именно для последнего случая предназначена LoadLibrary(), да собственно и сами DLL-библиотеки. Там не то чтобы сложно - "этикету" больше, но если один раз разобраться - потом не "страшно" :)))
Я так понимаю, с созданием DLL-библиотеки проблем не возникает? На всякий случай я приведу код простейшей библиотеки с одной функцией, HelloWorld(), которая этот самый "Hellow world" и выводит.
#include <Windows.h>
#include <iostream>
using namespace std;
// Главная функция
BOOL WINAPI DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) void HelloWorld(void)
{
cout << "Hello world" << endl;
} | Главная функция DllMain() практически пустая, события не обрабатываются, нам не надо, так как у нас нет никакой динамической памяти, параллельных потоков и прочего. Теоретически можно вообще DllMain() не создавать - она должна добавляться автоматически компилятором. Функция HelloWorld() объявлена без параметров и возвращаемых результатов, но можно и с тем и с другим - никаких сложностей не возникает. Чтобы функцию было "видно" из вне, она объявляется с атрибутами extern и __declspec(dllexport), "C" - это порядок чтения аргументов, у нас тут их вообще нет, но приводим для единообразия.
Вообще если вы находитесь в VisualStudio, лучше в рамках одного решения создать два проекта - один с DLL-библиотекой, другой - с кодом, тестирующим эту библиотеку. Первый проект понятно DLL, второй - можно консольный. Исполняемым (выделенным жирным) у вас должен быть консольный проект, ему же кстати можно добавить зависимость от DLL-проекта, тогда никаких проблем вообще быть не должно - сначала будет компилироваться DLL, а потом консольный проект.
При условии, что DLL-проект называется dll, а библиотека на выходе соответственно dll.dll, консольный проверочный проект может выглядеть следующим образом
#include <Windows.h>
#include <iostream>
#include <tchar.h>
using namespace std;
int main()
{
// Дескриптор DLL-библиотеки
HMODULE hDll;
// Указатель на функцию
void (*dllHelloWorld) (void);
// Загружаем динамически подключаемую библиотеку
hDll = LoadLibrary(_T("dll.dll"));
if(!hDll)
{
cout << _T("Динамическая библиотека не загружена") << endl;
return GetLastError();
}
// Настраиваем адрес функции
dllHelloWorld = (void (*)(void))GetProcAddress(hDll, "HelloWorld");
if(!dllHelloWorld)
{
cout << _T("Ошибка получения адреса функции") << endl;
return GetLastError();
}
// Вызываем функцию из библиотеки
dllHelloWorld();
// Отключаем библиотеку
if(!FreeLibrary(hDll))
{
cout << _T("Ошибка выгрузки библиотеки из памяти") << endl;
return GetLastError();
}
// Устанавливаем паузу перед завершением программы
system("pause");
return 0;
} | PS Все проекты в UNICODE, т.е. строки обрамляем макросом _T, если программе нужны параметры, вместо main() используем _tmain(). Кстати, обратите внимание, что GetProcAddress() принимает обычные 8-битные строки, поэтому если у вас названия функций в LPTSTR/LPCTSTR-строках, придется переводить. | |
|
|
|
|
|
|
|
для: cheops
(28.01.2012 в 10:09)
| | Офигеть, работает!
А можно что-нибудь более сложно-полезное вызывать, например, вот такую функцию? Не очень ясно, как тут с параметрами?
void ShowMessage(LPCTSTR title, LPCTSTR text)
{
MessageBox(
NULL,
text,
title,
MB_OK | MB_ICONEXCLAMATION);
} |
| |
|
|
|
|
|
|
|
для: asker++
(28.01.2012 в 10:38)
| | В этом случае ваша DLL-библиотека должна выглядеть следующим образом
#include <Windows.h>
extern "C" __declspec(dllexport) void ShowMessage(LPCTSTR title, LPCTSTR text)
{
MessageBox(
NULL,
text,
title,
MB_OK | MB_ICONEXCLAMATION);
} | Тогда программа, загружающая библиотеку dll.dll и вызывающая функцию ShowMessage() может выглядеть следующим образом
// Главный заголовочный файл
#include <Windows.h>
#include <tchar.h>
// Главная входная точка Windows-программ
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpcmdline,
int ncmdshow)
{
// Дескриптор DLL-библиотеки
HMODULE hDll;
// Указатель на функцию
void (*dllShowMessage) (LPCTSTR, LPCTSTR);
// Загружаем динамически подключаемую библиотеку
hDll = LoadLibrary(_T("dll.dll"));
if(!hDll)
{
MessageBox(
NULL,
_T("Динамическая библиотека не загружена"),
_T("Ошибка"),
MB_OK | MB_ICONEXCLAMATION);
return GetLastError();
}
// Настраиваем адрес функции
dllShowMessage = (void (*)(LPCTSTR, LPCTSTR))GetProcAddress(hDll, "ShowMessage");
if(!dllShowMessage)
{
MessageBox(
NULL,
_T("Невозможно получить адрес функции ShowMessage()"),
_T("Ошибка"),
MB_OK | MB_ICONEXCLAMATION);
return GetLastError();
}
// Вызываем функцию из библиотеки
dllShowMessage(_T("Hello world!"), _T("Hello world!"));
// Отключаем библиотеку
if(!FreeLibrary(hDll))
{
MessageBox(
NULL,
_T("Ошибка выгрузки библиотеки из памяти"),
_T("Ошибка"),
MB_OK | MB_ICONEXCLAMATION);
return GetLastError();
}
// Выход из программы
return 0;
} |
PS Проверки, конечно, по уму надо бы через исключения делать, а то полезность dllShowMessage() как-то теряется, а сложность возрастает :))) | |
|
|
|
|
|
|
|
для: cheops
(28.01.2012 в 10:51)
| | Огромное спасибо! | |
|
|
|
|