VC++中生成DLL和LIB文件

来源:互联网 发布:python reserved word 编辑:程序博客网 时间:2024/04/29 14:58

1.概论

  先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。


  对动态链接库,我们还需建立如下概念:

  (1)DLL 的编制与具体的编程语言及编译器无关

  只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以相互调用。譬如Windows提供的系统DLL(其中包括了Windows的API),在任何开发环境中都能被调用,不在乎其是Visual Basic、Visual C++还是Delphi。

  (2)动态链接库随处可见

  我们在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这些DLL中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作。

  一般的程序员都用过类似MessageBox的函数,其实它就包含在user32.dll这个动态链接库中。由此可见DLL对我们来说其实并不陌生。

  (3)VC动态链接库的分类

  Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。

  非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。

  由于本文篇幅较长,内容较多,势必需要先对阅读本文的有关事项进行说明,下面以问答形式给出。

  问:本文主要讲解什么内容?

  答:本文详细介绍了DLL编程的方方面面,努力学完本文应可以对DLL有较全面的掌握,并能编写大多数DLL程序。

  问:如何看本文?

  答:本文每一个主题的讲解都附带了源代码例程,可以随文下载(每个工程都经WINRAR压缩)。所有这些例程都由笔者编写并在VC++6.0中调试通过。

  当然看懂本文不是读者的最终目的,读者应亲自动手实践才能真正掌握DLL的奥妙。

  问:学习本文需要什么样的基础知识?

  答:如果你掌握了C,并大致掌握了C++,了解一点MFC的知识,就可以轻松地看懂本文。

  2.静态链接库

  对静态链接库的讲解不是本文的重点,但是在具体讲解DLL之前,通过一个静态链接库的例子可以快速地帮助我们建立“库”的概念。

建立一个静态链接库

图1 建立一个静态链接库

 

  如图1,在VC++6.0中new一个名称为libTest的static library工程(单击此处下载本工程),并新建lib.h和lib.cpp两个文件,lib.h和lib.cpp的源代码如下:

//文件:lib.h

#ifndef LIB_H
#define LIB_H
extern "C" int add(int x,int y);   //声明为C编译、连接方式的外部函数
#endif

//文件:lib.cpp

#include "lib.h"
int add(int x,int y)
{
 return x + y;
}


  编译这个工程就得到了一个.lib文件,这个文件就是一个函数库,它提供了add的功能。将头文件和.lib文件提交给用户后,用户就可以直接使用其中的add函数了。

  标准Turbo C2.0中的C库函数(我们用来的scanf、printf、memcpy、strcpy等)就来自这种静态库。

  下面来看看怎么使用这个库,在libTest工程所在的工作区内new一个libCall工程。libCall工程仅包含一个main.cpp文件,它演示了静态链接库的调用方法,其源代码如下:

#include <stdio.h>
#include "../lib.h"
#pragma comment( lib, "..//debug//libTest.lib" )  //指定与静态库一起连接

int main(int argc, char* argv[])
{
 printf( "2 + 3 = %d", add( 2, 3 ) );
}

 


  静态链接库的调用就是这么简单,或许我们每天都在用,可是我们没有明白这个概念。代码中#pragma comment( lib , "..//debug//libTest.lib" )的意思是指本文件生成的.obj文件应与libTest.lib一起连接。如果不用#pragma comment指定,则可以直接在VC++中设置,如图2,依次选择tools、options、directories、library files菜单或选项,填入库文件路径。图2中加红圈的部分为我们添加的libTest.lib文件的路径。

在VC中设置库文件路径

图2 在VC中设置库文件路径

 

  这个静态链接库的例子至少让我们明白了库函数是怎么回事,它们是哪来的。我们现在有下列模糊认识了:

  (1)库不是个怪物,编写库的程序和编写一般的程序区别不大,只是库不能单独执行;

  (2)库提供一些可以给别的程序调用的东东,别的程序要调用它必须以某种方式指明它要调用之。

  以上从静态链接库分析而得到的对库的懵懂概念可以直接引申到动态链接库中,动态链接库与静态链接库在编写和调用上的不同体现在库的外部接口定义及调用方式略有差异。

 

 

VC中DLL的创建及调用:

 

方法一:

