重要:VC DLL编程

VC DLL编程

静态链接:每个应用程序使用函数库,必须拥有一份库的备份。多个应用程序运行时,内存中就有多份函数库代码的备份。

动态连接库:多个应用程序可以共享一份函数库的备份。

 

DLL的调用方式:即DLL的使用者在调用库中输出函数时,函数参数的压栈和出栈顺序和方法。

VC++支持四种方式:

<1>_cdecl调用方式: 也叫C调用方式,函数参数的压栈顺序是从右至左,参数的出栈方式由调用者完成,在调用DLL的函数的地方都应包含清空堆栈的代码,它是C/C++缺省的调用方式。

<2>_stdcall标准调用方式:函数参数压栈顺序是从右至左,参数出栈工作由被调用者负责完成。系统将加在函数原型定义前的”WINAPI”宏翻译为适当的调用方式,对于Win32是_stdcall调用方式。

<3>_fastcall:主要特点是调用速度快,被调用的函数参数传递不依靠堆栈,而是通过寄存器,但并不是对所有的参数传递均使用寄存器,往往只是用ECX和EDX传送前两个双字或比较小的参数,其余的参数传递仍然采用从右至左压栈方式,出栈工作由被调用的函数完成。

<4>thiscall:前三种是关键字,可以加到函数前作修饰,thiscall不是关键字,因此程序中不能显式写入,这种方式仅应用于C++成员函数,this指C++中指向对象的指针,this存放在ECX寄存器中,参数从右至左压栈,出栈由被调用者完成。

 

DLL的入口函数

DllMain()函数负责完成DLL的初始化和解说DLL调用后的清理工作。当加载DLL时,如存在DllMain()函数则调用它。

MFC DLL

  MFC DLL可以让我们的程序使用MFC库,它分为3类:

<1>Regular Dll with MFC Statically linked   (正规)

     静态链接MFC库,在DLL工程中将包含工程中所需的MFC库代码的拷贝,因此,程序可以脱离MFC库使用。

<2>Regular Dll using shared MFC Dll        (正规)

     动态共享MFC库,工程必须在装有MFC库的机器上才能运行。

MFC正规DLL编写注意问题:

     应在输出函数的函数体内首先加入:

     AFX_MANAGE_STATE(AfxGetStaticModuleState());

<3>MFC Extension Dll(using shared MFC Dll)     (扩展)

     它不但能输出函数,还能输出类,用户可以直接使用、继承这个输出类,但它不是正规DLL,如果要让非VC++程序调用,必须使用正规DLL。

MFC扩展DLL编写注意问题:

     <1>在要输出的类定义中加入:AFC_EXT_CLASS

         如:class AFX_EXT_CLASS cls{};

     <2>在要输出的函数定义前加入:AFC_EXT_CLASS

         如:AFX_EXT_CLASS int func(){}

自行编写DLL的方法

    <1>在DLL中编写的函数前加上”__declspec(dllexport)”即可导出该函数。

<2>从DLL中导出类,是在class和类名之间加入”__declspec(dllexport)”,如果只想导出类中指定的函数,可只在该函数前加上”__declspec(dllexport)”。

<3>C++为支持函数重载,采用了名称压轧,因此,DLL文件在编译时,函数名会发生改变,为保证对DLL的正确访问,可在”__declspec(dllexport)”声明之前加入”extern “c””,编译时就不会发生名称改变,但extern “c”只能用于导出全局函数,不能导出类的成员,如果在函数名前加入了调用约定(如:_stdcall),编译时还是会发生名称改变。

         也可通过模块定义文件的方式解决名称改变的问题,模块定义文件的后缀为”.def”,步骤如下:

         1新建一个文本文档,改名为”x.def”;

         2将x.def加入到工程;

3编辑x.def。EXPORTS下所写函数名如与DLL文件中函数名相同,则以所写名称导出该函数。

    <4>DLL通过GetForegroundWindow()获得正在使用它的前景窗口的句柄。

    <5>GetModuleHandle()得到一个DLL的句柄。

        GetSystemMetrics()获取系统信息。

 

系统对DLL中可改变的数据,在进程写访问时会拷贝到一个新的数据页面,如果多个进程要共享该数据,可设置节,创建节后,将数据放到节中且必须初始化:

#pragma     data_seg(“name”)          //开头

    //数据

#pragma     data_seg()      //结尾

