C++基础语法梳理:Windows 的动态链接库
cac55 2024-09-20 13:02 26 浏览 0 评论
Windows 应用程序入口函数
GUI(Graphical User Interface)应用,链接器选项:/SUBSYSTEM:WINDOWS
CUI(Console User Interface)应用,链接器选项:/SUBSYSTEM:CONSOLE
_tWinMain 与 _tmain 函数声明
Int WINAPI _tWinMain(
HINSTANCE hInstanceExe,
HINSTANCE,
PTSTR pszCmdLine,
int nCmdShow);
int _tmain(
int argc,
TCHAR *argv[],
TCHAR *envp[]);
Windows 的动态链接库(Dynamic-Link Library)
部分知识点来自《Windows 核心编程(第五版)》
用处
(1)扩展了应用程序的特性
(2)简化了项目管理
(3)有助于节省内存
(4)促进了资源的共享
(5)促进了本地化
(6)有助于解决平台间的差异
(7)可以用于特殊目的
注意
(1)创建 DLL,事实上是在创建可供一个可执行模块调用的函数
(2)当一个模块提供一个内存分配函数(malloc、new)的时候,它必须同时提供另一个内存释放函数(free、delete)
(3)在使用 C 和 C++ 混编的时候,要使用 extern "C" 修饰符
(4)一个 DLL 可以导出函数、变量(避免导出)、C++ 类(导出导入需要同编译器,否则避免导出)
(5)DLL 模块:cpp 文件中的 __declspec(dllexport) 写在 include 头文件之前
(6)调用 DLL 的可执行模块:cpp 文件的 __declspec(dllimport) 之前不应该定义 MYLIBAPI
加载 Windows 程序的搜索顺序
1、包含可执行文件的目录
2、Windows 的系统目录,可以通过 GetSystemDirectory 得到
3、16 位的系统目录,即 Windows 目录中的 System 子目录
4、Windows 目录,可以通过 GetWindowsDirectory 得到
5、进程的当前目录
6、PATH 环境变量中所列出的目录
DLL 入口函数
DllMain 函数
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
// 第一次将一个DLL映射到进程地址空间时调用
// The DLL is being mapped into the process' address space.
break;
case DLL_THREAD_ATTACH:
// 当进程创建一个线程的时候,用于告诉DLL执行与线程相关的初始化(非主线程执行)
// A thread is bing created.
break;
case DLL_THREAD_DETACH:
// 系统调用 ExitThread 线程退出前,即将终止的线程通过告诉DLL执行与线程相关的清理
// A thread is exiting cleanly.
break;
case DLL_PROCESS_DETACH:
// 将一个DLL从进程的地址空间时调用
// The DLL is being unmapped from the process' address space.
break;
}
return (TRUE); // Used only for DLL_PROCESS_ATTACH
}
载入卸载库
LoadLibrary、LoadLibraryExA、LoadPackagedLibrary、FreeLibrary、FreeLibraryAndExitThread 函数声明
// 载入库
HMODULE WINAPI LoadLibrary(
_In_ LPCTSTR lpFileName
);
HMODULE LoadLibraryExA(
LPCSTR lpLibFileName,
HANDLE hFile,
DWORD dwFlags
);
// 若要在通用 Windows 平台(UWP)应用中加载 Win32 DLL,需要调用 LoadPackagedLibrary,而不是 LoadLibrary 或 LoadLibraryEx
HMODULE LoadPackagedLibrary(
LPCWSTR lpwLibFileName,
DWORD Reserved
);
// 卸载库
BOOL WINAPI FreeLibrary(
_In_ HMODULE hModule
);
// 卸载库和退出线程
VOID WINAPI FreeLibraryAndExitThread(
_In_ HMODULE hModule,
_In_ DWORD dwExitCode
);
显示地链接到导出符号
GetProcAddress 函数声明
FARPROC GetProcAddress(
HMODULE hInstDll,
PCSTR pszSymbolName // 只能接受 ANSI 字符串,不能是 Unicode
);
DumpBin.exe 查看 DLL 信息
在 VS 的开发人员命令提示符 使用 DumpBin.exe 可查看 DLL 库的导出段(导出的变量、函数、类名的符号)、相对虚拟地址(RVA,relative virtual address)。如:
LoadLibrary 与 FreeLibrary 流程图
LoadLibrary 与 FreeLibrary 流程图
LoadLibrary
FreeLibrary
DLL 库的编写(导出一个 DLL 模块)
DLL 库的编写(导出一个 DLL 模块) DLL 头文件
// MyLib.h
#ifdef MYLIBAPI
// MYLIBAPI 应该在全部 DLL 源文件的 include "Mylib.h" 之前被定义
// 全部函数/变量正在被导出
#else
// 这个头文件被一个exe源代码模块包含,意味着全部函数/变量被导入
#define MYLIBAPI extern "C" __declspec(dllimport)
#endif
// 这里定义任何的数据结构和符号
// 定义导出的变量(避免导出变量)
MYLIBAPI int g_nResult;
// 定义导出函数原型
MYLIBAPI int Add(int nLeft, int nRight);
DLL 源文件
// MyLibFile1.cpp
// 包含标准Windows和C运行时头文件
#include <windows.h>
// DLL源码文件导出的函数和变量
#define MYLIBAPI extern "C" __declspec(dllexport)
// 包含导出的数据结构、符号、函数、变量
#include "MyLib.h"
// 将此DLL源代码文件的代码放在此处
int g_nResult;
int Add(int nLeft, int nRight)
{
g_nResult = nLeft + nRight;
return g_nResult;
}
DLL 库的使用(运行时动态链接 DLL)
DLL 库的使用(运行时动态链接 DLL)
// A simple program that uses LoadLibrary and
// GetProcAddress to access myPuts from Myputs.dll.
#include <windows.h>
#include <stdio.h>
typedef int (__cdecl *MYPROC)(LPWSTR);
int main( void )
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to the DLL module.
hinstLib = LoadLibrary(TEXT("MyPuts.dll"));
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts");
// If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) (L"Message sent to the DLL function\n");
}
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}
// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message printed from executable\n");
return 0;
}
运行库(Runtime Library)
典型程序运行步骤
(1)操作系统创建进程,把控制权交给程序的入口(往往是运行库中的某个入口函数)
(2)入口函数对运行库和程序运行环境进行初始化(包括堆、I/O、线程、全局变量构造等等)。
(3)入口函数初始化后,调用 main 函数,正式开始执行程序主体部分。
(4)main 函数执行完毕后,返回到入口函数进行清理工作(包括全局变量析构、堆销毁、关闭I/O等),然后进行系统调用结束进程。
一个程序的 I/O 指代程序与外界的交互,包括文件、管程、网络、命令行、信号等。更广义地讲,I/O 指代操作系统理解为 “文件” 的事物。
glibc 入口
_start -> __libc_start_main -> exit -> _exit
其中 main(argc, argv, __environ) 函数在 __libc_start_main 里执行。
MSVC CRT 入口
int mainCRTStartup(void)
执行如下操作:
(1)初始化和 OS 版本有关的全局变量。
(2)初始化堆。
(3)初始化 I/O。
(4)获取命令行参数和环境变量。
(5)初始化 C 库的一些数据。
(6)调用 main 并记录返回值。
(7)检查错误并将 main 的返回值返回。
C 语言运行库(CRT)
大致包含如下功能:
启动与退出:包括入口函数及入口函数所依赖的其他函数等。
标准函数:有 C 语言标准规定的C语言标准库所拥有的函数实现。
I/O:I/O 功能的封装和实现。
堆:堆的封装和实现。
语言实现:语言中一些特殊功能的实现。
调试:实现调试功能的代码。
C语言标准库(ANSI C)
包含:
标准输入输出(stdio.h)
文件操作(stdio.h)
字符操作(ctype.h)
字符串操作(string.h)
数学函数(math.h)
资源管理(stdlib.h)
格式转换(stdlib.h)
时间/日期(time.h)
断言(assert.h)
各种类型上的常数(limits.h & float.h)
变长参数(stdarg.h)
非局部跳转(setjmp.h)
今天的分享就到这里了,大家要好好学C++哟~
写在最后:对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!
编程学习书籍分享:
编程学习视频分享:
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
对于C/C++感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!
相关推荐
- 小车五位自动循环往返控制_小车自动往返控制系统
-
需求描述:用三相异步电动机拖动一辆小车在A、B、C、D、E五点之间自动循环往返运行,小车初始在A点,按下启动按钮,小车依次前进到B、C、D、E点,并分别停止2s返回到A点停止。按下停止...
- 自动灌溉系统_自动灌溉系统by
-
需求描述:PLC时钟设定每日6:00、18:00自动启动灌溉系统,每次运行15分钟后停止;非定时时段按下手动灌溉按钮,立即启动并运行15分钟;土壤湿度传感器检测到湿润时,跳过本次定时灌溉...
- 主板ERP开启还是关闭好_主板设置erp是什么
-
主板功能的开启与关闭,本质是在“节能环保”和“使用便利”之间做选择。为帮你快速决策,先给出直接结论,再深入解析原理、影响及操作步骤,让你根据自身需求精准设置。一、直接结论:ERP功能如何选?...
- 新电脑必做5项设置!做完再玩,流畅安全多用三年
-
刚拿到新电脑,兴奋之余先别急着开机畅玩!做好以下这5大设置,能让你的爱机长期保持流畅如新,安全又省心。尤其是最后一招,很多老用户都不知道!1关闭隐私常规,杜绝数据偷跑新电脑首次开机进行系统初始化时,...
- 属于 PHP 开发者的 Supervisor 实用指南
-
属于PHP开发者的Supervisor实用指南在PHP开发中,我们经常需要运行一些后台进程:队列处理、长时间运行的脚本、WebSocket服务器等。这些进程可能会因为各种原因意外退出,手...
- 领导半夜12点微信派活?三句高情商回复,反手拿捏让他不敢再烦
-
友友们大家来啦!今天来和大家一起分享精彩话题老规矩先点赞再看文!0102别在这里害人了,现在能保住工作就烧高香了,再得瑟,明天早上去办离职0304很简单,把他一起拉上,每半小时打电话或语音汇报,一两次...
- "零点黑科技!硬盘自动备份+离线神操作,服务器数据安全躺赢"
-
公司有一台服务器,数据库需要每天零点进行数据库备份,要求在本机备份一次,再在移动硬盘上异地备份一次。备份完成后硬盘自动离线。具体思路如下:数据库自动备份时间为每天0点,备份过程约需1分钟。0点时开启硬...
- 峰谷电:白天贵、晚上便宜,你家真的适合开通吗?
-
电费单又超预算了?别急着关掉空调,其实你可能错过了一个"电费打折"的机会——峰谷电。它就像电影院的日场和夜场票,白天贵、晚上便宜,聪明利用,电费真的能省下来。一、峰谷电是什么?峰谷电把...
- 电脑开机密码设置全指南:从基础到进阶的安全防护
-
在数字化时代,电脑存储着大量个人隐私和重要数据,设置开机密码是保护信息安全的第一道防线。本文将系统介绍Windows、macOS、Linux三大主流操作系统及BIOS层面的密码设置方法,同时涵盖密码管...
- 自动喷香机_香薰机自动喷香机
-
需求描述:PLC时钟设定每日9:00、14:00、18:00自动启动喷雾,每次喷雾3秒后停止;非定时时段按下手动喷雾按钮,立即喷雾3秒;香薰液缺液传感器检测到液位过低时,停止喷雾并亮报警...
- macbook系统自动启动项在哪里查看
-
了解和管理MacBook的开机自动启动项,是优化系统启动速度和运行效率的好方法。下面我来为你介绍几种查看和管理这些启动项的方法。查看和管理MacBook启动项1.通过系统设置(最简单直接的方法)...
- 想让电脑自己到点开机和关机?这4个超实用的设置方法快收好!
-
嘿,你是不是也经常忙到忘记关电脑?或者早上想用电脑时发现还没开机?别慌,今天我就跟你分享几个超实用的方法,帮你轻松搞定电脑的定时开关机设置。不管你是电脑小白还是有点基础,这篇教程都能让你秒懂操作,省时...
- 定时关机这样操作小白也会 一招设定工作日关机 指定时间关机
-
在日常使用电脑的过程中,我们常常会遇到这样的情况:晚上睡觉前忘记手动关机,导致电脑整夜运行,既浪费电又缩短硬件寿命;或者在下载大文件时,需要等待很长时间才能完成,却不能一直守在电脑前,下载完成后也无法...
- 日本无线电操作证试题,这些问题你能答的上来吗?
-
一直以来,我们对于日本的业余无线电的印象都停留在“操作能力强,爱好者数目众多”上,然而我们对于他们的业余无线电体系所知甚少。日本业余无线电操作证的等级分作四级,最基本的四级操作证书具有8MHz以下、2...
- 你知道吗?单边带信号就像DNA分子一样!
-
我们在准备B级操作证书的过程中,避免不了的要接触到一个新的名词——SSB。单边带是传统AM模式的一种特殊的形式,在传送相同的信息的过程中,其占用的带宽仅为AM模式的一半,那么SSB模式到底是怎样的一种...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)