分享
 
 
 

深入浅出Dll(介绍函数导出、类导出、钓子dll、不同语言混合编程方法、插件等的实现方法)

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

深入浅出Dll(介绍函数导出、类导出、钓子dll、不同语言混合编程方法、插件等的实现方法)

所有代码均经过测试,如有问题可留言

一。简单的dll函数调用有两种方式:

1。显式调用2。隐式调用.如下例子

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// dlltest.cpp : Dll 撰写

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#include <windows.h>

#include <stdio.h>

extern "C" __declspec(dllexport) int Add(int n1, int n2);

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{

if(ul_reason_for_call==DLL_PROCESS_ATTACH)

{

//TRACE0("DLL Initializing!\n");

}

else if(ul_reason_for_call=DLL_PROCESS_DETACH)

{

//TRACE0("DLL Terminating!\n");

}

return TRUE;

}

__declspec(dllexport) Add(int n1, int n2)

{

char szTxt[1024];

sprintf(szTxt,"%d + %d =%d",n1,n2,n1+n2);

MessageBox(0,szTxt,"Dll Respond here:",0);

return 1;

}

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// usedll.cpp : Dll 调用测试

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#include <windows.h>

//#define USESTATELIB

// 隐式链接方式:

#ifdef USESTATELIB

#pragma comment(lib,"lib\\dlltest.lib")

extern "C" __declspec(dllimport) int Add(int n1, int n2);

#endif

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

#ifndef USESTATELIB

// 显式调用方式:

HINSTANCE hIns=LoadLibrary("dlltest.dll");

if(!hIns)

{

MessageBox(0,"couldn't find dlltest.dll","error:",0);

return 0;

}

typedef int (DLL_Add)(int , int );

DLL_Add *testit=(DLL_Add*) GetProcAddress(hIns,"Add");

if(testit)

{

(*testit)(1,2);

}else

{

MessageBox(0,"couldn't find Add from dlltest.dll","error:",0);

return 0;

}

FreeLibrary(GetModuleHandle("dlltest.dll"));

#else

//隐式链接方式:

int nres= Add(1, 2);

#endif

return 0;

}

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// 二。 导出类

// 注意CTest类应该定义在文件头,dllexport最好用宏作判断定义,

// 而这里仅作测试。

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

1。dll生成:

// tdll.cpp : Defines the entry point for the DLL application.

//

#include "stdafx.h"

class __declspec(dllexport) CTest

{

private:

int m_nvalue;

public:

CTest() : m_nvalue(0) {}

int Getvalue() const;

};

int CTest::Getvalue() const

{

return m_nvalue;

}

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

return TRUE;

}

2。调用(记得把上述生成的tdll.dll及tdll.lib拷过来):

#pragma comment(lib, "tdll.lib")

class __declspec(dllimport) CTest

{

private:

int m_nvalue;

public:

CTest() : m_nvalue(1) {}

int Getvalue() const;

};

int main(int argc, char* argv[])

{

CTest a;

int kk = a.Getvalue();

return 0;

}

运行正确。

有趣的现象是:

当我把应用端的dllimport错误的改成dllexport,程序依然可以build通过

