DLL 的编写,引用,导出 .

一:编程环境:VC6.0

1.编写Win32的DLL:

   A.File->New->(Projects)Win32-Dynamic Link Library

   指定Project Name,OK,选择一个空的工程,OK;

   B.File->New->C++ Source File;

   C.在其中写入函数,类等等,编译链接,生成*.dll;举例如下:

//dll2.cpp中:

  int _stdcall add_33(int a,int b)
{
 return a+b;
}

int _stdcall substract_33(int a,int b)
{
 return a-b;
}

2.DLL中函数的导出:

   A.用 _declspec(dllexport) 修饰,如下:

_declspec(dllexport) int _stdcall add_33(int a,int b)
{
 return a+b;
}

_declspec(dllexport) int _stdcall substract_33(int a,int b)
{
 return a-b;
}

此时,导出的函数名称不一定与DLL源代码中的函数名称一致(因为会发生名字改编);

 

 B.保持源文件不变,在DLL工程中加入一个.def文件,其内容如下:

;*.def文件中的注释形式:采用分号引出一行(跟汇编一样)

;这种形式,导出的函数名将为add 和 substract
LIBRARY DLL2

EXPORTS
substract=substract_33
add=add_33

 

 

;这种形式,导出的函数名将为add_33 和 substract_33(保持源代码中的函数名称不变,不发生名字改编)
LIBRARY DLL2

EXPORTS
substract_33
add_33

 

C.若同时在源代码中用_declspec(dllexport)修饰,并且DLL工程中加入了.def文件,若未采用..=..方式,则导出函数名称以.def文件中约定的为准;若采用了..=..形式,则导出函数名同时存在等号左边指定的函数名称和名字改编后的函数名称,且调用者使用用二者均可;

 

D.依序号导出函数:

  1.若保留导出函数名,默认情况下,序号从1开始开始排,后续函数序号依次增加;

  2.若保留导出函数名,可以指定序号,形式如下:

EXPORTS
MyDLLFunc_1 @3
MyDLLFunc_2

此时,序号从3开始排,后续函数序号依次连续增加;

 

若形式如下:

EXPORTS
MyDLLFunc_1 @3
MyDLLFunc_2 @5
MyDLLFunc_3 @7
MyDLLFunc_4
MyDLLFunc_5

则,序号从指定的最小的数字开始排,除保证指定的几个函数的序号外,其余未指定序号的函数的序号依次填入,保证序号的连续;(若未指定序号的函数数量不足以使序号连续呢???)

 

  3.若不保留导出函数名,只按序号导出时:

意思就是只有序号没有函数名.(什么?不导出序号也不导出函数名? 链接器不答应.)

把 def 文件内容换成这样子:
EXPORTS
MyDLLFunc_1 @3 NONAME
MyDLLFunc_2 @5 NONAME

用PE工具查看结果:
No name rva: 00004E30 ord:   3
No name rva: 00002F60 ord:   5

3.DLL中函数的调用:

A.静态调用:

  1>.将DLL工程编译生成的.lib和.dll文件,复制到测试工程目录下;

  2>.在Project-->Settings-->Link-->Object/Library Modules中,写入lib文件的名称;/或者,在要用该函数的cpp文件对应的.h文件中,加入形式如下的代码:#pragma comment(lib,"dll1.lib")

  3>.在要用到DLL中函数的cpp文件对应的头文件中,加入要引用的函数的原型声明;/或者,在编写DLL时,加入一个头文件,在其中记录要导出的DLL函数的原型声明(注意其中,不再是dllexport,而是dllimport),将该头文件提供给DLL的使用者,包含进使用者的工程即可;

  4>.在cpp文件中正常使用DLL中的函数;

B.动态调用:

  1>.将DLL工程编译生成的.dll文件,复制到测试工程目录下;

  2>.在要用到DLL中函数的cpp文件中,添加如下形式的代码:

     //显式地动态加载动态链接库:
 HINSTANCE hInst;
 hInst = LoadLibrary("DLL2.dll");
 if(hInst != NULL)
 {
  typedef int (_stdcall *ADDPROC) (int a,int b); //定义函数指针(注意:此处的调用约定必须与DLL导出函数保持一致)
  //ADDPROC Add = (ADDPROC)GetProcAddress(hInst,"add");
  ADDPROC Add = (ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1)); //根据序号访问DLL中的导出函数(导出函数的序号可以用dumpbin工具看到(ordinal列))
  if(Add != NULL)
  {
   CString strTmp;
   strTmp.Format("3+5=%d",Add(3,5));
   MessageBox(strTmp);
  }
  else
  {
   MessageBox("获取函数/"add/"入口地址失败!");
  }
  FreeLibrary(hInst);//释放对DLL的引用
  return;
 }
 else
 {
  MessageBox("加载动态链接库/"DLL2.dll/"失败!");
  return;
 } 

 

 

4.导出DLL中定义的类:

   1>.可以用  _declspec(dllexport) 修饰,此时,可以导出整个类,也可以只导出类的一部分成员函数;

   2>.不能用extern "C"方式导出类;

 

5.关于名字改编:

  1>.extern "C"修饰;(注意:如果函数的调用约定发生了变化(如由默认的_cdecl变成了_stdcall),即使在声明这些导出函数时使用了extern "C"限定符,它们的名字仍然会发生改编)

  2>.用.def文件(模块定义文件)指定;

 

6.调用约定:_stdcall,_cdecl等;

 

7.工具的使用:dumpbin.exe(命令行界面), depends(图形界面)

 

原文地址:http://blog.csdn.net/yang_seal/article/details/5954566

你可能感兴趣的:(dll,VC)