Initial commit

This commit is contained in:
Gentleman 2021-10-19 07:50:07 +08:00
parent 26e63f771b
commit 99b312c610
13 changed files with 347 additions and 2 deletions

View File

@ -1,3 +1,60 @@
# DllExport
# 两种方式实现DLL导出函数之dllexport与def文件导出
两种方式实现DLL导出函数之dllexport与def文件导出
# 背景
我们开发DLL的时候大部分都会导出函数。对于导出函数常用的有两种方式一种是使用 dllexport 关键字导出,另一种是使用 .def 文件导出。我个人比较喜欢用后一种方式导出函数,因为用起来比较省心、方便。
现在,我就把这部分知识整理成文档,分享给大家。
# 实现过程
## dllexport关键字方法
这种方法就是在函数声明中加上 \_\_declspec(dllexport) 关键字,同时也要加上 extern "C" 这个前缀加上extern "C"后会指示编译器这部分代码按C语言的进行编译而不是C++的。
那么, \_\_declspec(dllexport) 关键字导出函数的代码如下所示:
```c++
// 方法一 dllexport
extern "C" __declspec(dllexport) BOOL MyExportFunc_dllexport(char *pszText, char *pszCaption)
{
::MessageBox(NULL, pszText, pszCaption, MB_OK);
return TRUE;
}
```
## def文件方法
def文件方法相对于上面介绍的 \_\_declspec(dllexport) 要更简便,而且很容易理解使用。
一般我们创建的DLL工程是没有 .def 这个文件的,需要我们创建并添加到项目工程中,添加方式如下:
选中工程项目右击选择“添加”并选中“新建项”在新建项中选择“Visual C++”下的“代码”中的“模块定义文件(.def)”文件,并输入文件名称,点击“添加”按钮,即可成功添加。
![](http://www.write-bug.com/myres/static/uploads/2021/10/19/c219201b6e95976a5be78a0ecf58fb59.writebug)
添加成功后,我们在新建的 .def 模块定义文件中添加 “EXPORTS” 关键字段这个表示DLL的导出函数位置。然后在 “EXPORTS” 字段下面添加要导出函数的名称即可。如下图,导出 “MyExportFunc_def” 这个函数。注意,只需写文件名即可。
![](http://www.write-bug.com/myres/static/uploads/2021/10/19/509763b8c8b1760011ec501c4bfeb715.writebug)
这样对于要导出的函数我们按正常编写的方式编写即可不需要额外添加任何关键字只需要把要导出的函数的函数名称放在“EXPORTS”字段下面就可以成功导出函数。
```c++
// 方法一 def文件
BOOL MyExportFunc_def(char *pszText, char *pszCaption)
{
::MessageBox(NULL, pszText, pszCaption, MB_OK);
return TRUE;
}
```
# 程序测试
我们对上面的DLL工程项目进行编译链接生成DLL文件。然后使用“DEPENDS.EXE”工具查看新生成的DLL文件的导出函数。我们可以看到上述分别使用两种导出函数方法导出的导出函数均成功导出。
![](http://www.write-bug.com/myres/static/uploads/2021/10/19/6d656a399ab78772e48e04ea6f00ca7f.writebug)
# 总结
对于上面两种导出方法来说,个人推荐 .def 模块定义文件 导出方式要注意的是要记得自己手动添加这个文件并在文件中添加“EXPORTS”导出字段。

Binary file not shown.

22
src/DllExport_Test.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllExport_Test", "DllExport_Test\DllExport_Test.vcxproj", "{57FA8153-2E07-465E-BCE8-527F40EDEBE1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{57FA8153-2E07-465E-BCE8-527F40EDEBE1}.Debug|Win32.ActiveCfg = Debug|Win32
{57FA8153-2E07-465E-BCE8-527F40EDEBE1}.Debug|Win32.Build.0 = Debug|Win32
{57FA8153-2E07-465E-BCE8-527F40EDEBE1}.Release|Win32.ActiveCfg = Release|Win32
{57FA8153-2E07-465E-BCE8-527F40EDEBE1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

BIN
src/DllExport_Test.v12.suo Normal file

Binary file not shown.

View File

@ -0,0 +1,24 @@
// DllExport_Test.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
// 方法一 dllexport
extern "C" __declspec(dllexport) BOOL MyExportFunc_dllexport(char *pszText, char *pszCaption)
{
::MessageBox(NULL, pszText, pszCaption, MB_OK);
return TRUE;
}
// 方法一 def文件
BOOL MyExportFunc_def(char *pszText, char *pszCaption)
{
::MessageBox(NULL, pszText, pszCaption, MB_OK);
return TRUE;
}

View File

@ -0,0 +1,5 @@
LIBRARY
EXPORTS
MyExportFunc_def

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{57FA8153-2E07-465E-BCE8-527F40EDEBE1}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>DllExport_Test</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DLLEXPORT_TEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>DllExport_Test.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;DLLEXPORT_TEST_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>DllExport_Test.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="DllExport_Test.cpp" />
<ClCompile Include="dllmain.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="DllExport_Test.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="DllExport_Test.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="DllExport_Test.def">
<Filter>源文件</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,32 @@
========================================================================
动态链接库DllExport_Test 项目概述
========================================================================
应用程序向导已为您创建了此 DllExport_Test DLL。
本文件概要介绍组成 DllExport_Test 应用程序的每个文件的内容。
DllExport_Test.vcxproj
这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。
DllExport_Test.vcxproj.filters
这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。
DllExport_Test.cpp
这是主 DLL 源文件。
此 DLL 在创建时不导出任何符号。因此,生成时不会产生 .lib 文件。如果希望此项目成为其他某个项目的项目依赖项,则需要添加代码以从 DLL 导出某些符号,以便产生一个导出库,或者,也可以在项目“属性页”对话框中的“链接器”文件夹中,将“常规”属性页上的“忽略输入库”属性设置为“是”。
/////////////////////////////////////////////////////////////////////////////
其他标准文件:
StdAfx.h, StdAfx.cpp
这些文件用于生成名为 DllExport_Test.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。
/////////////////////////////////////////////////////////////////////////////
其他注释:
应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。
/////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,19 @@
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@ -0,0 +1,8 @@
// stdafx.cpp : 只包括标准包含文件的源文件
// DllExport_Test.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息
#include "stdafx.h"
// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用

View File

@ -0,0 +1,16 @@
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的信息
// Windows 头文件:
#include <windows.h>
// TODO: 在此处引用程序需要的其他头文件

View File

@ -0,0 +1,8 @@
#pragma once
// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h并将
// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
#include <SDKDDKVer.h>