vc++ DLL开发小结

DLL开发总结

一概论

DLL(Dynamic Linkable Library),你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量,函数。

静态库和动态库都是共享代码的方式,它们的区别请参见我的上一篇博文。

  1. DLL的编制与具体的变成语言及编译器无关

只要遵循约定的DLL接口规范和调用方式,用各种语言编写的DLL都可以

相互调用,譬如Windows提供的系统DLL,在任何开发环境中都能被调用,不在乎其实VisualBasics、Visual C++还是Delphi。

  1. VC动态链接库的分类

VisualC++支持三种DLL,它们分别是Non-MFCDLL(非MFC动态库)、MFC

Regular DLL(MFC规则的DLL)、MFCExtension DLL(MFC扩展DLL)。

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

二导出函数

DLL中导出函数的声明有两种方式:一种是在函数声明中加上__declspec(dllexport),另外一种是采用模块定义(.def)文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。

①extern “C” int __declspec(dllexport) add(int x, int y);怎样使用可以参见上一篇博客——静态库与动态库的区别。

②LIBRARY dllTest

EXPORTS

add @1

.def文件的规则为:

①LIBRARY语句说明.def文件相应的DLL;

②EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数后面加@n,表示要导出函数的序号为n

③.def文件中的注释由每个注释行开始处的分号指定,且注释不能与语句同行。

使用.def文件在使用时,可以这样

hDll = LoadLibrary(“dllTest.dll”);

if(hDll!= NULL)

addFun = (lpAddFun)GetProcAddress(hDll,MAKEINTRESOURCE(1));

FreeLibrary(hDll);

其中1为导出函数的序号。

三导出变量

DLL定义的全局变量可以被调用进程访问;DLL也可以访问调用进程的全局数据,我们来看看在应用工程中引用DLL中变量的例子。

Lib.h

#ifndef LIB_H

#define LIB_H

extern intdllGlobalVar;

extern"C" int GetGlobalVar();

#endif

lib.cpp

#include"lib.h"

#include<windows.h>

intdllGlobalVar;

BOOL APIENTRYDllMain( HANDLE hModule, 

                                     DWORD ul_reason_for_call, 

                                     LPVOID lpReserved

                                     )

{

    switch (ul_reason_for_call)

       {

       case DLL_PROCESS_ATTACH:

              dllGlobalVar = 100;

              break;

       case DLL_THREAD_ATTACH:   

       case DLL_THREAD_DETACH:          

       case DLL_PROCESS_DETACH: 

              break;

    }

    return TRUE;

}

.def文件为

LIBRARY dllTest

EXPORTS

dllGlobalVarDATA

使用方法:

#include"stdafx.h"

#include<windows.h>

#include<stdio.h>

#pragmacomment(lib,"dllTest.lib")

extern intdllGlobalVar;

int main(intargc, char* argv[])

{

       printf("%d ",GetGlobalVar());

       *(int *)dllGlobalVar = 1;

       //特别要注意的是这种方法导出的并不是变量本身,而是DLL中导出变量的指针,应用程序必

       //须通过强制指针转换来使用  

       printf("%d ",GetGlobalVar());

       return 0;

}

如果执行这样的赋值操作:

dllGlobalVar= 1;

其结果是dllGlobalVar指针的内容发生变化,程序中以后再也引用不到这个变量了。所以在应用工程中引用DLL中全局变量的一个更好的方法是:

externint _declspec(dllimport) dllGlobalVar;//用_declspec(dllimport)导入

通过_declspec(dllimport)方式导入的就是DLL中全局变量本身而不再是地址了,所以建议在一切可能的情况下都使用这种方式。

四DLL导出类

point.h

#ifndefPOINT_H

#definePOINT_H

#ifdefDLL_FILE

class_declspec(dllexport) point  //导出类point

#else

class_declspec(dllimport) point  //导入类point

#endif

{

public:

       float y;

       float x;

       point();

       point(float x_coordinate,floaty_coordinate );

};

#endif

point.cpp

#ifndefDLL_FILE

#defineDLL_FILE

#endif

#include"point.h"

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

//Construction/Destruction

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

point::point()

{

}

point::point(floatx_coordinate,float y_coordinate)

{

       x = x_coordinate;

       y = y_coordinate;

}

circle.h

#ifndefCIRCLE_H

#defineCIRCLE_H

#include"point.h"      

#ifdefDLL_FILE

class_declspec(dllexport) circle  //导出类circle

#else

class_declspec(dllimport) circle  //导入类circle

#endif

{

public:

       void SetCentre(const point¢rePoint);

       void SetRadius(float r);

       float GetGirth();

       float GetArea();

       circle();

private:

       float radius;

       point centre;

};
<p>#endif</p>

circle.cpp

#ifndefDLL_FILE

#defineDLL_FILE

#endif

#include"circle.h"

#definePI 3.1415926

circle::circle()

{

   centre = point(0,0);

   radius = 0;

}

floatcircle::GetArea()

{

       return PI*radius*radius;

}

floatcircle::GetGirth()

{

    return 2*PI*radius;

}

voidcircle::SetCentre(const point ¢rePoint)

{

       centre = centrePoint;

}

voidcircle::SetRadius(float r)

{

       radius = r;

}

调用:

dllCall.cpp

#include"stdafx.h"

#include<windows.h>

#include"..\circle.h"

#pragmacomment(lib,"dllTest.lib");

intmain(int argc, char* argv[])

