想想还是把这个记录下吧,虽然不难,但由于平时写得不多,老是搞忘了。

1、我们来编写一个简单的DLL程序。

首先,我们来看下入口函数DllMain()。DllMain()有3个参数:

(1)hModule:DLL模块的句柄。

(2)ul_reason_for_call:DllMain函数被调用的原因。其取值有4种,分别是DLL_PROCESS_ATTACH(当DLL被某进程加载时DllMain被调用)、DLL_PROCESS_DETACH(当DLL被某进程卸载时DllMain被调用)、DLL_THREAD_ATTACH(进程中有线程被创建时DllMain被调用)、DLL_THREAD_DETACH(进程中有线程结束时DllMain被调用)。

(3)lpReserved:保留项。

函数前面的APIENTRY是一个宏,定义如下:

#define APIENTRY    WINAPI

WINAPI也是一个宏,表示一种函数调用约定。

我们需要对DllMain()进行一下填充,加个switch。后面详见例子。我们还需要为之添加一个简单的导出函数。该函数定义如下:

extern "C" __declspec(dllexport) VOID MsgBox(char *szMsg);

extern "C"表示该函数以C方式导出。

其实现如下:

VOID MsgBox(char *szMsg){
char szModuleName[MAX_PATH]={};
GetModuleFileName(NULL,szModuleName,MAX_PATH);
MessageBox(NULL,szMsg,szModuleName,MB_OK);
}

运行函数后弹出一个对话框,显示一个字符串,并显示其所在的进程的进程名。我们分别在DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH下加一个对该函数的调用。

如下:

#include <windows.h>

extern "C" __declspec(dllexport) VOID MsgBox(char *szMsg);

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved){
switch(ul_reason_for_call){
case DLL_PROCESS_ATTACH:
MsgBox("DLL_PROCESS_ATTACH");
break;
case DLL_PROCESS_DETACH:
MsgBox("DLL_PROCESS_DETACH");
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
VOID MsgBox(char *szMsg){
char szModuleName[MAX_PATH]={};
GetModuleFileName(NULL,szModuleName,MAX_PATH);
MessageBox(NULL,szMsg,szModuleName,MB_OK);
}

编译该代码,会生成两个好玩的文件:6_10_4.dll和6_10_4.lib。前面是DLL文件,后面是库文件。

2、静态调用:

创建一个控制台程序,建立一个cpp文件,添加代码如下:

#include <windows.h>

extern "C" VOID MsgBox(char *szMsg);
#pragma comment(lib,"6_10_4") int main(int argc,char* argv[]){
MsgBox("hello first dll!");
return ;
}

对该代码直接编译链接,会报错:无法找到6_10_4.lib文件。把这个文件复制到这个cpp目录下,运行会报错,提示没有找到6_10_4.dll文件。同样,也需要把该文件置于cpp目录下。至此,没有问题了,运行依次弹出三个对话框:

3、动态调用:

静态调用就是在编译程序时便把dll信息写入程序里,而动态调用则是在运行时导入dll信息。

控制台程序cpp代码如下:

#include <windows.h>

typedef VOID (*PFUNMSG)(char *);

int main(int argc,char* argv[]){
HMODULE hModule=LoadLibrary("6_10_4.dll");
if(hModule==NULL){
MessageBox(NULL,"6_10_4.dll文件不存在","DLL加载失败",MB_OK);
return -;
}
PFUNMSG pFunMsg=(PFUNMSG)GetProcAddress(hModule,"MsgBox");
pFunMsg("hello first dll!");
return ;
}

这里不要求dll文件一定在cpp目录下,在LoadLibrary函数里写入dll的路径即可。运行结果与前面的一样。

4、其他

对于未文档化的API,或是没有提供头文件的API,我们可以利用LoadLibrary()和GetProcAddress()这两个API函数来实现对前面那些API的调用。

LoadLibrary():

HMODULE LoadLibrary(
LPCTSTR lpFileName //file name of module
);

该函数只有一个参数,即要加载的DLL文件的路径。

GetProcAddress():

GetProcAddress(
HMODULE hModule, //handle to DLL module
LPCSTR lpProcName //function name
);

该函数有两个参数,hModule是模块的句柄,lpProcName指定要获取函数地址的函数名称。

另外说下,vc6自带的工具"Depends"挺好用的,可以查看dll程序的导出函数等。它在:菜单“开始”->“程序”->“Microsoft Visual Studio 6.0”->“Microsoft Visual Studio 6.0 Tools”->“Depends”。

编写DLL的更多相关文章

  1. QT编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)

    最近这阵子,接了个私活,封装一个开发包俗称的SDK给客户调用,查阅了很多人家的SDK,绝大部分用VC编写,而且VC6.0居多,估计也是为了兼容大量的XP用户及IE浏览器,XP自带了VC6.0运行库,所 ...

  2. delphi编写dll心得, 谢谢原作者的分享。转

    delphi编写dll心得 1.每个函数体(包括exports和非exports函数)后面加 'stdcall;', 以编写出通用的dll2.exports函数后面必须加'export;'(放在'st ...

  3. 如何编写Dll(用命令行编译加深理解)

    DLL的优点 简单的说,dll有以下几个优点: 1)      节省内存.同一个软件模块,若是以源代码的形式重用,则会被编译到不同的可执行程序中,同时运行这些exe时这些模块的二进制码会被重复加载到内 ...

  4. VC2010编写Dll文件(转)

    源:VC2010编写Dll文件 1. 打开VS2010[Flie / New / Project / Visual C++ / Win32 / Win32 Console Application]在下 ...

  5. 编写dll时的内存分配策略

    前一篇文章介绍了为何要共用内存管理器,有人要问可不可以在编写dll时更通用一些,可以兼顾其它编译器(如果是其它编译器的话,Delphi写的dll不能与其它语言共用内存管理器),采用一定的策略来避免在d ...

  6. C++编写DLL动态链接库的步骤与实现方法

    原文:http://www.jb51.net/article/90111.htm 本文实例讲述了C++编写DLL动态链接库的步骤与实现方法.分享给大家供大家参考,具体如下: 在写C++程序时,时常需要 ...

  7. Delphi 编写DLL动态链接库文件的知识

    一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...

  8. Delphi调用C# 编写dll动态库

    Delphi调用C# 编写dll动态库 编写C#dll的方法都一样,首先在vs2005中创建一个“类库”项目WZPayDll, using System.Runtime.InteropServices ...

  9. Delphi 编写DLL动态链接库文件的知识和样例(有详细步骤,很清楚)

    一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...

  10. windows下编写dll

    dll的优点 简单的说,dll有以下几个优点: 1) 节省内存.同一个软件模块,若是以源代码的形式重用,则会被编译到不同的可执行程序中,同时运行这些exe时这些模块的二进制码会被重复加载到内存中.如果 ...

