学做网站,克拉玛依 网站建设,校园网站建设途径,吉林省示范校建设专题网站前言
本篇博客主要是记录windows系统下dll开发的相关基本知识点#xff0c;并使用相关分析工具分析#xff0c;有利于初学者学习#xff0c;更是为开发者查缺补漏#xff1b;
使用dumpbin查看dll,lib,exe相关信息
VS编译器提供了查看链接库相关的工具#xff0c;安装后…前言
本篇博客主要是记录windows系统下dll开发的相关基本知识点并使用相关分析工具分析有利于初学者学习更是为开发者查缺补漏
使用dumpbin查看dll,lib,exe相关信息
VS编译器提供了查看链接库相关的工具安装后的VS编译器的安装目录内可以找到dumpbin.exe也可以在工具里直接打开dumpbin
打开VS2015 x86 x64兼容工具命令提示符输入dumpbin指令/exports是显示所有函数的指令后面是要查看的dll文件
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VCdumpbin /exports G:\bin\CustomWidget.dll执行之后便可以看到dll内相关函数信息红色框内便是函数名 也可以用dumpbin查看lib和exe信息只不过指令不是/exports具体的指令有
查看a.dll库中包含哪些函数可以使用:dumpbin /exports a.dll
查看b.exe中加载了哪些动态库可以使用dumpbin /imports b.exe
查看c.lib中包含哪些函数可以使用:dumpbin /all /rawdata:none c.lib
查看d.obj中包含哪些函数可以使用dumpbin /all /rawdata:none d.obj dll输出调试信息与debugview调试
在编写dll程序的过程中不像exe可以输出信息到控制台可以将dll中信息输出到调试信息窗口内只需要调用OutputDebugString函数别人调用此函数时调试信息也会显示在调试窗口内
int __stdcall fun1(int a, int b)
{OutputDebugString(LCamera::Run Fun);return a b;
}调用dll时可以在调试窗口内看到
dll发布后三方调用时如何查看dll内输出的信息微软提供了debugview软件可以跟踪dll内信息 点击漏斗型按钮打开过滤器设置在Include中输入Camera::在Exclude中输入WAIT_TIMEOUT这样就只显示带字符串“TRACE”的debug信息不显示带“WAIT_TIMEOUT”的调试信息不设置过滤器的话会捕获所有dll的调试信息我们只关注所监控的信息在编写dll时设置好唯一的标识符字符 exe是如何找到dll的
.dll 是动态链接库文件里面存储着函数和数据 .lib是静态数据连接库文件存储着函数名和文件位置 也就是说在执行程序时exe文件可通过lib文件找到dll文件并执行在程序中调用的函数。 Windows在查找dll文件会按照以下几种方式顺序查找 1.exe文件所在的目录下 2.进程当前的工作目录 3.Windows系统目录 4.Windows目录 5.环境变量Path下的一系列目录
C语言编译成dll,lib和C编译成dll,lib的区别
C语言编译动态链接库
首先使用VS建立一个win32的dll空项目再添加SelfDll.h文件和SelfDll.c文件编译器会根据.c文件格式默认为C的编译器 SelfDll.h文件代码如下
/**
file SelfDll.h
brief C语言导出dll
*/
#pragma once
__declspec(dllexport) int fun1(int a,int b);
__declspec(dllexport) double fun2(double a, double b);这里注意的是
_declspec(dllexport) int fun1(int a,int b); //加上_declspec(dllexport)是导出lib文件如果不加上则只有dll文件
int fun1(int a,int b); //只导出dll文件SelfDll.c文件代码如下
#include SelfDll.h
int fun1(int a, int b)
{return a b;
}double fun2(double a, double b)
{return a b;
}最终编译出来的文件如图 使用dumpbin查看c编译的dll
C编译动态链接库
VS建立一个win32的dll空项目添加SelfDll.h文件和SelfDll.cpp文件注意不是.c文件 SelfDll.h文件代码如下
/**
file SelfDll.h
brief C导出dll
*/
#pragma once
__declspec(dllexport) int fun1(int a,int b);
__declspec(dllexport) double fun2(double a, double b);SelfDll.cpp文件代码如下
#include SelfDll.h
int fun1(int a, int b)
{return a b;
}double fun2(double a, double b)
{return a b;
}编译出的dll,lib与C语言相同名称使用dumpbin查看c编译的dll
C如何使用C语言编译的链接库
从上面的图可以看出虽然函数声明与定义一样但是编译出来的结果不一样。 一个是_fun1,另一个是?fun1YAHHHZ,可以看出存在差异。 如果C程序链接C编译的动态链接库则会报错 如果C可以使用C编译的链接库需要在原先C的头文件内增加extern C关键字这样编译器便会将此处函数按照C链接编译 C项目中重新修改原先C的头文件
/**
file SelfDll.h
brief C语言导出dll
*/
#pragma once extern C
{__declspec(dllexport) int fun1(int a, int b);__declspec(dllexport) double fun2(double a, double b);
}当C编译到C这段代码时会将这段按照C编译
C导出类的动态链接库
同样的需要增加__declspec(dllexport)在.h文件内代码如下
__cdecl与__stdcall的区别
Visual Studio默认是__cdecl如果使用这个关键字以后栈的销毁是调用者来做VS自己编译的dll再用VS调用会自动销毁栈但是给其他编译器使用时就会出问题。 因此标准调用最好是自己编写__stdcall,其他编译器和其他语言比如C#,VB都会识别出这个dll并自动清理栈
__cdecl是VS默认加上的因此VS不需要添加写__stdcall这个关键字需要在函数声明和定义的时候都带上,不然编译器会认为是两个函数
分别定义一个带_stdcall的dll文件和不带_stdcall的dll文件用dumpbin查看下区别 带_stdcall的.h源码如下
/**
file SelfDll.h
brief __cdecl与__stdcall的区别
*/#pragma once extern C {
__declspec(dllexport) int __stdcall fun1(int a, int b);
__declspec(dllexport) double __stdcall fun2(double a, double b);
}带_stdcall的.cpp源码如下
#include SelfDll.hint __stdcall fun1(int a, int b)
{return a b;
}double __stdcall fun2(double a, double b)
{return a b;
}用dumpbin查看下区别 带__stdcall的 不带__stdcall的 带__stdcall的函数_fun18,这里8代表8个字节源代码fun1的形参是两个int,占8个字节带__stdcall的函数编译出的dll附带形参栈信息因此可以被其他语言或者编译器调用。
综上所述对于dll开发者而言应该考虑到二次开发者是使用C开发还是C开发最好添加一个判断C的宏因此标准的dll文件一般都有这样开头的宏定义
#ifndef SDK_API
#if (defined(_WIN32) || defined(_WIN64))
#if defined(SDK_API)
#define SDK_API __declspec(dllexport)
#else
#define SDK_API __declspec(dllimport)
#endif
#else
#ifndef __stdcall
#define __stdcall
#endif
#ifndef SDK_API
#define SDK_API
#endif
#endif
#endif#ifdef __cplusplusextern C // 使用extern C{
#endif// 设置业务消息回调接口SDK_API void __stdcall SetMsgCallBack(int a);// 初始化SDK库SDK_API void __stdcall InitNetSDK();// 登录SDK_API void __stdcall LoginServer(const int a);#ifdef __cplusplus}
#endif对于二次开发者来说如果加载dll进项目中后发现编译错误。在发现配置文件没有出错的情况下很可能开发者忘记了添加extern “C”,这时候二次开发者就需要手动在原来的.h文件内添加extern C了
def文件规范导出符号
如果为了其他语言或者编译器能够使用dll我们就需要在每一个函数签名加上extern “C” _declspec(dllexport)这一长串声明。如果需要导出的函数较多则显得非常繁琐也非常难看。为了简化这一过程VS引入了 def文件方便我们操作。 头文件便可以简化为
/**
file SelfDll.h
brief 使用def文件导出dll
*/#pragma once int __stdcall fun1(int a, int b);
double __stdcall fun2(double a, double b);在项目中加上一个.def文件内容如图所示。
在VS编译器内添加上
模块定义文件是用来描述 dll 文件的文本格式的文件其格式如下
LIBRARY libdll.dll ;dll 文件的文件名
DESCRIPTION 描述信息 ;描述信息此行可以不要
EXPORTS
lib_add 1 ;函数描述
lib_sub 2 ;函数描述第一行在 LIBRARY 后面填 dll 文件的名字分号后面是注释。 第二行DESCRIPTION描述信息此行可以忽略 第三行EXPORTS 第四行开始是 dll 文件中函数的描述可以使用 dumpbin /EXPORTS libdll.dll 命令查看其中libdll.dll 是目标 dll 的文件路径 注意def只生成dll文件是没有lib文件的如果想要生成对应的lib文件需要在dumpbin那里使用以下命令
lib /out:F:\sqlite3.lib /MACHINE:X64 /def:F:\sqlite3.defF:\sqlite3.lib是要生成的lib文件 F:\sqlite3.def是项目生成dll的def文件
__declspec(dllimport)和__declspec(dllexport)的区别
这篇博主详细分析了之间的区别结论就是 dllimport是为了更好的处理类中的静态成员变量的如果没有静态成员变量那么这个__declspec(dllimport)无所谓。 链接如下 dllimport与dllexport作用与区别 因此很多三方库的.h文件内都是这样定义
#ifdef SIMPLEDLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endifC#使用C导出的dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices; //引入三方库namespace LearnDll
{class Program{[DllImport(E:/14_learnC/LearnDll/SelfDll(C)/SelfDll/Debug/SelfDll.dll, CharSet CharSet.Ansi)]//声明函数static extern int fun1(int a, int b);static void Main(string[] args){int a 1;int b 2;int c fun1(a,b);Console.WriteLine(结果是 c );Console.ReadKey();}}
}C编译的dll库通过def文件导出C#可以直接调用