{

       circle c;

       point p(2.0,2.0);

       c.SetCentre(p);

       c.SetRadius(1.0);

       printf("area:%fgirth:%f",c.GetArea(),c.GetGirth());

       return 0;

}

从上述源代码可以看出,由于在DLL的类实现代码中定义了宏DLL_FILE,故在DLL的实现中所包含的类声明实际上为

Class_declspec(dllexport) point

{

…….

};

class_declspec(dllexport) circle

{

…………..

};

而在应用工程dllCall.cpp中没有定义DLL_FILE,故其包含point.h和circle.h后引入的类声明为:

Class_declspec(dllimport) point

{

……….

};

class_declspec(dllimport) circle

{

……….

};

我们往往通过在类的声明头文件中用一个宏来决定使其编译为class_declspec(dllexport) class_name还是class_declspec(dllimport) class_name版本,这样就不需要两个头文件。

讨论静态库和动态库区别的博客链接

http://blog.csdn.net/lqlblog/article/details/48086569

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-11 19:12:06

vc++ DLL开发小结的相关文章

VC++ DLL 发布到生产环境过程

最近项目中用到了VC++ DLL,在本机调试时无任何问题,但是发布出来后,COPY到另外的机器就报错,说找不到DLL,由于自身工作接触这方面比较少,经过一番折腾后,终于解决,以下为解决步骤 一,平台工具集(最终没选这个发布后也可以运行,选的VS 2015(V140),但是C++相关的工具是必须要装的),就选了Visual Studio 2015 - Windows XP (v140_xp),如图 接下来生成项目报错,C:\Program Files (x86)\MSBuild\Microsoft

VC/MFC开发中的句柄HWND

Windows开发中,经常会碰到一个常见的字眼HWND,如下 HWND hWnd; hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); HWND就是句柄,那么句柄是什么? [句柄定义] 先看Windows下面的定义,如下 DECLARE_HANDLE (HWND)

VC项目开发之单文档多视图实现-非分割窗口[转]

k_eckel:http://www.mscenter.edu.cn/blog/k_eckel 多视图是VC开发中经常要用到的技术之一,一般地实现单文档多视图有两种方式 1)通过视图分割的技术(使用CSplitterWnd实现),将窗口分割为多个部分,每个部分显示各自显示不同的视图,这种技术实现起来比较简单,并且相关的资料也很多. 2)通过一个文档关联多个视图,窗口显示整个视图. 第二种实现较第一种复杂,这里给出详细的实现方法. Step 1:使用VC 6.0新建一个Project,命名为:Mu

iOS线程开发小结

/* 方法名决定是否开启新线程(async,sync),队列类型(全局队列,串行队列)决定开启多少条线程 1.快速线程调用 *开启后台线程执行任务 [self performSelectorInBackground:@selector(test) withObject:nil]; *回到主线程执行任务 [self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; 2.GCD

vc dll的生成和使用

这两天做了打印机的上位机驱动,要生成DLL,了解了这方面的东东,记录下简单. 因为要在wince平台上使用,接口不能用MFC类,所以费劲的转换成了非MFC,也就使用Non-MFC Dlls DLL的生成: *.h #ifndef __PRINTERCONTROL_H__ #define __PRINTERCONTROL_H__ int __declspec(dllexport)PrintDC(void *p); #endif 因为要静态调用需要*.lib 所以还要生成.def文件,直接创建即可,

学习VC MFC开发必须了解的常用宏和指令

1.#include指令  包含指定的文件 2.#define指令   预定义,通常用它来定义常量(包括无参量与带参量),以及用来实现那些"表面似和善.背后一长串"的宏,它本身并不在编译过程中进行,而是在这之前(预处理过程)就已经完成了 3.#typedef指令 常用来定义一个标识符及关键字的别名它是语言编译过程的一部分,但它并不实际分配内存空间. 4.#ifndef   #else   #endif指令  条件编译.一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容

让你提前认识软件开发(51):VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改

第3部分 软件研发工作总结 VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改 [文章摘要] Pclint是一种C/C++软件代码静态分析工具.它是一种更加严格的编译器,能够发现普通编译器所不能发现的代码中的很多问题,因此被广泛应用于软件开发项目中. 本文介绍了如何在VC++集成开发环境中配置Linux下的Pclint工程,给出了C语言中pclint规则A检查的常见错误,并描述了对应的修改办法. [关键词] VC++  Pclint  配置  操作  修改 1. 前言 P

VB调用VC dll的返回方式

第一种类型:数值传递 注意:在VB中,默认变量传递方式为ByRef为地址,而传递值就是用ByVal,还要注意在C++中,int类型的变量是32位的,在VB中要用long型变量来配合.VC++部分: [cpp] view plaincopy extern "C" _declspec(dllexport) int __stdcall TestCalc(int source) { //AFX_MANAGE_STATE(AfxGetStaticModuleState()); return(++

学习VC MFC开发必须了解的常用宏和指令(转)————复习一下

1.#include指令  包含指定的文件 2.#define指令   预定义,通常用它来定义常量(包括无参量与带参量),以及用来实现那些“表面似和善.背后一长串”的宏,它本身并不在编译过程中进行,而是在这之前(预处理过程)就已经完成了 3.#typedef指令 常用来定义一个标识符及关键字的别名它是语言编译过程的一部分,但它并不实际分配内存空间. 4.#ifndef   #else   #endif指令  条件编译.一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容只在满足一