#pragma     comment(linker,”/section:name,RWS”)

    //设为读、写、共享,也可写在.def文件中。

 

使用DLL

    要使用DLL,首先要将DLL文件映像到用户进程的地址空间中,并声明被调用的函数,然后才能进行函数调用,调用方法与一般函数相同。

    将DLL映像到进程地址空间的方法:

    <1>隐式的加载时链接

        DLL工程经编译后,产生一个.dll文件,一个.lib文件及一个包含DLL输出函数声明的.h头文件,隐式调用DLL就是将这个.lib文件链接到工程中。

        lib文件中包含了DLL允许调用的所有函数列表,链接器发现程序调用了lib文件中列出的某个函数时,会在程序的可执行文件的文件映像中加入包含这个函数的DLL文件的名字信息,当程序运行时,可执行文件被操作系统产生映像文件,系统会查看这个映像文件中关于DLL的信息,然后将这个DLL文件映像到进程的地址空间。

    链接lib文件的方法:

1加入到文件列表

2在Link项下加入

3#pragma   comment(lib,”mydll.lib”)

<2>显式的运行时链接步骤如下:

1用LoadLibrary()或AfxLoadLibrary()加载DLL或可运行模块;

2用GetProcAddress()得到要调用的DLL中函数的指针,然后使用该函数;

3使用完DLL以后,用FreeLibrary()将DLL在进程的映射解除,减少加载DLL的记数。

被调用的函数声明的方法有三种:

    <1>用”extern”声明被调用函数。

    <2>使用”__declspec(dllimport)”声明,即告诉编译器,所引用的函数或文件是从DLL中输入的,编译器能生成运行效率更高的代码。

    <3>也可将声明放在DLL编写的头文件中,在使用的文件中包含该头文件即可。

要使用DLL中导出的类,必须在使用的文件中包含该类所在的头文件!

尽量导出方法(做接口)少导出类。

标准DLL中导出函数的写法:

extern "C" BOOL __declspec(dllexport) EXPORT ShowDlg()   ///标准导出函数格式

{

    AFX_MANAGE_STATE(AfxGetStaticModuleState());//些宏不可少!

    // 此处为普通函数体

}

1.AfxGetStaticModuleState()指向当前模块状态;

2.当前函数调用结束后原模块的状态自动被恢复;

3.用于DLL中所调用MFC函数、类、资源时的模块状态切换

并在def文件中定义导出函数的序号:ShowDlg @1

在调用处写如下代码:

typedef void (*dllfun)(); //定义函数指针类型

HINSTANCE   hlib= NULL;

hlib=LoadLibrary("std_dll.dll"); //加载库

dllfun ShowDlg = NULL;//定义函数指针

ShowDlg=(dllfun)GetProcAddress(hlib,"ShowDlg");//获取库中函数地址

ShowDlg(); //调用函数

扩展DLL导出类的写法:

class AFX_EXT_CLASS clsName{};

扩展DLL中的资源使用

简单的说:每个DLL有自己特有的资源。在使用时,明确的告诉系统要使用哪个DLL的资源。现在的问题就是如何告诉系统使用哪个DLL的资源。函数:AfxSetResourceHandle() 可以完成这个功能。参数是资源的句柄。

那怎么得到某个DLL的资源句柄呢?如下:

在扩展DLL的入口函数

extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)

{

if (!AfxInitExtensionModule(ShpSymbolDLL, hInstance))

        return 0;

}

其中ShpSymbolDll 可能会因工程名不同而不同,这里就以这个名称代替来说明了,DLL的资源句柄就可以在此得到。

ShpSymbolDLL 定义:

AFX_EXTENSION_MODULE ShpSymbolDLL   = { NULL, NULL };

ShpSymbolDLL.hResource 这个就是我们要的了。其它参数请看说明。现在我们在使用某DLL的资源时只要先加入以下两行就可以正确执行了:

HINSTANCE hOld = AfxGetResourceHandle();

AfxSetResourceHandle( ShpSymbolDLL.hResource );

注意在用完之后再恢复:

AfxSetResourceHandle( hOld );

另外一个不得不提起的东西,在入口函数中有一行

new CDynLinkLibrary(ShpSymbolDLL);

旁边有一说明:将此 DLL 插入到资源链中。

