Кто может написать простой пример создания dll на Visual C++ только так чтобы работал,
Чем проще тем лучше.
03.06.04 06:15: Перенесено модератором из 'C/C++' — Павел Кузнецов
Здравствуйте, Crossroad, Вы писали:
C>Кто может написать простой пример создания dll на Visual C++ только так чтобы работал,
C>Чем проще тем лучше.
Вот самая простая Dll :
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason
LPVOID lpReserved)
{
return TRUE;
}
Здравствуйте, _nn_, Вы писали:
__>Здравствуйте, Crossroad, Вы писали:
C>>Кто может написать простой пример создания dll на Visual C++ только так чтобы работал,
C>>Чем проще тем лучше.
__>Вот самая простая Dll :
__>__>BOOL APIENTRY DllMain(HANDLE hModule,
__> DWORD dwReason
__> LPVOID lpReserved)
__>{
__> return TRUE;
__>}
__>
А можно немножко посложнее с вызовом пару функций и т.п.?
Здравствуйте, Crossroad, Вы писали:
C>Здравствуйте, _nn_, Вы писали:
__>>Здравствуйте, Crossroad, Вы писали:
C>>>Кто может написать простой пример создания dll на Visual C++ только так чтобы работал,
C>>>Чем проще тем лучше.
__>>Вот самая простая Dll :
__>>__>>BOOL APIENTRY DllMain(HANDLE hModule,
__>> DWORD dwReason
__>> LPVOID lpReserved)
__>>{
__>> return TRUE;
__>>}
__>>
C>А можно немножко посложнее с вызовом пару функций и т.п.?
А чем не нравится примерчик, который генерит application wizard в VS?
Здравствуйте, Crossroad, Вы писали:
C>Здравствуйте, _nn_, Вы писали:
__>>Здравствуйте, Crossroad, Вы писали:
C>>>Кто может написать простой пример создания dll на Visual C++ только так чтобы работал,
C>>>Чем проще тем лучше.
__>>Вот самая простая Dll :
__>>__>>BOOL APIENTRY DllMain(HANDLE hModule,
__>> DWORD dwReason
__>> LPVOID lpReserved)
__>>{
__>> return TRUE;
__>>}
__>>
C>А можно немножко посложнее с вызовом пару функций и т.п.?
Разумеется!!! Предлагаю вашему вниманию некую DLL, содержащюю объявления экспортируемых классов, функции и глобальной переменной. Причём экспортирование классов возможно, как при явной, так и при неявной загрузке DLL.
// Dummy.h
#ifdef DUMMY_EXPORTS
#define DUMMY_API __declspec(dllexport)
#else
#define DUMMY_API __declspec(dllimport)
#endif
#include <windows.h>
namespace Dummy_Interface {
// An abstract interface.
class DUMMY_API IDummyInterface {
public:
virtual void hello(const char* name) = 0;
virtual void goodbye() = 0;
};
// Interface's rountines for the explicit linking...
DUMMY_API int APIENTRY Load(IDummyInterface ** pInterface);
DUMMY_API int APIENTRY Unload(IDummyInterface ** pInterface);
// Pointers to the interface's rountines
typedef int (APIENTRY* PFNLOAD)(IDummyInterface**);
typedef int (APIENTRY* PFNUNLOAD)(IDummyInterface**);
// The Dummy interface.
class DUMMY_API IDummy : public IDummyInterface {
public:
enum Max_char { max = 32 }; // the maximumum name's lenght
IDummy() { p = new char[max]; }
~IDummy() { delete[] p; }
void hello(const char* name = szDefName);
void goodbye();
static const char szDefName[max]; // the default user's name
private:
char* p; // a pointer to the user's name
};
}
// Globals
extern DUMMY_API int address;
DUMMY_API void APIENTRY Increment(int&);
// dummy.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "dummy.h"
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved)
{
static Dummy_Interface::IDummy* dum;
switch (dwReason) {
case DLL_PROCESS_ATTACH:
{
dum = new Dummy_Interface::IDummy();
dum->hello();
}
break;
case DLL_PROCESS_DETACH:
{
dum->goodbye();
delete dum;
}
break;
}
return TRUE;
}
// Пример "экспорта" функции.
void APIENTRY Increment(int& x) { x++; }
// Экспортируемая глобальная переменная.
int address = 0x00FA;
// Инициализация статической переменной класса.
const char Dummy_Interface::IDummy::szDefName[IDummy::max] = "Lamer";
// Инициализация "интерфейса" IDummy, только при неявной загрузке DLL.
// Не использовать при явном связываннии DLL.
int APIENTRY Dummy_Interface::Load(Dummy_Interface::IDummyInterface ** pInterface)
{
if (!*pInterface)
return -1;
*pInterface = reinterpret_cast<IDummyInterface*>(new IDummy);
return 0;
}
// Очистка "интерфейса" IDummy, только при неявной загрузке DLL.
// Не использовать при явном связываннии DLL.
int APIENTRY Dummy_Interface::Unload(Dummy_Interface::IDummyInterface ** pInterface)
{
if (!*pInterface)
return -1;
delete *pInterface;
*pInterface = 0;
return 0;
}
// Выводит сообщение формата: "Hello, name!", где name - произвольное
// имя (может быть опущено, в этом случае используется аргумент по
// умолчанию - szDefName).
void Dummy_Interface::IDummy::hello(const char* name)
{
char* base = p;
for (char* pch=(char*)name; *pch!=0; *p++ = *pch++);
*p++ = '!';
*p = 0;
p = base;
char out[100] = "Hello, ";
lstrcat(out, p);
MessageBox(
NULL,
out,
"Dummy_Interface",
MB_OK|MB_ICONEXCLAMATION);
}
// Делает то-же, что и hello, за исключением того, что формат выволимой
// строки меняется на: "Goodbye, name!".
void Dummy_Interface::IDummy::goodbye()
{
char out[100] = "Goodbye, ";
lstrcat(out, p);
MessageBox(
NULL,
out,
"Dummy_Interface",
MB_OK|MB_ICONEXCLAMATION);
}
Код "клиента"[*1] может выглядеть следующим образом (неявное связывание):
// Где-то в программе.....
HMODULE hDummy = LoadLibrary("dummy.dll");
// См. примечание ниже.
PFNLOAD pfnLoad = (PFNLOAD)GetProcAddress(hDummy, "Load");
PFNUNLOAD pfnUnload = (PFNUNLOAD)GetProcAddress(hDummy, "Unload");
Dummy_Interface::IDummyInterface* dum; // "интерфейс"
pfnLoad(&dum); // инициализация...
dum->Dummy_Interface::hello("Boomer"); // использование...
dum->Dummy_Interface::goodbye();
pfnUnload(&dum); // очистка...
FreeLibrary(hDummy); // выгружаем DLL из адресного пространства процесса
[*1] Под клиентом подразумевается любое приложение использующее DLL для явного (implicit) или неявного (explicit) связывания.
Примечание: Экспортируемые функции используют соглашение о вызове языка C, поэтому компоновщик (linker), если пользователь не указал этого явно, использует декорированние имён преобразуя сигнатуры (сигнатура функции — это совокупность её имени, аргументов (если они есть) и типа возвращаемого значения) всех функций, у которых отсутствует префикс extern "C" перед объявлением функции или функции не указанные в файле *.def (используется для указания списка экспортируемых функций) в уникальное символьное имя. То есть, сколько бы не было в DLL функций, переменных или же классов, всё они, так или иначе будут иметь на выходе (после обработки единиц трансляции компоновщиком, другими словами после "сборки" программы — DLL) соглашение о вызове и компоновке языка C. В результате при неявном связывании придётся писать подобный код:
PFNLOAD pfnLoad = (PFNLOAD)GetProcAddress(
hDummy,
"?Load@Dummy_Interface@@YGHPAPAVIDummyInterface@1@@Z");
PFNUNLOAD pfnUnload = (PFNUNLOAD)GetProcAddress(
hDummy,
"?Unload@Dummy_Interface@@YGHPAPAVIDummyInterface@1@@Z");
вместо того, который был приведён выше. Избежать этого, можно включив в проект с DLL *.def файл и объявив в нём список экспортируемых фукций или глобальных переменных, например:
DESCRIPTION 'Dummy DLL for Win32 API'
LIBRARY dummy.dll
EXPORTS
Load @1
Unload @2
hello @3
goodbye @4
Increment @5
szDefName @6
address @7
Удачи!