羽夏笔记——Win32(非WinAPI)
写在前面
本笔记是由本人独自整理出来的,图片来源于网络。本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
本篇文章主要是让读者对
Win32基本知识和底层有一个简单的了解,并不是详细介绍WinAPI的使用,如果有这个想法的请不要继续阅读,以免浪费时间。
Win32碎碎念
- 文字编码:常见的有
ASCII
、GB2312
、Unicode
等。 - Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。Unicode不一定只占两个字节,也可能是一个字节或者多个字节。
- TCHAR是一个宏,它是ASCII编码还是Unicode编码取决于项目的设置。
- 每个进程都有一个句柄表;多进程共享一个内核对象;句柄是否“可以”被继承。
- 如果句柄不通过继承得到,如果通过调用打开内核对象的API得到的句柄,和源创建内核对象得到的句柄可能是不同的。
- 模块目录与工作目录:当前模块路径是不变的,文件放在哪就在哪。工作路径是父进程通过CreateProcess这个API传给。
- 把所有引用线程对象CloseHandle,并不会真正销毁该线程对象,除非该线程执行完毕或被Terminate。
- malloc是假申请内存,它的本质的HeapAlloc,都是VirtualAlloc提前申请好的私有内存。
- 在局部变量创建线程并给线程传参时,要确保这个局部变量的生命周期比线程长,否则局部变量所在函数执行完毕堆栈被清空导致错误。
- 进程的虚拟内存只有使用时才挂上对应的物理页(物理内存按照4KB为一页管理)
- 一个程序真正拥有低2GB的空间(相对4GB)
- 消息队列:每个线程只有一个消息队列
TranslateMessage
函数的作用是把键盘消息转化为字符消息(WM_CHAR)
☀️ UTF-16
/UTF-8
/UTF-32
是Unicode
的实现方式
1️⃣
UTF-16
UTF-16编码以
16位无符号整数为单位,注意是16位为一个单位,不 表示一个字符就只有16位。这个要看字符的
Unicode编码处于什么范围而定,有可能是2个字节,也可能是4个字节。现在机器上的
Unicode编码一般指的就是
UTF-16。 2️⃣
UTF-8编码规则(网络传输中含有较多字母时建议使用) | Unicode编码(16进制) | UTF-8字节流(二进制) | | ------------------- | ----------------------------------- | | 000000 - 00007F | 0xXXXXXX | | 000080 - 0007FF | 110xxxxx 10xxxxxx | | 000800-00FFFF | 1110xxxx 10xxxxxx 10xxxxxx | | 010000- 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
3️⃣
UTF-32:以
4个字节为单位,类比
UTF-16
☀️ BOM(Byte Order Mark)
LE:小端存储;BE:大端存储
BOM | |
---|---|
UTF-8 | EF BB BF |
UTF-16LE | FF FE |
UTF-16BE | FE FF |
☀️ C语言的宽字符
char(多字节字符类型) | wchar_t(宽字符类型) |
---|---|
printf | wprintf |
strlen | wcslen |
strcpy | wcscpy |
☀️ Win系统中几个重要的DLL
- Kernel32.dll:最核心的功能模块,比如管理内存、进程和线程相关的函数等。
- User32.dll:是Windows用户界面相关应用程序接口,如创建窗口和发送消息等。
- GDI32.dll:全称是Graphical Device Interface(图形设备接口),包含用于画图和显示文本的函数。
☀️ 进程内存空间的地址划分
☀️ 进程的创建
1️⃣ 任何进程都是别的进程创建的: CreateProcess() 2️⃣ 创建过程
- 映射EXE文件
- 创建内核对象EPROCESS
- 映射系统DLL(ntdll.dll)
- 创建线程内核对象ETHREAD
- 如果是挂起的方式创建的(CREATE_SUSPENDED),就在这停了,等你Resume。
- 系统启动线程:映射DLL(ntdll.LdrlnitializeThunk),线程开始执行
☀️ 什么是内核对象
像进程、线程、文件、互斥体、事件等在内核都有一个对应的结构体,这些结构体由内核负责管理,这样的对象叫做内核对象。
☀️ 如何让线程暂停
让自己停:Sleep()函数 让别人停:SuspendThread()函数 线程恢复:ResumeThread()函数 【注意:挂起几次线程就必须恢复几次线程,线程才能继续】
☀️ 等待线程结束
- WaitForSingleObject();
- WaitForMultipleObjects();
- GetExitCodeThread();
☀️ 设置、获取线程上下文
BOOL GetThreadContext( HANDLE hThread, // handle to thread with context LPCONTEXT lpContext // context structure ); BOOL SetThreadContext( HANDLE hThread, // handle to thread CONST CONTEXT*lpContext // context structure );
☀️ 临界区实现之线程锁
- 创建全局变量
CRITICAL_SECTION Cs;
- 初始化全局变量
lnitializeCriticalSection(&cs);
- 实现临界区
EnterCriticalSection(&cs); //使用临界资源 LeaveCriticalSection(&cs);
☀️ 使用互斥体示例
HANDLE g__hMlutex =CreateHutex(NULL,FALSE,"XYZ"); //创建互斥体 WaitForSingle0bject(g_hMutex, INF INITE); //获取令牌 //操作代码 ReleaseMutex(g_hMutex); //释放令牌
☀️ 互斥体与线程锁的区别
- 线程锁只能用于单个进程间的线程控制
- 互斥体可以设定等待超时,但线程锁不能
- 线程意外终结时,Mutex可以避免无限等待
- Mutex效率没有线程锁高
☀️ 线程互斥
线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。
☀️ 线程同步(CreateEvent可以实现)
线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
☀️ 窗体的本质
图上的dll仅为编程提供接口,真正的实现在右边的exe和sys文件
内核句柄:HANDLE;窗体句柄:HWND
☀️ GDI图形设备接口(Graphics Device Interface)
☀️ 窗体是画图画出来的
【注】如果不进行关联的话,将使用默认的画笔
HWND hwnd; HDC hdc; HPEN hpen; //1. 设备对象画在哪 hwnd = (HWND) /*HWND句柄值,为NULL则是桌面*/; //2. 获取设备对象上下文 hdc = GetDc(hwnd); //3.创建画笔设置线条的属性 hpen = CreatePen(PS_soLID,5 ,RGB(0XFF,00,00)); //4. 关联 Selectobject(hdc,hpen); //5. 开始画 MoueToEx(hdc,8,400,NULL); LineTo(hdc,400,400) ; // gdi32.d11 //6. 释放资源 DeleteObject(hpen); Re1easeDC(hwnd,hdc);
☀️ Win32工程入口函数
int APIENTRY WinMain( HINSTANCE hInstance, //当前模块的内存地址 HINSTANCE hPrevInstance, //NULL LPSTR lpCmdLine, //命令行 int nCmdShow //显示状态 )
☀️ 消息机制示意图:
☀️ 子窗口控件:
- WINDOWS提供了几个预定义的窗口类以方便我们的使用,我们一般就它们叫做子窗口控件,简称控件。
- 控件会自己处理消息,并在自己状态发生改变时通知父窗口。
- 预定义的控件有:按钮、复选框、编辑框、静态字符串标签和滚动条等。
☀️ 虚拟内存与物理内存的关系
☀️ 可供使用的物理内存:
- MmNumberOfPhysicalPages × 4
- 虚拟内存(硬盘)
☀️ 能够识别的物理内存
32位系统最多可以识别物理内存为64GB,但由于操作系统的限制 比如XP,只能识别4GB(Windows 2003服务器版本可以识别4GB以上)。
☀️ 物理页
一个程序对应的物理页如果不经常使用,将会失去,转到硬盘的虚拟内存。如果失去后,程序又要调用,,将走下图的流程获取。
☀️ 申请内存的两种方式:
- 通过VirtualAlloc/VirtualAllocEx申请的: Private Memory(只有该进程使用,别的不能使用)
- 通过CreateFileMapping映射的:Mapped Memory(可以公共使用)
☀️ 文件系统
文件系统是操作系统用于管理磁盘上文件的方法和数据结构;简单点说就是在磁盘上如何组织文件的方法。
1️⃣ EFS加密是指一个用户在文件属性-高级-加密以保护数据选中时,切换到另一个用户,则该用户无法访问该文件。 2️⃣ 磁盘配额是指Admin赋予给其他用户的磁盘空间,如果超过则拒绝。
☀️ 卷(在此电脑打开看到的驱动器)相关API
- 获取卷:GetLogicalDrives()
- 获取一个所卷的盘符的字符串:GetLogicalDrives()
- 获取卷的类型:GetLogicalDrives()
- 获取卷的类型:GetVolumelnformation()
☀️ 目录相关API
- 创建目录:CreateDirectory()
- 删除目录:RemoveDirectory()
- 修改目录名称:MoveFile()
- 获取程序当前目录:GetCurrentDirectory()
- 设置程序当前目录:SetCurrentDirectory()
☀️ 文件相关API
- 创建文件:CreateFile()
- 关闭文件的:CloseHandle()
- 获取文件长度:GetFileSize()
- 获取文件的属性和信息:GetFileAttributes()/GetFileAttributesEx()
- 读/写/拷贝/删除文件:ReadFile()/WriteFile()/CopyFile()/DeleteFile()
- 查找文件:FindFirstFile()/FindNextFile()
☀️ 内存映射文件
☀️ 内存映射文件之共享
☀️ 写拷贝
- 羽夏笔记——Hook攻防基础
- Win32 DLL动态库学习笔记一
- Cocos2d-x引擎学习笔记之(一)Win32下开发环境的搭建
- Win32学习笔记 - ComboBox
- 【VC编程】笔记3---使用Win32SDK编程,模仿MFC的消息映射处理机制
- vs2008下win32 dll封装笔记
- Win32 API笔记
- cocos2d-x 笔记(一) win32环境配置以及eclipse+ndk+sdk+cygwin的android移植
- win32线程池代码(WinApi/C++)(转)
- WebKit 学习笔记(2) -- Win32 版
- Win32 SDK 学习笔记5
- Win32学习笔记——对话框资源
- Win32学习笔记 第一章
- Java学习笔记 Java调用Win32 API控制鼠标活动范围
- cocos2d-x学习笔记:如何将win32移植到android
- Win32程序SendMessage使用笔记
- win32剪切板学习笔记
- 一、Win32基本程序观念 (学习笔记)
- Win32编程day02 学习笔记
- 多线程 学习笔记<3> WIN32应用程序,多参数