随机推荐

  1. numpy 的三角函数运算

    numpy 的三角函数运算 cos, cosh, sin sinh, tan, tanh regular 和 hyperbolic 三角函数 arccos, arccosh, arcsin, arcs ...

  2. WPF 自定义消息框(转)

    相信很多人用过MessageBox.show(),是不是觉得这个消息框有点丑呢,反正我是觉得有点丑的,所以我自己重写了一个.先不说,上两幅图对比先: 当然,也不是很好看,不过比原有的好多了. 不多说了 ...

  3. oracle11g安装(win10)

    oracle11g安装(win10) 0.安装环境 1.安装包下载 1)http://www.oracle.com/technetwork/database/enterprise-edition/do ...

  4. 关于angular的好文推荐

    独立作用域篇 1)http://www.angularjs.cn/A09C 2)http://www.cnblogs.com/wangmeijian/p/4944030.html 理解$watch , ...

  5. Hibernate Cannot release connection 了,有办法解决!

      问题:    系统采用Spring MVC 2.5 + Spring 2.5 + Hibernate 3.2架构,其中数据源连接池采用的是Apache commons DBCP.问题是这样的,系统 ...

  6. TCP/IP网络编程系列之三(初级)

    TCP/IP网络编程系列之三-地址族与数据序列 分配给套接字的IP地址和端口 IP是Internet Protocol (网络协议)的简写,是为首发网络数据而分配给计算机的值.端口号并非赋予计算机值, ...

  7. linux下进程cpu占用过高问题定位方法

    背景 记得前段时间,同事说他们测试环境的服务器cpu使用率一直处于100%,本地又没有什么接口调用,为什么会这样?cpu使用率居高不下,自然是有某些线程一直占用着cpu资源,那又如何查看占用cpu较高 ...

  8. 使用Ajax解析数据遇到的问题

    数据格式 我最近在使用JQuery的$.ajax访问后台的时候,发现竟然无法解析返回的数据,具体的错误记不清了(以后在遇到问题先截个图),可以在浏览器的Console中看到一个错误,但是去看这条请求是 ...

  9. 【BZOJ】2007: [Noi2010]海拔(平面图转对偶图)

    题目 传送门:QWQ 分析 左上角是0,右下角是1.那么大概整张图是由0 1构成的. 那么我们要找到0和1的分界线,值就是最小割. 然后变成求原图最小割. 考虑到此题是平面图,那么就转成对偶图跑最短路 ...

  10. oracle同义词详解

    在Oracle中对用户的管理是使用权限的方式来管理的,也就是说,如果我们想使用数据库,我们就必须得有权限,但是如果是别人将权限授予了我们, 我们也是能对数据库进行操作的,但是我们必须要已授权的表的名称 ...