的确如此。言下之意,上面所说的没什么用了?其实不然,假如DLL中有一个Dialog。 ID为120,在你调用此DLL的应用程序资源中,如果没有ID的值为120。那么,上面的都是白做了,你会得到预料中的结果。但如果应用程序中有一相同ID的对话框资源呢?请大家一试。结果就不一样了。其中的原因与new CDynLinkLibrary(ShpSymbolDLL) 相关联。

具体请看MFC中 的代码 DoModal() 就会得到解答。或看MSDN中带的例子 dllhusk,系统自动会查找相应的资源,但不会判断哪个是正确的。以找到的第一个资源为准。

另:为了编写方便,可以写一个类 ,写成全局的。

class CModuleInfo

{public:

   HMODULE    m_hModule;

   HMODULE    m_hResource;

public:

   CModuleInfo(void){}

   ~CModuleInfo(void){}

};

class AFX_EXT_CLASS CModuleStateMana

{

   HINSTANCE m_hInstOld;

public:

   CModuleStateMana();

   ~CModuleStateMana();

};

实现如下:

CModuleInfo s_mi;

CModuleStateMana::CModuleStateMana()

{

   m_hInstOld = AfxGetResourceHandle();

   AfxSetResourceHandle( s_mi.m_hModule );

}

CModuleStateMana::~CModuleStateMana()

{

   AfxSetResourceHandle( m_hInstOld );

}

然后在入口函数之前加入

extern CModuleInfo s_mi;

函数中加入:

     s_mi.m_hModule   = ShpSymbolDLL.hModule;

     s_mi.m_hResource= ShpSymbolDLL.hResource;

在调用的时候只要先加入:

CModuleStateMana msm;

就可以正确调用了。

转载于:https://www.cnblogs.com/skyofbitbit/p/3617718.html

VC DLL基础教程 用Visual Sudio 6.0新建一个工程,工程的类型选择Win32 Dynamic-Link Library.工程名任意,其他所有选项取默认新建一个cpp文件,代码如下:int add(int a ,int b){ return a+b;}如果工程类型是Win32 Console Application,那么在编译链接以后,会产生一个Debug目录,并且里面有一个exe文件这 阅读详情

相关推荐

vc dll编程整理(源代码)

vc dll编程整理(源代码) 包括 导出函数,导出类,导出MFC类,三种基本dll编程的实例 如果错误请指示

VCDLL编程

VCDLL编程 标签:调用方式 入口函数 正规DLL编写 扩展DLL编写 自行编写DLL 导出类   DLL编程 静态链接:每个应用程序使用函数库,必须拥有一份库的备份。多个应用程序运行时,内存中就有多份函数库代码的备份。 动态连接库:多个应用程序可以共

特权份子的专栏 447

VC dll编程和使用例子

里面有2个vs2005工程,分别是dll制作工程和dll使用工程,代码简洁,非常实用

VC DLL编程

在我们实际用软件时,经常可看到许多动态连接库。动态连接库有其自身的优点如节省内存、支持多语种等功能,而且,当DLL中的函数改变后,只要不是参数的改变调用起的函数并不需要重新编译。这在编程时十分有用。至于其他妙处,各位在电脑杂志、书籍中都能看到,我这里再说就是废话了. 这次小弟我所要讲的是如何在VC5.0中如何做自己的Win32 DLLs,各位要做自己的动态连接库,首先要知道DLLVC5.0中都

技术资料收集站 386

VC++动态链接库(DLL)编程深入浅出(zz)

1.概论  先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。  静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该DLL不必...

weixin_33755554的博客 639

VC编写DLL几种方法的简介

  动态连接库最大的特点就是能节省磁盘空间.当多个进程共享同一个DLL的时候,内存中只有一个DLL的代码.通过映射来使各个进程得以调用.1.用VC建立一个WIN32 DLL我们利用VC编写DLL有几种方法.如果用VC建立一个WIN32 DLL 工程.那这个工程就应该只导出C++的类或全局变量.和全局函数.方法就是在CPP文件中编写你的代码,为每个需要导出的元素进行导出办法是增加如下语句

jiangxinyu的专栏 7315

VC6.0显示行号的插件无限制版本VC6LineNumberAddin.dll:轻松提升编程效率

