前言:
為了實現windows上的數據壓縮和解壓縮,最方便的方法就是直接調用WIN32 API函數,windows系統的ntdll.dll專門提供了RtlCompressBuffer函數和RtlDecompressBuffer函數來負責數據壓縮和解壓縮操作,這兩個函數並未公開,需要通過ntdll.dll來動態調用。
實現過程:
一、數據壓縮:
(1).調用LoadLibrary函數加載ntdll.dll,獲取ntdll.dll加載模塊的句柄
(2).調用GetProcAddress函數獲取RtlGetCompressionWorkSpaceSize函數與RtlCompressBuffer函數的地址
(3).調用RtlGetCompressionWorkSpaceSize函數來獲取RtlCompressBuffer函數的工作空間緩沖區的大小(壓縮格式和引擎類型設置為COMPRESSION_FORMAT_LZNT1和COMPRESSION_ENGINE_STANDARD)
(4).根據工作空間緩沖區的大小申請內存給壓縮數據使用
(5).調用RtlCompressBuffer函數來壓縮數據。數據壓縮緩沖區的大小為4096字節
注意:需要將實際的壓縮數據大小和數據壓縮緩沖區的大小進行比較,如果數據壓縮緩沖區太小,則需要釋放原來的緩沖區,按照實際壓縮數據的大小重新申請一個新的數據壓縮緩沖區,並且重新壓縮數據
二、數據解壓縮
(1).調用LoadLibrary函數加載ntdll.dll,並獲取ntdll.dll加載模塊的句柄
(2).調用GetProcAddress函數來獲取RtlDecompressBuffer函數
(3).申請一塊內存,大小為4096字節,存放解壓縮后的數據
(4).調用RtlDecompressBuffer函數來解壓縮數據(壓縮格式和引擎類型必須設置為COMPRESSION_FORMAT_LZNT1)
注意:需要將實際的解壓數據大小和數據解壓緩沖區的大小進行比較,如果數據解壓緩沖區太小,則需要釋放原來的緩沖區,按照實際解壓數據的大小重新申請一個新的數據解壓緩沖區,並且重新解壓縮數據
實現代碼:
//************************************ // 函數名:CCondenseDlg::DataCompress // 返回類型:BOOL // 功能: 數據壓縮 // 參數1:BYTE* pUncompressData 未壓縮的數據 // 參數2:DWORD dwUncompressDataLength 未壓縮的數據的數據大小 // 參數3:BYTE** ppCompressData 壓縮后的數據 // 參數4:DWORD* pdwCompressDataLength 壓縮后的數據大小 //************************************ BOOL CCondenseDlg::DataCompress(BYTE* pUncompressData, DWORD dwUncompressDataLength, BYTE** ppCompressData, DWORD* pdwCompressDataLength) { BOOL bRet = FALSE; NTSTATUS status = 0; HMODULE hModule = NULL; //定義函數指針變量 typedef_RtlGetCompressionWorkSpaceSize RtlGetCompressionWorkSpaceSize = NULL; typedef_RtlCompressBuffer RtlCompressBuffer = NULL; DWORD dwWorkSpaceSize = 0; DWORD dwFragmentWorkSpaceSize = 0; BYTE* pWorkSpace = NULL; BYTE* pCompressData = NULL; DWORD dwCompressDataLength = 4096; DWORD dwFinalCompressSize = 0; //加載ntdll.dll hModule = LoadLibrary(_T("ntdll.dll")); if (hModule == NULL) { m_Tip += _T("LoadLibrary Error\r\n"); return bRet; } //獲取函數地址 RtlGetCompressionWorkSpaceSize = (typedef_RtlGetCompressionWorkSpaceSize)::GetProcAddress(hModule, "RtlGetCompressionWorkSpaceSize"); if (NULL == RtlGetCompressionWorkSpaceSize) { m_Tip += _T("GetProcAddress Error\r\n"); FreeLibrary(hModule); return bRet; } RtlCompressBuffer = (typedef_RtlCompressBuffer)::GetProcAddress(hModule, "RtlCompressBuffer"); if (NULL == RtlCompressBuffer) { m_Tip += _T("GetProcAddress Error\r\n"); FreeLibrary(hModule); return bRet; } //獲取WorkSpace大小 status = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_STANDARD, &dwWorkSpaceSize, &dwFragmentWorkSpaceSize); if (0 != status) { m_Tip += _T("RtlGetCompressionWorkSpaceSize Error\r\n"); FreeLibrary(hModule); return bRet; } //申請動態內存 pWorkSpace = new BYTE[dwWorkSpaceSize]{ 0 }; if (pWorkSpace == NULL) { m_Tip += _T("new Error\r\n"); FreeLibrary(hModule); return bRet; } while (TRUE) { //申請動態內存存儲壓縮后的數據 pCompressData = new BYTE[dwCompressDataLength]; if (pCompressData == NULL) { m_Tip += _T("new Error\r\n"); delete[] pWorkSpace; FreeLibrary(hModule); return bRet; } //開始壓縮數據 RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, pUncompressData, dwUncompressDataLength, (PUCHAR)pCompressData, dwCompressDataLength, 4096, &dwFinalCompressSize, (PVOID)pWorkSpace); //如果壓縮數據的緩沖區小於最終的壓縮大小 說明壓縮失敗 需要重新壓縮 if (dwCompressDataLength < dwFinalCompressSize) { //釋放內存 if (pCompressData) { delete[] pCompressData; } dwCompressDataLength = dwFinalCompressSize; } else { //否則說明壓縮成功 退出循環 break; } } //返回壓縮后的數據和長度 *ppCompressData = pCompressData; *pdwCompressDataLength = dwFinalCompressSize; bRet = TRUE; //釋放資源 if (pWorkSpace) { delete[] pWorkSpace; } if (hModule) { FreeLibrary(hModule); } return bRet; }
//************************************ // 函數名:CCondenseDlg::UncompressData // 返回類型:BOOL // 功能: 數據解壓縮 // 參數1:BYTE *pCompressData 壓縮的數據 // 參數2:DWORD dwCompressDataLength 壓縮的數據大小 // 參數3:BYTE **ppUncompressData 解壓縮的數據 // 參數4:DWORD *pdwUncompressDataLength 解壓縮的數據大小 //*BOOL CCondenseDlg::UncompressData(BYTE *pCompressData, DWORD dwCompressDataLength, BYTE **ppUncompressData, DWORD *pdwUncompressDataLength) { BOOL bRet = FALSE; HMODULE hModule = NULL; typedef_RtlDecompressBuffer RtlDecompressBuffer = NULL; BYTE* pUncompressData = NULL; DWORD dwUncompressDataLength = 4096; DWORD dwFinalUncompressSize = 0; // 加載 ntdll.dll hModule = ::LoadLibrary(_T("ntdll.dll")); if (NULL == hModule) { m_Tip += _T("LoadLibrary Error\r\n"); return bRet; } // 獲取 RtlDecompressBuffer 函數地址 RtlDecompressBuffer = (typedef_RtlDecompressBuffer)::GetProcAddress(hModule, "RtlDecompressBuffer"); if (NULL == RtlDecompressBuffer) { m_Tip += _T("GetProcAddress Error\r\n"); FreeLibrary(hModule); return bRet; } while (TRUE) { // 申請動態內存 pUncompressData = new BYTE[dwUncompressDataLength]; if (NULL == pUncompressData) { m_Tip += _T("new Error\r\n"); FreeLibrary(hModule); return bRet; } ::RtlZeroMemory(pUncompressData, dwUncompressDataLength); // 調用RtlCompressBuffer壓縮數據 RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, pUncompressData, dwUncompressDataLength, pCompressData, dwCompressDataLength, &dwFinalUncompressSize); if (dwUncompressDataLength < dwFinalUncompressSize) { // 釋放內存 if (pUncompressData) { delete[] pUncompressData; pUncompressData = NULL; } dwUncompressDataLength = dwFinalUncompressSize; } else { break; } } //返回解壓后的數據和長度 *ppUncompressData = pUncompressData; *pdwUncompressDataLength = dwFinalUncompressSize; bRet = TRUE; //釋放資源 if (hModule) { ::FreeLibrary(hModule); } return bRet; } ***********************************