(不过注释了#pragma comment(lib, "tdll.lib")就不行),运行时结果

是1(为区别于dll中初始值0,我把应用端的初始为1)。

嗯,这是因为编译器在处理应用端的CTest时,编译确实看得见类结构,而链接时

在tdll.lib中也可找Getvalue()相应符号,所以build成功,运行时既然应用端自己

的CTest是dllexport,当然就是直接运行它了。

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

//三。使用钓子的dll

// 1.参见我的QQ本马程序:

// http://blog.gameres.com/thread.asp?BlogID=386&;threadid=13701;threadid=13701

// 2.另一个用于按F3弹出dll框供输出debug信息的dll,代码如下:

// 用vc创建一个win32dll,并在菜单中选择insert下的resource,插入一个dialog按ctrl+s存盘,并编写内容如下:

// logdll.h内容:

#ifdef LOGDLL_EXPORTS

#define LOGDLL_API __declspec(dllexport)

#else

#define LOGDLL_API __declspec(dllimport)

#endif

extern "C" LOGDLL_API void LG( const char* szTxt );

// logdll.cpp 内容:

//

#include <windows.h>

#include "logdll.h"

#include "resource.h"

// global data:

#pragma comment( linker, "section:Shared,rws" )

#pragma data_seg( "Shared" )

HHOOK g_hhook = NULL;

HINSTANCE g_hInstance = NULL;

HWND g_pLogDlg = NULL;

BOOL g_bShowDlg = FALSE;

#pragma data_seg()

//------------------------------------------------------------------------

void Init();

void Finish();

BOOL CreateLogDlg();

BOOL ShowLogDlg();

void InstallHook();

void UninstallHook();

LRESULT CALLBACK KeyboardProc( int, WPARAM, LPARAM );

INT_PTR CALLBACK LgDlgProc( HWND, UINT, WPARAM, LPARAM );

//------------------------------------------------------------------------

/*

*/

BOOL CreateLogDlg()

{

if( g_pLogDlg ) return TRUE;

if( FALSE == g_hInstance ) return FALSE;

g_pLogDlg = CreateDialog( g_hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)LgDlgProc );

return TRUE;

}

//------------------------------------------------------------------------

/*

*/

BOOL ShowLogDlg()

{

if( NULL == g_pLogDlg )

{

if( FALSE == CreateLogDlg() )

return FALSE;

}

return ShowWindow( g_pLogDlg, (g_bShowDlg = !g_bShowDlg) ? SW_SHOW : SW_HIDE );

}

//------------------------------------------------------------------------

/*

*/

void InstallHook()

{

if( g_hhook == NULL ) {

g_hhook = SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hInstance, 0 );

}

}

//------------------------------------------------------------------------

/*

*/

void UninstallHook()

{

if( g_hhook ) {

UnhookWindowsHookEx(g_hhook);

g_hhook = NULL;

}

}

//------------------------------------------------------------------------

/*

*/

LOGDLL_API void LG( const char* szTxt )

{

// here set the text info to your dialog's text ctrl

}

void Init()

{

InstallHook();

}

void Finish()

{

UninstallHook();

if( g_pLogDlg )

{

DestroyWindow( g_pLogDlg );

g_pLogDlg = NULL;

}

}

//------------------------------------------------------------------------

/*

*/

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )

{

g_hInstance = (HINSTANCE) hModule;

switch( ul_reason_for_call )

{

case DLL_PROCESS_ATTACH:

Init();

break;

case DLL_THREAD_ATTACH:

Init();

break;

case DLL_THREAD_DETACH:

Finish();

break;

case DLL_PROCESS_DETACH:

Finish();

break;

}

return TRUE;

}

//------------------------------------------------------------------------

/*

*/

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)

{

LRESULT res = CallNextHookEx( g_hhook, nCode, wParam, lParam);

if( (lParam & (1 << 31)) && (wParam == VK_F3) && (nCode == HC_ACTION) )

{

ShowLogDlg();

}

return res;

}

//------------------------------------------------------------------------

/*

*/

INT_PTR CALLBACK LgDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )

{

switch ( msg )

{

case WM_INITDIALOG:

return TRUE;

case WM_COMMAND:

switch( LOWORD(wParam) )

{

case IDCANCEL:

case IDOK:

EndDialog( hDlg, TRUE );

g_bShowDlg = FALSE;

return TRUE;

}

break;

case WM_DESTROY:

break;

}

return FALSE;

}

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// 四。不同语言混合编程方法

// 标题太夸张了点,这里只是通过一种语言编写dll给另一种语言使用而已。例如:在VC中写dll而在vb中调用。这个在我转载的文章中已有祥细例子,我就不多说了,参见:(引用别人的“库”,又少写了很多“代码”,呵呵)

