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

深入浅出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 
// 四。不同语言混合编程方法 
//             标题太夸张了点,这里只是通过一种语言编写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; 


本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/317347,如需转载请自行联系原作者
上一篇:阿里巴巴DevOps实践指南(四)| 需求的层次结构


下一篇:LC3视角:Kubernetes下日志采集、存储与处理技术实践