C++中DLL函数的导出和导入
如何做才能从dll中导出类
如何做才能从dll中导出类能不能在一个dll中定义一个类,然后在程序中动态链接这个dll,然后导出这个类呢?要用 MFC 的扩展DLL写倒出类定义//定义一个导出类class AFX_EXT_CLASS CMouseHook : public CObject{public:CMouseHook();virtual ~CMouseHook();BOOL StopMouseHook();BOOL StartMouseHook( HWND hOwner );};OK 了,其它和DLL编写是一样的用API也可以:class extern "C" __dllexport(import) 类名{定义;};不好意思写错了,应该是__declspec(dllimport)顶一、DLL的不同类型使用MFC可以生成两种类型的DLL:MFC扩展DLL和常规DLL。
常规DLL有可以分为动态连接和静态连接。
Visual C++还可以生成WIN32 DLL,但不是这里讨论的主要对象。
1、MFC扩展DLL每个DLL都有某种类型的接口:变量、指针、函数、客户程序访问的类。
它们的作用是让客户程序使用DLL,MFC扩展DLL可以有C++的接口。
也就是它可以导出C++类给客户端。
导出的函数可以使用C++/MFC数据类型做参数或返回值,导出一个类时客户端能创建类对象或者派生这个类。
同时,在DLL中也可以使用DLL和MFC。
Visual C++使用的MFC类库也是保存在一个DLL中,MFC扩展DLL动态连接到MFC代码库的DLL,客户程序也必须要动态连接到MFC代码库的DLL。
(这里谈到的两个DLL,一个是我们自己编写的DLL,一个装MFC类库的DLL)现在MFC代码库的DLL也存在多个版本,客户程序和扩展DLL都必须使用相同版本的MFC代码DLL。
所以为了让MFC扩展DLL能很好的工作,扩展DLL和客户程序都必须动态连接到MFC代码库DLL。
MFC动态链接库的创建和调用(类和函数的dll导出和调用)
1.新建MFC DLL工程,取名为:DLL0410
动态链接库的创建和调用(类,函数的DLL导出和调用)
2.在工程中编辑好DLL0410.h,DLL0410.cpp,DLL0410.def三个文件后编译生成对应的dll和lib文件
2.1 DLL0410.h
2.2 DLL0410.cpp
2.3 DLL0410.def
2.4 编辑好上面的3个文件编译后,用dumpbin命令查看是否有函数导出。
(如图所示,sub全局函数和add类的成员函数已经导出)
3.新建一个工程DLL0410test将生成的DLL0410.dll,DLL0410.lib以及DLL0410.h文件拷贝到 DLL0410test工程目录下
4.静态调用:在工程的DLL0410test.cpp文件中导入头文件DLL0410.h,并编写对应的静态调用代码。
同时也要在工程属性链接中加入DLL0410.lib文件。
(如果编译出错有可能是,工程属性中的常规>>字符集>>修改为 使用多字节字符集)
运行成功
5.4.动态调用:只需将生成的DLL0410.dll文件拷贝到新建工程目录下,直接在工程的
DLL0410test.cpp中编写动态调用代码即可。
不用做其他任何连接和导入头文件的操作。
运行成功。
C中DLL函数的导出和导入
1.使用DEF 文件从DLL 导出模块定义(.def) 文件是包含一个或多个描述DLL 各种属性的Module 语句的文本文件。
如果不使用__declspec(dllexport)关键字导出DLL 的函数,则DLL 需要 .def 文件。
.def 文件必须至少包含下列模块定义语句:文件中的第一个语句必须是LIBRARY 语句。
此语句将 .def 文件标识为属于DLL。
LIBRARY 语句的后面是DLL 的名称。
链接器将此名称放到DLL 的导入库中。
EXPORTS 语句列出名称,可能的话还会列出DLL 导出函数的序号值。
通过在函数名的后面加上@ 符和一个数字,给函数分配序号值。
当指定序号值时,序号值的范围必须是从1 到N,其中N 是DLL 导出函数的个数。
如果希望按序号导出函数,请参见按序号而不是按名称从DLL 导出函数以及本主题。
例如,包含实现二进制搜索树的代码的DLL 看上去可能像下面这样:LIBRARY BTREEEXPORTSInsert @1Delete @2Member @3Min @4如果使用MFC DLL 向导创建MFC DLL,则向导将为您创建主干 .def 文件并将其自动添加到项目中。
添加要导出到此文件的函数名。
对于非MFC DLL,必须亲自创建 .def 文件并将其添加到项目中。
如果导出C++ 文件中的函数,必须将修饰名放到 .def 文件中,或者通过使用外部“C”定义具有标准C 链接的导出函数。
如果需要将修饰名放到 .def文件中,则可以通过使用DUMPBIN 工具或/MAP 链接器选项来获取修饰名。
请注意,编译器产生的修饰名是编译器特定的。
如果将Visual C++ 编译器产生的修饰名放到 .def 文件中,则链接到DLL 的应用程序必须也是用相同版本的Visual C++ 生成的,这样调用应用程序中的修饰名才能与DLL 的 .def 文件中的导出名相匹配。
如果生成扩展DLL 并使用 .def 文件导出,则将下列代码放在包含导出类的头文件的开头和结尾:#undef AFX_DATA#define AFX_DATA AFX_EXT_DATAef 文件创建导出(.exp) 文件和导入库(.lib) 文件。
c语言导出函数
c语言导出函数C语言是一种广泛应用于系统编程、嵌入式开发和科学计算等领域的编程语言。
在C语言中,导出函数是一种非常重要的概念,它允许我们将函数声明为可在其他源文件中使用的公共接口。
本文将详细介绍C语言中导出函数的概念、用法和注意事项。
一、什么是导出函数在C语言中,导出函数即将函数声明为可供其他源文件调用的公共接口。
通过导出函数,我们可以将某个函数的实现代码封装在一个源文件中,并在其他源文件中通过函数声明来调用该函数。
导出函数的作用类似于其他编程语言中的类的公共方法或接口,它提供了一种模块化的编程方式,使得代码更易于维护和重用。
二、导出函数的用法要将一个函数声明为导出函数,我们需要在函数声明前加上关键字"extern"。
例如,下面是一个将函数add声明为导出函数的例子:extern int add(int a, int b);在上面的例子中,函数add被声明为一个返回类型为int、接受两个int类型参数的导出函数。
通过将函数声明为导出函数,我们可以在其他源文件中使用add函数的功能,而无需关心它的具体实现。
在使用导出函数时,我们需要注意以下几点:1. 在调用导出函数之前,我们需要包含包含该函数声明的头文件。
通常,我们会将函数声明放在一个单独的头文件中,并在需要使用该函数的源文件中通过#include指令引入该头文件。
2. 导出函数的实现代码应该放在一个独立的源文件中。
在编译时,我们需要将该源文件与调用该函数的源文件一起编译。
3. 导出函数的实现代码通常位于一个独立的源文件中,这样可以提高代码的可维护性和重用性。
通过将函数的实现代码与函数的声明分离,我们可以实现模块化的编程,使得代码更易于理解和修改。
4. 导出函数的命名应具有一定的规范性,以便其他开发人员能够清楚地理解函数的功能和用途。
三、导出函数的注意事项在使用导出函数时,我们需要注意以下几点:1. 导出函数的参数和返回值类型应与函数声明一致。
C#调用动态库,C_调用C++DLL
同上面一样,我们也举一个例子: int __stdcall FunctionName(unsigned char ¶m1, unsigned char *param2) 在 C#中对其进行调用的方法是: [DllImport(“ COM DLL path/file ”)] extern static int FunctionName(ref byte param1, ref byte param2) 看到这,可能有人会问,&是取地址,*是传送指针,为何都只用 ref 就可以了呢?一种可能的解释是 ref 是一个具有重载特性的修饰符,会自动识别是取地址还是传送指针。 在实际的情况中,我们利用参数传递地址更多还是用在传送数组首地址上。 如:byte[] param1 = new param1(6); 在这里我们声明了一个数组,现在要将其的首地址传送过去,只要将 param1 数组的第一个元素用 ref 修 饰。具体如下: [DllImport(“ COM DLL path/file ”)] extern static int FunctionName(ref byte param1[1], ref byte param2)
第四步,修改动态链接库实现,实现整数参数的输出: LIBEXPORT_API int mySum(int a,int b,int *c) { *c=a+b; return *c;
(此文详细解说了,C#调用 C++DLL 的参数传入,与传出,sting 类型的传出等) C#调用 C++编写的 COM DLL 封装库时会出现两个问题: 1. 数据类型转换问题 2. 指针或地址参数传送问题 首先是数据类型转换问题。因为 C#是.NET 语言,利用的是.NET 的基本数据类型,所以实际上是 将 C++的数据类型与.NET 的基本数据类型进行对应。 例如 C++的原有函数是: int __stdcall FunctionName(unsigned char param1, unsigned short param2) 其中的参数数据类型在 C#中,必须转为对应的数据类型。如: [DllImport(“ COM DLL path/file ”)] extern static int FunctionName(byte param1, ushort param2) 因为调用的是__stdcall 函数,所以使用了 P/Invoke 的调用方法。其中的方法 FunctionName 必须声明为 静态外部函数, 即加上 extern static 声明头。 我们可以看到,在调用的过程中, unsigned char 变为了 byte, unsigned short 变为了 ushort。变换后,参数的数据类型不变,只是声明方式必须改为.NET 语言的规范。 我们可以通过下表来进行这种转换: Win32 Types char, INT8, SBYTE, CHAR short, short int, INT16, SHORT int, long, long int, INT32, LONG32, BOOL , INT __int64, INT64, LONGLONG unsigned char, UINT8, UCHAR , BYTE unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT unsigned __int64, UINT64, DWORDLONG, ULONGLONG float, FLOAT double, long double, DOUBLE CLR Type System.SByte System.Int16 System.Int32 System.Int64 System.Byte Sys.UInt64 System.Single System.Double
VC DLL加载方法
调用DLL,首先需要将DLL文件映像到用户进程的地址空间中,然后才能进行函数调用,这个函数和进程内部一般函数的调用方法相同。
Windows提供了两种将DLL映像到进程地址空间的方法:1. 隐式的加载时链接这种方法需要DLL工程经编译产生的LIB文件,此文件中包含了DLL允许应用程序调用的所有函数的列表,当链接器发现应用程序调用了LIB文件列出的某个函数,就会在应用程序的可执行文件的文件映像中加入一些信息,这些信息指出了包含这个函数的DLL文件的名字。
当这个应用程序运行时,也就是它的可执行文件被操作系统产生映像文件时,系统会查看这个映像文件中关于DLL的信息,然后将这个DLL文件映像到进程的地址空间。
系统通过DLL文件的名称,试图加载这个文件到进程地址空间时,它寻找DLL 文件的路径按照先后顺序如下:·程序运行时的目录,即可执行文件所在的目录;·当前程序工作目录·系统目录:对于Windows95/98来说,可以调用GetSystemDirectory函数来得到,对于WindowsNT/2000 来说,指的是32位Windows的系统目录,也可以调用GetSystemDirectory函数来得到,得到的值为SYSTEM32。
·Windows目录·列在PATH环境变量中的所有目录VC中加载DLL的LIB文件的方法有以下三种:①LIB文件直接加入到工程文件列表中在VC中打开File View一页,选中工程名,单击鼠标右键,然后选中“Add Files to Project”菜单,在弹出的文件对话框中选中要加入DLL的LIB文件即可。
②设置工程的 Project Settings来加载DLL的LIB文件打开工程的 Project Settings菜单,选中Link,然后在Object/library modules 下的文本框中输入DLL的LIB文件。
③通过程序代码的方式加入预编译指令#pragma comment (lib,”*.lib”),这种方法优点是可以利用条件预编译指令链接不同版本的LIB文件。
使用VS2015创建纯C的DLL及其调用
使用VS2015创建纯C的DLL及其调用
展开全文
1. 创建一个win32项目,如下图所示
2.确定后选择下一步,应用程序类型下勾选DLL(D)选项,附加选项去掉预编译头选项(如果忘记也可以在项目属性下去掉),如下图所示:
3.确定后默认创建如下项目:
右键项目---》生成
可以正常生成
4.删除所有默认生成的文件,如下:
右键项目---》生成,这时候是可以正常生成的。
如果提示缺少预编译头之类的错误,就是创建文件的时候加上的预编译头了,看第二步。
右键项目-->属性,如下设置即可解决该问题
5.添加自己的C源文件及头文件,注意,导出的函数可通过def文件导出,也可通过
在导出函数前添加_declspec(dllexport) 声明,如下:
#define API_DECL _declspec(dllexport)
extern API_DECL void add(int a, int b);
注意:在导出函数所以对应的源文件,需包含自身头文件,否则编译时只生成Dll,不会生成lib文件(头文件函数的声明需添加_declspec(dllexport))
编译成功后,我们需要生成的Dll及对应的lib、头文件这个三个。
6.创建Demo对生成的Dll的调用
对所创建的Demo工程属性设置如下:
a.链接器—> 常规—> 附加库目录添加lib文件所在路径
b.链接器—> 输入—> 附加依赖项添加对应Dll的lib文件名
正确设置之后,Demo中包含对应的头文件即可正常调用Dll中的函数。
DLL文件的生成和引用方法
一、动态链接库什么是动态链接库?DLL三个字母对于你来说一定很熟悉吧,它是Dynamic Link Library 的缩写形式,动态链接库(DLL) 是作为共享函数库的可执行文件。
动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。
函数的可执行代码位于一个DLL 中,该DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。
DLL 还有助于共享数据和资源。
多个应用程序可同时访问内存中单个DLL 副本的内容。
和大多数程序员一样,你一定很使用过DLL吧。
也曾感受到它的带给你程序设计和编码上的好错吧今天我想和大家探讨一个主题:如何在C#创建和调用DLL(动态链接库), 其实在很大意义上而讲,DLL让我更灵活的组织编写我们的应用程序,作为软件设计者,可一个根据它来达到很高的代码重用效果。
下面我来介绍一下在C#中如何创建和调用DLL。
二、准备工作我们需要对我们接下来要做的事情做个简单的介绍,在本文我们将利用C#语言创建一个名为MyDLL.DLL的动态链接库,在这个动态链接库文件中我们将提供两个功能一个是对两个参数交换他们的值,另一个功能是求两个参数的最大公约数。
然后创建一个应用程序使用这个DLL。
运行并输出结果。
1、MySwap.csnamespace MyMethods{public class SwapClass{public static bool Swap(ref long i,ref long j){i = i+j;j = i-j;i = i-j;return true;}}}2、MyMaxCD.csnamespace MyMethods{public class MaxCDClass{public static long MaxCD(long i, long j){long a,b,temp;if(i>j){a = i;b = j;}else{b = i;a = j;}temp = a % b;while(temp!=0){a = b;b = temp;temp = a % b;}return b;}}}需要注意的是:我们在制作这两个文件的时候可以用Visual 或者其他的文本编辑器,就算是记事本也可以。
VC导出类
在测试和使用dll的工程中的头文件使用的是#define DLLCLASS_API __declspec(dllimport)表示导入
3.不论Dll工程的头文件如何实现(比如说包括内联函数等等),在测试和使用dll的工程中的头文件中全部都是声明而没有定义(即将类成员函数的实现部分去掉)
使用定义文件可以有效的避免这个问题,这种方法是利用宏定义在不同的地方产生不同的编译代码:在头文件中加入如下的代码:
#ifdef _CLASSINDLL
#define CLASSINDLL_CLASS_DECL __declspec(dllexport)
#else
#define CLASSINDLL_CLASS_DECL __declspec(dllimport)
-----------------------------------------------------------------------
要输出整个的类,对类使用_declspec(_dllexpot);要输出类的成员函数,则对该函数使用_declspec(_dllexport)。如:
class AFX_EXT_CLASS CTextDoc : public CDocument
#defineDLLCLASS_API__declspec(dllexport)
//导出一个类(包括其方法、属性)
classDLLCLASS_APICDllClass
{
public:
CDllClass(void);
voidMSG(constchar*conststr);
DLL或SO—导出符号
DLL或SO—导出符号动态链接库(DLL)/共享库(SO) —导出符号1、导出符号使用gcc编译“共享库”,采用的是linux下的风格,默认所有全局变量,函数,类(g++),全是导出的,即调用者调用共享库的时候,可以通过简单的方法,看到共享库的全部。
“共享库/so”在windows下叫“动态库/dll”,使用VC 或BC(borland c++)编译器编译动态库时,采用的是Windows的风格:即默认什么都不导出(这个DLL里的所有全局变量,类,函数,调用程序默认看不到)。
最早MS是让程序员写个.def文件,来指出哪些函数要导出(只能导出函数及数据,类不能直接导出,若导出的类成员函数,得知道c++成员函数完整的导出符号名,因为操作系统的接口是C风格的,没有类这一说)。
后来又搞了一些方法,改了,烦不胜烦,后来就添这个扩展:__declspec(dllexport)和__declspec(dllimport)Windows下最常用的两大编译器:VC/BC都支持,但这只是Windows专有的,g++不支持。
windows下的g++,仍然采用全部导出。
2、如何链接到Linux共享库.so中的函数或C++类1.先include相关头文件2.编译的时候g++加上-l选项,链接上相关的库。
例如:库文件是libMyApi.so,那么编译你的cpp是用以下的方法:g++ my.cpp -lMyApi3、__declspec(dllexport)和__declspec(dllimport)Windows动态库导出符号的3种方法(按照被推荐使用的顺序列出):1.The __declspec(dllexport) keyword in the source code2.An EXPORTS statement in a .DEF file3.An /EXPORT specification in a LINK command__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法。
提取dll资源
提取dll资源
要提取DLL资源,您可以使用以下方法之一:
1. 使用资源提取工具:您可以使用像Resource Hacker或PE Explorer等资源提取工具,通过打开DLL文件并浏览其资源字典来提取所需资源。
这些工具允许您浏览和导出DLL中的图像、文本、音频、视频等各种资源。
2. 使用开发工具:如果您是开发人员,可以使用开发工具如Visual Studio来提取DLL资源。
通过创建一个项目并将DLL 文件添加到项目中,您可以浏览并访问其中的资源。
然后,您可以使用代码将资源导出到您需要的位置。
3. 使用命令行工具:Windows提供了一些命令行工具,如命令行工具rsrc和dumpbin,您可以使用这些工具提取DLL资源。
通过执行特定的命令,您可以导出DLL资源到指定的位置。
无论您选择哪种方法,提取DLL资源时,请确保遵守软件使用许可协议和法律规定。
vc dll导出方法
vc dll导出方法VC DLL导出方法在VC(Visual C++)中,DLL(Dynamic Link Library)是一种动态链接库,它可以包含多个可执行文件。
在使用VC开发过程中,经常需要将函数或变量导出为DLL,以供其他程序使用。
本文将介绍如何在VC中导出方法为DLL,并详细讲解相关的技术和注意事项。
一、什么是VC DLL导出方法?VC DLL导出方法是指在VC中将函数或变量导出为动态链接库的过程。
通过将函数或变量导出为DLL,其他程序可以使用这些函数或变量,实现代码的共享和重用。
在VC中,导出方法可以通过使用宏、关键字或修饰符等方式实现。
二、VC DLL导出方法的实现步骤1. 创建VC项目:首先,在VC中创建一个新的项目。
可以选择“Win32 Console Application”或“Win32 DLL”等项目类型,根据实际需求选择。
2. 编写代码:在项目中编写需要导出的函数或变量。
可以使用C或C++语言编写代码,根据实际需求进行逻辑处理和功能实现。
3. 声明导出函数或变量:在函数或变量的前面加上宏、关键字或修饰符等,声明它们为导出的。
例如,在VC中可以使用__declspec(dllexport)关键字来声明导出函数或变量。
4. 生成DLL文件:编译项目并生成DLL文件。
在生成过程中,VC 会将导出的函数或变量打包为动态链接库,生成对应的DLL文件。
5. 使用DLL文件:在其他程序中引用生成的DLL文件,调用其中的导出函数或变量。
可以通过函数指针、LoadLibrary()和GetProcAddress()等方式实现。
三、VC DLL导出方法的注意事项1. 函数或变量的命名:导出的函数或变量的命名应具有一定的规范性和易读性,以方便其他程序员使用和理解。
2. 函数或变量的参数和返回值:导出的函数或变量在设计时应考虑参数的合理性和返回值的正确性,以避免出现错误或歧义。
3. 调用约定和位宽:在导出函数或变量时,需要指定调用约定和位宽,以确保在不同的编译环境中能够正确地调用和使用。
dll提取函数
dll提取函数DLL提取函数是一种在软件开发中常用的技术,它可以从动态链接库(DLL)中提取出特定的函数以供程序调用。
这种技术的应用广泛,可以在各种软件开发领域中发挥重要的作用。
要理解DLL提取函数的原理,首先需要了解动态链接库的概念。
动态链接库是一种包含可重用代码和数据的文件,它可以被多个程序共享使用。
而DLL提取函数就是通过解析动态链接库文件,获取其中特定函数的地址,并将其加载到调用程序中。
实际上,DLL提取函数的过程并不复杂。
首先,需要确定目标DLL 文件的路径,并通过操作系统提供的API函数打开该文件。
然后,通过读取文件的导出表等信息,确定需要提取的函数的名称。
最后,通过操作系统提供的API函数,可以获取到目标函数在DLL中的地址,并将其加载到调用程序中。
通过DLL提取函数,开发人员可以充分利用已有的动态链接库资源,提高软件开发的效率和质量。
同时,DLL提取函数还可以实现模块化开发,使得代码更易于维护和扩展。
然而,使用DLL提取函数也需要注意一些问题。
首先,需要确保目标DLL文件的可用性和完整性,否则可能会导致提取函数失败或出现运行时错误。
其次,需要注意函数的命名冲突问题,避免不同DLL中的函数名称相同而导致调用混淆。
此外,还需要考虑函数的参数和返回值类型等问题,以确保调用的正确性和安全性。
DLL提取函数是一种重要的软件开发技术,它可以提高开发效率和代码复用性。
通过合理使用DLL提取函数,开发人员可以更好地利用已有资源,实现高质量的软件开发。
在今后的软件开发过程中,我们应该更加重视和深入研究DLL提取函数的应用,以提升软件开发的水平和质量。
C++生成dll和调用dll的方法实例
C++⽣成dll和调⽤dll的⽅法实例本⼈根据⽹络多个相关博客帖⼦原创1)⽣成dll建⽴两个⽂件 xxx.h , xxx.cppxxx.h内容如下:#ifdef BUILD_XXX_DLL#define EXPORT __declspec(dllexport)#else#define EXPORT __declspec(dllimport)#endifextern "C"{EXPORT void example(void);... ...}xxx.cpp内容如下:#define BUILD_XXX_DLL#include "xxx.h"void example(void){}... ...然后从DOS控制台进⾏编译(假设已经安装mingw并加⼊环境变量)g++ -shared -Wl,--kill-at,--output-def,xxx.def -o xxx.dll xxx.cpp(因为C++通过修饰函数名来实现函数重载,所以我们要⽤extern "C"配合--kill-at编译选项来避免对函数名的修正,BUILD_XXX_DLL宏的作⽤是⽤来选择函数原型声明的作⽤)2)静态调⽤dll在新⽂件yyy.cpp⾥加⼊如下内容;#include "xxx.h"#pragma comment(lib,"xxx.dll")⽣成的dll不需要def⽂件和cpp⽂件也可以不包含xxx.h的话,需要把h⽂件内的函数原型声明添加进yyy.cpp编译时需要加⼊dll,类似这样:g++ -L. -o yyy.exe yyy.cpp xxx.dll3)动态调⽤dll⾸先,你需要包含windows.h#include <windows.h>你还需要⼀个句柄保存装⼊的dll⽂件HINSTANCE hDll=LoadLibrary("xxx.dll");声明所需函数的对应函数指针类型typedef void (*pfunc)(void);获得指向函数的函数指针pfunc pf=(pfunc*)GetProcAddress(hDll,"example");使⽤完毕后,要释放dll⽂件FreeLibrary(hDll);。
编译VC++类的动态链接库DLL 导出类及其中的函数
如果已经写好了一个C++的类,希望把它做成dll动态链接库,这里介绍一种简单的方法。
1、制作dll利用VC6新建工程时选择win32 dynamic-Link Library,然后添加头文件和cpp文件。
假设类名为exp,添加头文件exp.h,头文件中声明类的定义,添加exp.cpp,其中是成员函数的具体定义。
与一般写类的定义不同,在exp.h 中需要写成class __declspec(dllexport) exp{...}从而说明以后从dll要被导出的类是哪一个。
这样编译完就会产生exp.dll和exp.lib两个文件。
2、dll的调用当已经生成dll后,可以在其它程序中调用dll中的类和成员函数。
方法如下:a)把exp.dll和exp.lib复制到调用程序的执行路径下,注意不是debug 路径下。
b)在project->setting->link里添加exp.libc)把exp.h复制到调用程序的执行路径下,将__declspec(dllexport)改成__declspec(dllimport)这样在主程序中就可以使用exp.h中声明的类和它的成员函数了。
如何在VC中导出类,这是一个常有人问起的问题,下面我以一个简单的例子来说明这个问题:首先使用Wizard创建一个Win32 Dynamic-Link Library工程,然后定义一个简单的C++类CInDLL。
由于该类会被工程之外的文件所引用,所以需要对这个类进行引出。
因为只有引出后所生成的 DLL中才带有供足够的信息以在连接和运行时被正确引入到进程空间中。
有两种方法可以引出类,使用__declspec(dllexport)定义和使用定义文件。
下面先讲使用__declspec(dllexport)的方法:将类定义改为:class__declspec(dllexport) CInDLL 就可以了。
(译者:你也许不相信会有这么简单,我也不相信。
在C++类中使用dllimport和dllexport导出,
在C++类中使⽤dllimport和dllexport导出,在Windows平台下:您可以使⽤dllimport或dllexport属性声明C ++类。
这些形式意味着导⼊或导出整个类。
以这种⽅式导出的类称为可导出类。
以下⽰例定义可导出的类。
导出其所有成员函数和静态数据:#define DllExport __declspec( dllexport )class DllExport C {int i;virtual int func( void ) { return1; }};请注意,禁⽌在可导出类的成员上显式使⽤dllimport和dllexport属性。
dllexport类声明类dllexport时,将导出其所有成员函数和静态数据成员。
您必须在同⼀程序中提供所有此类成员的定义。
否则,将⽣成链接器错误。
此规则的⼀个例外适⽤于纯虚函数,您⽆需为其提供显式定义。
但是,因为抽象类的析构函数总是由基类的析构函数调⽤,所以纯虚拟析构函数必须始终提供定义。
请注意,这些规则对于不可导出的类是相同的。
如果导出类类型的数据或返回类的函数,请确保导出该类。
dllimport类声明类dllimport时,将导⼊其所有成员函数和静态数据成员。
与dllimport和dllexport在⾮类类型上的⾏为不同,静态数据成员不能在定义dllimport类的同⼀程序中指定定义。
继承和可导出的类可导出类的所有基类都必须是可导出的。
如果不是,则⽣成编译器警告。
此外,所有可访问的成员也必须是可导出的。
该规则允许DLLEXPORT类从继承dllimport的类和dllimport的类从继承DLLEXPORT类(但不建议后者)。
通常,DLL调⽤者可访问的所有内容(根据C ++访问规则)应该是可导出接⼝的⼀部分。
这包括内联函数中引⽤的私有数据成员。
选择成员导⼊/导出由于类中的成员函数和静态数据隐式具有外部链接,因此可以使⽤dllimport或dllexport属性声明它们,除⾮导出整个类。
dll中导出函数的方法
dll中导出函数的方法在DLL(Dynamic Link Library)中,导出函数是指在DLL文件中声明并可以被其他程序调用的函数。
导出函数的方法有以下几种:1. 使用导出宏:在函数声明前加上导出宏,例如在Windows平台上可以使用`__declspec(dllexport)`宏来声明导出函数。
示例代码如下:```c++__declspec(dllexport) void MyExportedFunction();```这种方法可以直接在函数的声明处指定导出,使得函数在编译过程中会被添加到导出表中。
2. 使用.def文件:在.def文件中列出要导出的函数和其他导出的符号。
在编译DLL时,可以将.def文件作为输入文件之一,以告知编译器需要导出的函数。
示例.def文件如下:```LIBRARY MyDLLEXPORTSMyExportedFunction```3. 使用Module Definition (.def)文件:通过创建.def文件来指定要导出的函数和其他符号。
在项目属性的配置中,可以将.def文件指定为Module Definition File,以告知链接器需要导出的函数。
无论使用哪种方法,导出的函数将会在DLL文件中创建一个导出表,其中包含了所有导出函数的地址。
其他程序可以通过加载DLL并获取导出函数的地址,从而调用这些函数。
拓展:除了导出函数,DLL还可以导出变量、类和数据结构等。
通过在声明前加上导出宏或在.def文件中列出,可以将这些符号导出为公共接口,以供其他程序使用。
导出的变量和数据结构可以用于共享数据,导出的类可以在不同的程序中实现代码重用。
需要注意的是,导出函数的名称和参数列表在导出和导入时必须一致,否则会导致链接错误。
因此,在使用导出函数时,需要确保函数的声明和调用处的参数列表匹配。
另外,为了确保导出函数的版本兼容性,应该遵循一定的规范。
例如,在Windows 平台上,建议使用`stdcall`调用约定,以确保在不同编译器和操作系统下的兼容性。
c#的dllimport使用方法详解
c#的dllimport使⽤⽅法详解DllImport是System.Runtime.InteropServices命名空间下的⼀个属性类,其功能是提供从⾮托管DLL导出的函数的必要调⽤信息DllImport属性应⽤于⽅法,要求最少要提供包含⼊⼝点的dll的名称。
DllImport的定义如下:复制代码代码如下:[AttributeUsage(AttributeTargets.Method)]public class DllImportAttribute: System.Attribute{public DllImportAttribute(string dllName) {…} //定位参数为dllNamepublic CallingConvention CallingConvention; //⼊⼝点调⽤约定public CharSet CharSet; //⼊⼝点采⽤的字符接public string EntryPoint; //⼊⼝点名称public bool ExactSpelling; //是否必须与指⽰的⼊⼝点拼写完全⼀致,默认falsepublic bool PreserveSig; //⽅法的签名是被保留还是被转换public bool SetLastError; //FindLastError⽅法的返回值保存在这⾥public string Value { get {…} }}⽤法⽰例:复制代码代码如下:[DllImport("kernel32")]private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);以上是⽤来写⼊ini⽂件的⼀个win32api。
⽤此⽅式调⽤Win32API的数据类型对应:DWORD=int或uint,BOOL=bool,预定义常量=enum,结构=struct。
dll导出函数的两种方式的比较
dll导出函数的两种⽅式的⽐较最初的⽹页链接已经挂了, 在此贴⼀个中间的转载链接⼀概要 vs中导出 dll的⽅法有两种: ⼀种是使⽤__declspec(dllexport), 另⼀种就是使⽤.def⽂件⽅式, 这两种⽅式的最主要区别是在导出函数的名字上, 其次还有⼀些操作的灵活性上以及功能的强弱⼆⼀个具体的例⼦1 __declspec(dllexport) ⽅式⾸先对C和C++编译(extern "C")与调⽤约定(__cdecl、__stdcall、__fastcall)进⾏组合测试:<1> C++编译__declspec(dllexport) int add(int, int);__declspec(dllexport) int __cdecl add(int, int);__declspec(dllexport) int __stdcall add(int, int);__declspec(dllexport) int __fastcall add(int, int);对于C++编译器的函数名修饰规则:不管__cdecl, __fastcall还是__stdcall调⽤⽅式,函数修饰名都是以"?"开始,后⾯是函数在名字,再后⾯是函数返回类型和参数类型按照代号拼出的参数表。
对于__stdcall⽅式,参数表的开始标⽰是"@@YG”,对于__cdecl⽅式则是"@@YA”,对于__fastcall⽅式则是"@@YI”.参数表后以"@Z”标⽰整个名字的结束,如果该函数⽆参数,则以"Z”标识结束。
<2> C编译extern "C" __declspec(dllexport) int add(int, int);extern "C" __declspec(dllexport) int __cdecl add(int, int);extern "C" __declspec(dllexport) int __stdcall add(int, int);extern "C" __declspec(dllexport) int __fastcall add(int, int);<3> 备注__declspec(dllexport)的位置:To export functions, the __declspec(dllexport) keyword must appear to the left of the calling-convention keyword, if a keyword is specified.For example:__declspec(dllexport) void __cdecl Function1(void);To export all of the public data members and member functions in a class, the keyword must appear to the left of the class name as follows:class __declspec(dllexport) CExampleExport : public CObject{ class definition };2 def⽂件导出⽅式(项⽬中添加⼀个def后缀的⽂件, 然后在项⽬属性->连接器->所有选项->模块定义⽂件)具体到测试实例,我们的def⽂件内容如下:LIBRARY "win"EXPORTSadd @1其中LIBRARY指定dll的模块名称,即dll名字,EXPORTS后的每⼀⾏指定⼀个导出函数名字,这个名字和头⽂件中的声明⼀致,后⾯可以跟@序号指定该函数的序号(这个是可选的,后⾯按序号导⼊函数的时候再详细说)。
C#调用C++编写的DLL函数,以及各种类型的参数传递(转载)
C#调用C++编写的DLL函数,以及各种类型的参数传递(转载)1. 如果函数只有传入参数,比如:C/C++ Code Copy Code To Clipboard1.//C++中的输出函数2.int __declspec(dllexport) test(const int N)3.{4.return N+10;5.}对应的C#代码为:C# Code Copy Code To Clipboard1.[DllImport("test.dll", EntryPoint = "#1")]2.public static extern int test(int m);3.4.private void button1_Click(object sender, EventArgs e)5.{6.textBox1.Text= test(10).ToString();7.}2. 如果函数有传出参数,比如:C/C++ Code Copy Code To Clipboard1.//C++2.void __declspec(dllexport) test(const int N, int& Z)3.{4.Z=N+10;5.}对应的C#代码:C# Code Copy Code To Clipboard1.[DllImport("test.dll", EntryPoint = "#1")]2.public static extern double test(int m, ref int n);3.4.private void button1_Click(object sender, EventArgs e)5.{6.int N = 0;7.test1(10, ref N);8.textBox1.Text= N.T oString();9.}3. 带传入数组:C/C++ Code Copy Code To Clipboard1.void __declspec(dllexport) test(const int N, const int n[], int& Z)2.{3.for (int i=0; i<N; i++)4.{5.Z+=n[i];6.}7.}C#代码:C# Code Copy Code To Clipboard1.[DllImport("test.dll", EntryPoint = "#1")]2.public static extern double test(int N, int[] n, ref int Z);3.4.private void button1_Click(object sender, EventArgs e)5.{6.int N = 0;7.int[] n;8.n = new int[10];9.for (int i = 0; i < 10; i++)10.{11.n[i] = i;12.}13.test(n.Length, n, ref N);14.textBox1.Text= N.T oString();15.}4. 带传出数组:C++不能直接传出数组,只传出数组指针,C/C++ Code Copy Code To Clipboard1.void __declspec(dllexport) test(const int M, const int n[], int *N)2.{3.for (int i=0; i<M; i++)4.{5.N[i]=n[i]+10;6.}7.}对应的C#代码:C# Code Copy Code To Clipboard1.[DllImport("test.dll", EntryPoint = "#1")]2.public static extern void test(int N, int[] n, [MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)] int[] Z);3.4.private void button1_Click(object sender, EventArgs e)5.{6.int N = 1000;7.int[] n, Z;8.n = new int[N];Z = new int[N];9.for (int i = 0; i < N; i++)10.{11.n[i] = i;12.}13.test(n.Length, n, Z);14.for (int i=0; i<Z.Length; i++)15.{16.textBox1.AppendT ext(Z[i].ToString()+"n");17.}18.}这里声明函数入口时,注意这句[MarshalAs(UnmanagedType.LPArray,SizeParamIndex=1)] int[] Z 在C#中数组是直接使用的,而在C++中返回的是数组的指针,这句用来转化这两种不同的类型.关于MarshalAs的参数用法以及数组的Marshaling,可以参见这篇转帖的文章:5. 传出字符数组:C++定义:C/C++ Code Copy Code To Clipboard1.void __declspec(dllexport) test(int i, double &a, double & b, char t[5])C#对应声明:C# Code Copy Code To Clipboard1.[DllImport("dll.dll", EntryPoint = "test")]2.public static extern void test(int i, ref double a, ref double b, [Out, MarshalAs(UnmanagedType.LPArray)] char[] t);3.。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.使用DEF 文件从DLL 导出模块定义(.def) 文件是包含一个或多个描述DLL 各种属性的Module 语句的文本文件。
如果不使用__declspec(dllexport)关键字导出DLL 的函数,则DLL 需要 .def 文件。
.def 文件必须至少包含下列模块定义语句:文件中的第一个语句必须是LIBRARY 语句。
此语句将 .def 文件标识为属于DLL。
LIBRARY 语句的后面是DLL 的名称。
链接器将此名称放到DLL 的导入库中。
EXPORTS 语句列出名称,可能的话还会列出DLL 导出函数的序号值。
通过在函数名的后面加上@ 符和一个数字,给函数分配序号值。
当指定序号值时,序号值的范围必须是从1 到N,其中N 是DLL 导出函数的个数。
如果希望按序号导出函数,请参见按序号而不是按名称从DLL 导出函数以及本主题。
例如,包含实现二进制搜索树的代码的DLL 看上去可能像下面这样:LIBRARY BTREEEXPORTSInsert @1Delete @2Member @3Min @4如果使用MFC DLL 向导创建MFC DLL,则向导将为您创建主干 .def 文件并将其自动添加到项目中。
添加要导出到此文件的函数名。
对于非MFC DLL,必须亲自创建 .def 文件并将其添加到项目中。
如果导出C++ 文件中的函数,必须将修饰名放到 .def 文件中,或者通过使用外部“C”定义具有标准C 链接的导出函数。
如果需要将修饰名放到 .def文件中,则可以通过使用DUMPBIN 工具或/MAP 链接器选项来获取修饰名。
请注意,编译器产生的修饰名是编译器特定的。
如果将Visual C++ 编译器产生的修饰名放到 .def 文件中,则链接到DLL 的应用程序必须也是用相同版本的Visual C++ 生成的,这样调用应用程序中的修饰名才能与DLL 的 .def 文件中的导出名相匹配。
如果生成扩展DLL 并使用 .def 文件导出,则将下列代码放在包含导出类的头文件的开头和结尾:#undef AFX_DATA#define AFX_DATA AFX_EXT_DATA// <body of your header file>#undef AFX_DATA#define AFX_DATA这些代码行确保内部使用的MFC 变量或添加到类的变量是从扩展DLL 导出(或导入)的。
例如,当使用DECLARE_DYNAMIC派生类时,该宏扩展以将CRuntimeClass成员变量添加到类。
省去这四行代码可能会导致不能正确编译或链接DLL,或在客户端应用程序链接到DLL 时导致错误。
当生成DLL 时,链接器使用 .def 文件创建导出(.exp) 文件和导入库(.lib) 文件。
然后,链接器使用导出文件生成DLL 文件。
隐式链接到DLL 的可执行文件在生成时链接到导入库。
请注意,MFC 本身使用 .def 文件从MFCx0.dll 导出函数和类。
2.使用_declspec(dllexport) 从DLL 导出Microsoft 在Visual C++ 的16 位编译器版本中引入了_export,使编译器得以自动生成导出名并将它们放到一个 .lib 文件中。
然后,此 .lib 文件就可以像静态 .lib 那样用于与DLL 链接。
在更新的编译器版本中,可以使用_declspec(dllexport)关键字从DLL 导出数据、函数、类或类成员函数。
_declspec(dllexport)会将导出指令添加到对象文件中,因此您不需要使用 .def 文件。
当试图导出C++ 修饰函数名时,这种便利最明显。
由于对名称修饰没有标准规范,因此导出函数的名称在不同的编译器版本中可能有所变化。
如果使用_declspec(dllexport),仅当解决任何命名约定更改时才必须重新编译DLL 和依赖 .exe 文件。
许多导出指令(如序号、NONAME 和PRIVATE)只能在 .def 文件中创建,并且必须使用 .def 文件来指定这些属性。
不过,在 .def 文件的基础上另外使用_declspec(dllexport)不会导致生成错误。
若要导出函数,_declspec(dllexport)关键字必须出现在调用约定关键字的左边(如果指定了关键字)。
例如:_declspec(dllexport) void _cdecl Function1(void);若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:class _declspec(dllexport) CExampleExport : public CObject{ ... class definition ... };生成DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将_declspec(dllexport)添加到头文件中的声明中。
若要提高代码的可读性,请为_declspec(dllexport)定义一个宏并对正在导出的每个符号使用该宏:#define DllExport _declspec( dllexport )_declspec(dllexport)将函数名存储在DLL 的导出表中。
如果希望优化表的大小,请参见按序号而不是按名称从DLL 导出函数。
注意:将DLL 源代码从Win16 移植到Win32 时,请用_declspec(dllexport)替换_export的每个实例。
作为参考,请在Win32 Winbase.h 头文件中搜索。
它包含_declspec(dllimport)的用法示例。
3.使用AFX_EXT_CLASS 导出和导入扩展DLL 使用AFX_EXT_CLASS宏导出类;链接到扩展DLL 的可执行文件使用该宏导入类。
用于生成扩展DLL 的相同头文件可通过AFX_EXT_CLASS宏与链接到DLL 的可执行文件一起使用。
在DLL 的头文件中,将AFX_EXT_CLASS关键字添加到类的声明中,如下所示:class AFX_EXT_CLASS CMyClass : public CDocument{// <body of class>};当定义了预处理器符号_AFXDLL和_AFXEXT时,该宏被MFC 定义为__declspec(dllexport)。
但当定义了_AFXDLL而未定义_AFXEXT时,该宏被定义为__declspec(dllimport)。
定义后,预处理器符号_AFXDLL指示共享MFC 版本正在由目标可执行文件(DLL 或应用程序)使用。
当_AFXDLL 和_AFXEXT都定义了时,这指示目标可执行文件是扩展DLL。
由于从扩展DLL 导出时,AFX_EXT_CLASS被定义为__declspec(dllexport),因此可以导出整个类,而不必将该类的所有符号的修饰名放到 .def 文件中。
此方法由MFC 示例DLLHUSK使用。
虽然使用此方法可以避免创建 .def 文件和类的所有修饰名,但由于名称可以按序号导出,因此创建 .def 文件的效率更高。
若要使用 .def 文件导出方法,请将下列代码放在头文件的开头和结尾处:#undef AFX_DATA#define AFX_DATA AFX_EXT_DATA// <body of your header file>#undef AFX_DATA#define AFX_DATA警告:导出内联函数时要小心,因为它们有可能导致版本冲突。
内联函数扩展到应用程序代码中;因此,如果以后重写内联函数,除非重新编译应用程序本身,否则内联函数不会被更新。
通常,不用重新生成使用DLL 函数的应用程序就可以更新DLL 函数。
4.导出类中的个别成员有时,您可能希望导出类中的个别成员。
例如,如果导出CDialog派生类,可能只需要导出构造函数和DoModal调用。
可以对需要导出的个别成员使用AFX_EXT_CLASS。
例如:class CExampleDialog : public CDialog{public:AFX_EXT_CLASS CExampleDialog();AFX_EXT_CLASS int DoModal();...// rest of class definition...};您不再导出类的所有成员,但由于MFC 宏的工作方式,您可能会遇到其他问题。
几个MFC 的Helper 宏实际声明或定义数据成员。
因此,还必须从DLL 导出这些数据成员。
例如,当生成扩展DLL 时,DECLARE_DYNAMIC宏的定义如下:#define DECLARE_DYNAMIC(class_name)protected:static CRuntimeClass* PASCAL _GetBaseClass();public:static AFX_DATA CRuntimeClass class##class_name;virtual CRuntimeClass* GetRuntimeClass() const;以static AFX_DATA打头的行声明类的内部静态对象。
若要正确导出该类并从客户端可执行文件访问运行时信息,必须导出此静态对象。
由于静态对象是用AFX_DATA修饰符声明的,因此只需在生成DLL 时将AFX_DATA定义为__declspec(dllexport),并在生成客户端可执行文件时将AFX_DATA 定义为__declspec(dllimport)。
由于已经以此方式定义了AFX_EXT_CLASS,因此只需参考类定义,将AFX_DATA重定义为与AFX_EXT_CLASS相同。
例如:#undef AFX_DATA#define AFX_DATA AFX_EXT_CLASSclass CExampleView : public CView{DECLARE_DYNAMIC()// ... class definition ...};#undef AFX_DATA#define AFX_DATAMFC 总是在其宏的内部定义的数据项上使用AFX_DATA符号,因此此技术适用于所有这类情况。
例如,它适用于DECLARE_MESSAGE_MAP。
注意:如果导出整个类而非选定的类成员,静态数据成员将自动导出。
5.使用 .DEF 文件的优缺点在 .def 文件中导出函数使您得以控制导出序号。
当将附加的导出函数添加到DLL 时,可以给它们分配更高的序号值(高于任何其他导出函数)。
当您进行此操作时,使用隐式链接的应用程序不必与包含新函数的新导入库重新链接。
这非常重要,例如,在设计将由许多应用程序使用的第三方DLL 时。