VC++动态/静态链接库 【3】

来源:互联网 发布:wkwebview js交互demo 编辑:程序博客网 时间:2024/06/04 18:04

Win32 Dll 的创建和调用:

 

1. 创建:

在VC中创建project: Win32 Dynamic-Link Library: win32Dll

 

*.cpp 的内容与上节中的静态链接库一样,不同的是头文件的实现:

 

动态链接库:extern "C" int __declspec(dllexport)add(int x, int y);//声明add为dll的导出函数。

静态链接库:extern "C" int add(int x, int y);

 

编译生成 win32Dll.lib 和 win32Dll.dll

 

2. 调用:


动态调用步骤如下:

(1) 定义函数指针:

     typedef int (* FunPtr)(int,int);
     FunPtr addFun;
(2) 加载动态链接库:
      Handle handle =LoadLibrary("win32Dll.dll");

(3) 获取函数指针调用函数:
      addFun =(FunPtr)GetProcAddress(handle ,"Add");
      int res = addFun(2,3); // 2+3;

(4) 释放动态链接库:
      FreeLibrary(handle); // 释放载入的动态库

 

静态调用:

      #pragma comment(lib,"win32Dll.lib") //告诉编译器lib文件所在的路径。

      extern "C" __declspec(dllimport) add(int x,int y);


      win32Dll.lib 文件中包含了DLL 导出函数的符号名及序号(并不含有实际的代码),经过编译将这些信息与动态链接库的文件名一起编译到exe文件中。

      当执行exe时,可以根据这些信息加载dll 并调用dll中的函数。

     这样,EXE将能直接通过函数名调用DLL的输出函数,就象调用程序内部的其他函数一样。

 

3. dll 导出函数的声明:

    采用__declspec 进行声明;

    采用模块定义(.def) 文件声明:


    必须在工程中加入lib.def文件:

    ; lib.def : 导出DLL函数
    LIBRARY dllTest
    EXPORTS

    add @ 1

    分号表示注释,dllTest 为dll名称;EXPORTS后列出要导出函数的名称,可以用@1表示导出函数的序号为1.

    因此也可以这样调用库函数:

   addFun =(FunPtr)GetProcAddress(handle , MAKEINTRESOURCE ( 1 ));

 

4. DllMain 函数:

    windows 程序在加载dll库的时候,需要一个入口函数 DllMain, 默认调用缺省的DllMain 函数。

    DllMain是Dll的内部函数,是被系统自动调用的,外部程序无法直接调用DllMain。

- ul_reason_for_call指明了被调用的原因。原因共有4种,即PROCESS_ATTACH、PROCESS_DETACH、THREAD_ATTACH和THREAD_DETACH。

- APIENTRY被定义为__stdcall,它意味着这个函数以标准Pascal的方式进行调用,也就是WINAPI方式;
- 进程中的每个DLL模块被全局唯一的32字节的HINSTANCE句柄标识,只有在特定的进程内部有效,句柄代表了DLL模块在进程虚拟空间中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,这两种类型可以替换使用,这就是函数参数hModule的来历。

 

5. __stdcall 和__cdecl

 如果通过VC++编写的DLL欲被其他语言编写的程序调用,应将函数的调用方式声明为__stdcall方式,WINAPI都采用这种方式,而C/C++缺省的调用方式却__cdecl。     

   __stdcall方式与__cdecl对函数名最终生成符号的方式不同。

   若采用C编译方式(在C++中需将函数声明为extern "C"),__stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number;

   而__cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。

#define CALLBACK __stdcall //这就是传说中的回调函数
#define WINAPI __stdcall //这就是传说中的WINAPI
#define WINAPIV __cdecl
#define APIENTRY WINAPI //DllMain的入口就在这里
#define APIPRIVATE __stdcall
#define PASCAL __stdcall


在lib.h中,应这样声明add函数:

int __stdcall add(int x, int y);

在应用工程中函数指针类型应定义为:

typedef int(__stdcall *lpAddFun)(int, int);

 

若在lib.h中将函数声明为__stdcall调用,而应用工程中仍使用typedef int (* lpAddFun)(int,int),运行时将发生错误(因为类型不匹配,在应用工程中仍然是缺省的__cdecl调用)

 

导出函数

/////////////////////////////////////////////////////////////////////////////////////////

#ifndef LIB_H
#define LIB_H
extern "C" int __declspec(dllexport)add(int x, int y);
#endif

////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "lib.h"

int add(int x, int y)
{
return x + y;
}

/////////////////////////////////////////////////////////////////////////////////////////////////

【注】windows and linux 动态/静态链接库 学习整理系列

参考资料:http://pcedu.pconline.com.cn/empolder/gj/vc/