http://blog.gameres.com/thread.asp?BlogID=386&;threadid=13945

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

// 五。插件dll相关撰写

// (我写了以下例子来说明3dmax的导出插件是如何编写与实现,

// 源码简单就不说明了)

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

这里我们的程序我用app.h和app.cpp实现,而别人写的插件我用plugtest.h与plugtest.cpp实现.

1.先写我们的程序(用建立普通win32程序方法创建)

// app.h头文件内容:

#include <windows.h>

// extern "C"

// Define USING_IMPORT by app's project setting that this head file local at

#ifdef USING_IMPORT

#define THIS_CLASS_EXPORT __declspec(dllimport)

#else

#define THIS_CLASS_EXPORT __declspec(dllexport)

#endif

class THIS_CLASS_EXPORT TestExport

{

public:

TestExport() {};

virtual ~TestExport() {};

virtual int DoExport() = 0;

};

class THIS_CLASS_EXPORT ClassDesc

{

public:

virtual HINSTANCE HInstance() = 0;

virtual void* Create() = 0; // { return new TestExport's Derive class }

};

// app.cpp 文件内容:

//

#include "app.h"

#include <stdio.h>

#include <IO.H>

typedef ClassDesc* (*PFN_DESC)();

void TestCall( const char* szName )

{

HINSTANCE hDll = LoadLibrary( szName );

PFN_DESC pPlugDesc = (PFN_DESC)GetProcAddress( hDll, "Get_PlugDesc" );

ClassDesc* pDesc = (*pPlugDesc)();

if( pDesc )

{

TestExport* pExp = (TestExport*)pDesc->Create();

if( pExp )

{

pExp->DoExport();

}

}

}

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

// search all dll:

struct _finddata_t c_file;

long hFile;

/* Find first .c file in current directory */

if( (hFile = _findfirst( "*.dll", &c_file )) == -1L )

printf( "No *.dll files in current directory!\n" );

else

{

TestCall( c_file.name );

/* Find the rest of the .c files */

while( _findnext( hFile, &c_file ) == 0 )

{

TestCall( c_file.name );

}

_findclose( hFile );

}

return 0;

}

下面写一个插件来测试一下:

可在vc中用普通win32 dll的创建方法来创建以下一个dll内容:

// plugtest.cpp内容

//

#include <windows.h>

#include "../app/app.h"

//#pragma comment(lib, "app.lib")

HINSTANCE g_hInstance;

// example:

// notic: must not define USING_IMPORT(because this example using for client)

class Dll_Plug : public TestExport

{

int DoExport()

{

MessageBox(0, "test ok", "ok", 0);

return 1;

}

};

class Test_plusClassDesc : public ClassDesc

{

HINSTANCE HInstance()

{

return g_hInstance;

}

void* Create()

{

return new Dll_Plug;

}

};

static Test_plusClassDesc test_plusDesc;

extern "C" THIS_CLASS_EXPORT ClassDesc* Get_PlugDesc()

{

return &test_plusDesc;

}

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

)

{

g_hInstance = (HINSTANCE)hModule;

return TRUE;

}

[注:]

1. 函数调用有不同的约定方式,其中带extern "C"的是c约定与不带

的是不同的,具体体现在输出的符号上,一般c约定的符号与函数名相同,

c++的则带xx@xxxx之类(这可用dll查看工具查看),主要是区别参数的不同(为了处理类似重载等),相关文章可参见我转载的文章:

http://blog.gameres.com/thread.asp?BlogID=386&;threadid=13945

2. dll查看工具推荐: process explorer.exe、 dependency walker.exe

这些工具非常有用,如果你的项目经常与一堆dll打交道的话就知道

怎么用它们来查出不同dll工程之间关系,查出找不到符号的原因。

相关有关工具参见:

http://blog.gameres.com/show.asp?BlogID=386&;column=469

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有