VC6.0显示行号的插件无限制版本VC6LineNumberAddin.dll:轻松提升编程效率 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 VC6.0显示行号的插件无限制版本VC6LineNumberAddin.dll 是一款专门为 Visual C++ 6.0 环境设计的显示行号插件。它旨在解决 VC6.0 环境中缺乏行号显示功能的痛点,让开发者能够更直观、高效...

gitblog_06755的博客 773

C语言程序OD后保存为DLL,编程技巧:vc下把.exe转成dll文件

【文章标题】: 编程技巧:vc下把.exe转成dll文件【文章作者】: vbcs【作者邮箱】: baoliangster@gmail.com【作者主页】:【下载地址】:【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!--------------------------------------------------------------------------------【详...

weixin_29854481的博客 559

VC动态链接库DLL编程深入浅出含全部源码:掌握DLL核心技巧,助力项目开发

VC动态链接库DLL编程深入浅出含全部源码:掌握DLL核心技巧,助力项目开发 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 《VC++动态链接库(DLL)编程深入浅出》是一个专为初学者设计的教程项目,涵盖了DLL编程的核心概念和技术。该项目通过详细的文字说明和丰富的示例代码,帮助读者深入理解并掌握DLL编程的精髓,从而在实际项目中灵活运用。 项目技术分析 本项目采用V...

gitblog_06721的博客 410

VC-基础:VC++动态链接库(DLL)编程深入浅出

1.概论  先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量、函数或类。在仓库的发展史上经历了“无库-静态链接库-动态链接库”的时代。  静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了。但是若使用DLL,该...

avgp36575的博客 339

vb 中调用用vc dll

 vb 中用vc dll 一般来说,VB和VC共同编程有3种方式:一种是VC生成DLL,在VB中调用DLL;一种是VC生成ActiveX控件(.ocx),在VB中插入;还有一种是在VC中生成ActiveX Automation服务器,在VB中调用。相对而言,第一种方法对VC编程者的要求最低,但要求你的伙伴进行配合,我推荐这种方法。     先说说VC++的编程。首先在VC++中生成Win32

听说读写 806

VC.net环境下轻松实现DLL编程

    在我们实际用软件时,经常可看到许多动态连接库。动态连接库有其自身的优点如节省内存、支持多语种等功能,而且,当DLL中的函数改变后,只要不是参数的改变调用起的函数并不需要重新编译。这在编程时十分有用。  而DLLVC中有三种形式:  1、Non-MFC Dlls  2、Regular Dlls  3、Extension DllsNon-MFC DLL:指的是不用MFC的类库结构,直接用C语

BlueSoal的专栏 4073

vc调用matlab函数 dll,VC++与Matlab混合编程之二:调用Matlab中M函数转换成DLL文件的形式...

VC中调用MATLAB的,总结有以下几种方法:1、是调用Matlab引擎;2、是调用Matlab中M函数转化成的dll文件;3、调用Matlab中M函数转化成c语言的函数。在本文当中重点讲解第二种方法,调用Matlab中M函数转换成DLL文件的形式。在我自己编写之前,查看了很多的文献,但是每个文献所应用的Matlab的版本不一样,很多数学函数对应的库不一样,导致最终的函数出错,本次练习和测试也是...

weixin_28889007的博客 442

VC与Matlab混合编程

转自: 本文主要介绍VC与Matlab混合编程的两种方法,并详细介绍了VC向Matlab传递复杂数据:结构体的方法,有详细代码说明。 Matlab 主要面对科学计算、可视化以及交互式程序设计的高科技计算环境,但由于Matlab开发平台上开发的程序不能脱离Matlab运行环境,因而在处理一些实际应用问题时显得灵活性不足,而VC++则在一定程度上能够弥补这一漏洞,因此,将二

top_along的专栏 2029

VC与Matlab混合编程及复杂数据:结构体传递

VC与Matlab混合编程 及复杂数据:结构体传递   本文主要介绍VC与Matlab混合编程的两种方法,并详细介绍了VC向Matlab传递复杂数据:结构体的方法,有详细代码说明。 Matlab 主要面对科学计算、可视化以及交互式程序设计的高科技计算环境,但由于Matlab开发平台上开发的程序不能脱离Matlab运行环境,因而在处理一些实际应用问题时显得灵活性不足,而VC+

xiaonianlun的专栏 2418
上一篇: VC++程序员如何做好界面
下一篇: UML关系(泛化,实现,依赖,关联(聚合,组合))
aolan7349
博客等级 码龄10年 12粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值