VC中DLL的创建及调用方法   
  此中只有实际才操作,而无相关理论   
    
  &sup2;             DLL的创建   
    
  首先,用VC集成开发界面中的“新建”,新建一个项目。无论是VC6.0还是VC.NET,都有建立DLL项目的选项。只不过有些稍有不同,例如VC.NET中就有ISAPI   DLL,扩展存储过程DLL等,这些都不在讨论的范围。例如我们建立了一个用静态连接MFC库的DLL项目,名称为mydll   
    
  然后,编辑mydll.cpp文件,在其中加入我们自己的函数void   go()。注意,不需要在mydll.h中声明它,而需要将函数头变成如下样子:   
    
  extern   “c”   __declspec(dllexport)   void   go()   
    
  {   
    
  //code……   
    
  }   
    
  dllexport表示这个函数是由外部调用的。   
    
  由于是否带参数,要影响到外部调用的方式,因此,我们再声明一个带参数的函数:   
    
  extern   “c”   __declspec(dllexport)   void   went(CString   str)   
    
  {   
    
  //code……   
    
  }   
    
  OK,下面编译连接形成mydll.dll文件。   
    
  &sup2;             DLL的调用   
    
  好,下面我们就用VC写个程序调用它。在调用的函数中,首先要获得DLL的句柄,有如下语句:   
    
  HINSTANCE           dllinstance;   
    
  dllinstance=::LoadLibrary(strDllUrl);   
    
  if(dllinstance==NULL)   AfxMessageBox("can't   open   dll   file");   
    
        其中strDllUrl是mydll.dll路径的字符串,这样程序才能找到它。::LoadLibrary获得参数标识的DLL文件的句柄。   
    
          获得句柄后,下面要获得函数地址以便执行它。有如下语句:   
    
          FARPROC     proc;   
    
          proc=GetProcAddress(dllinstance,"go");   
    
            if(proc==NULL)   AfxMessageBox("can't   find   function");   
    
            else   proc();   
    
  FARPROC是一个远程过程指针,通过GetProcAddress获得函数的地址。它的两个参数就是dll文件句柄和函数的名字了。   
    
  然后FARPROC就可以和go一样的使用了,它就是go   ,go   就是它。   
    
  而对于带参数的DLL中的函数,调用方法有所不同。因为对函数的调用是通过对它地址的引用进行的,这样,传入参数对不对,在函数调用程序的编译和联接过程中,无法知道其正确性。因此,要在调用程序中对DLL中带参数的函数做个声明,如mydll中的went,我们要做个声明如下:   
    
  typedef   void   (FAR   __cdecl   *MYWENT)(CString);   
    
  然后以类型MYWENT声明变量既可调用,如下:   
    
          MYWENT   myproc;   
    
          myproc   =(MYWENT)GetProcAddress(dllinstance,"go");   
    
            if(myproc   ==NULL)   AfxMessageBox("can't   find   function");   
    
            else   myproc   (“o-----yeah---------”);   
    
  注意声明的时候呢,由于DLL中WENT的定义为C语言调用规范,因此MYWENT前一定要用__cdecl,而VC中常用的__stdcall是PASCAL调用规范,不可以的。一定要注意。  

方法二:

New->MfcWiazard.dll   一路下去,就会生成一个了。


1)打开VC(我用的是VC6.0)文件->新建->Win32 Static Library 输入工程名称:Mylib

2)在工程里边新建C/C++ Header File和C++ Source File各一个,分别命名为:lib.h和lib.cpp

3)在lib.h中输入内容如下:

#ifndef _LIB_H
#define _LIB_H

#ifdef MYLIBAPI
#else

int MyFunc(int n);

#define MYLIBAPI extern "C" _declspec(dllimport)

#endif

#endif  //_LIB_H

4)在lib.cpp中输入内容如下:

#define MYLIBAPI extern "C" _declspec(dllexport)

#include "lib.h"

int MyFunc(int n)
{
 return n += 100;
}

5)先Compile(CTRL+F7),再Build(F7),现在可以查看在Debug文件中是否有Mydll.dll文件,如果没有,自己想办法(反正我是有的)

6)关闭刚才的工作空间,新建一个C++ SourceFile,命名为:Mytest.cpp(将刚才生成的Mydll.dll和dll.h拷贝到现在这个Mytest.cpp的文件目录)

文件内容如下:

#include <iostream>

#include "lib.h"

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

int main()

{

std::cout << MyFunc(8) << std::endl;

return 0;

}

7)这是运行的结果:


 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Joetao/archive/2009/05/09/4164276.aspx

0 0
原创粉丝点击