编写DLL
想想还是把这个记录下吧,虽然不难,但由于平时写得不多,老是搞忘了。
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的更多相关文章
- QT编写DLL给外部程序调用,提供VC/C#/C调用示例(含事件)
最近这阵子,接了个私活,封装一个开发包俗称的SDK给客户调用,查阅了很多人家的SDK,绝大部分用VC编写,而且VC6.0居多,估计也是为了兼容大量的XP用户及IE浏览器,XP自带了VC6.0运行库,所 ...
- delphi编写dll心得, 谢谢原作者的分享。转
delphi编写dll心得 1.每个函数体(包括exports和非exports函数)后面加 'stdcall;', 以编写出通用的dll2.exports函数后面必须加'export;'(放在'st ...
- 如何编写Dll(用命令行编译加深理解)
DLL的优点 简单的说,dll有以下几个优点: 1) 节省内存.同一个软件模块,若是以源代码的形式重用,则会被编译到不同的可执行程序中,同时运行这些exe时这些模块的二进制码会被重复加载到内 ...
- VC2010编写Dll文件(转)
源:VC2010编写Dll文件 1. 打开VS2010[Flie / New / Project / Visual C++ / Win32 / Win32 Console Application]在下 ...
- 编写dll时的内存分配策略
前一篇文章介绍了为何要共用内存管理器,有人要问可不可以在编写dll时更通用一些,可以兼顾其它编译器(如果是其它编译器的话,Delphi写的dll不能与其它语言共用内存管理器),采用一定的策略来避免在d ...
- C++编写DLL动态链接库的步骤与实现方法
原文:http://www.jb51.net/article/90111.htm 本文实例讲述了C++编写DLL动态链接库的步骤与实现方法.分享给大家供大家参考,具体如下: 在写C++程序时,时常需要 ...
- Delphi 编写DLL动态链接库文件的知识
一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...
- Delphi调用C# 编写dll动态库
Delphi调用C# 编写dll动态库 编写C#dll的方法都一样,首先在vs2005中创建一个“类库”项目WZPayDll, using System.Runtime.InteropServices ...
- Delphi 编写DLL动态链接库文件的知识和样例(有详细步骤,很清楚)
一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...
- windows下编写dll
dll的优点 简单的说,dll有以下几个优点: 1) 节省内存.同一个软件模块,若是以源代码的形式重用,则会被编译到不同的可执行程序中,同时运行这些exe时这些模块的二进制码会被重复加载到内存中.如果 ...
随机推荐
- c++ 中 毫秒级时间获取
#include <time.h> clock_t start,ends; start=clock(); Sleep(); ends=clock(); cout<<ends-s ...
- 连电子硬件行业都在开始使用 Git 了你还在等什么?
连电子硬件行业都在开始使用 Git 了你还在等什么? 无论二进制还是文本 Git 都可以管理. 相对于电子行业传统的复制粘贴式的版本管理, git 的版本管理先进太多太多了,没有理由不用. 虽然做不到 ...
- python之面向对象(继承)
类的继承 python之面向对象(继承) 面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制.继承完全可以理解成类之间的类型和子类型关系. 需要注意的地方:继承语法 c ...
- torcs代码
/** Info returned by driver during the race */ typedef struct { tdble steer; /**< Steer command [ ...
- cocos2d
http://www.jetbrains.com/webstorm/download/index.html 运行又有下面错误 Fatal signal 11 (SIGSEGV) at 0x000000 ...
- 今天使用VS2012遇到一个问题:"链接器工具错误 LNK2026 XXX模块对于 SAFESEH 映像是不安全的"
今天使用VS2012遇到一个问题:"链接器工具错误 LNK2026 XXX模块对于 SAFESEH 映像是不安全的" 解决方法: 1.打开该项目的“属性页”对话框. 2.单击“ ...
- [rejected] master -> master (fetch first)(non-fast forward)
git push 时候遇到的错误: hint: Updates were rejected because the tip of your current branch is behind hint: ...
- python学习(二十二) Python 中boolean
- ALSA声卡笔记4-----体验声卡
1 .配置内核支持UDA1341 (1)内核 解压内核并打上补丁 配置内核 platform 需要设置哪些配置项,先看一下platform,需要把S3c24xx-i2s.c文件配置上去,dma.c也要 ...
- MySql——编程
基本语法形式 语句块模式: 在mysql编程中,begin....end;基本代替了原来编程语句中的{...}语法. 但又有所区别: 一个bigin...end;块,可以给定一个“标识符”,并且可以使 ...