寫在前面
本筆記是由本人獨自整理出來的,圖片來源於網絡。本人非計算機專業,可能對本教程涉及的事物沒有了解的足夠深入,如有錯誤,歡迎批評指正。 如有好的建議,歡迎反饋。碼字不易,如果本篇文章有幫助你的,如有閑錢,可以打賞支持我的創作。如想轉載,請把我的轉載信息附在文章后面,並聲明我的個人信息和本人博客地址即可,但必須事先通知我。
本篇文章主要是讓讀者對
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()
☀️ 內存映射文件
☀️ 內存映射文件之共享
☀️ 寫拷貝