C/C++ 實現動態資源文件釋放

當我們開發Windows應用程序時,通常會涉及到使用資源(Resource)的情況。資源可以包括圖標、位圖、字符串等,它們以二進制形式嵌入到可執行文件中。在某些情況下,我們可能需要從可執行文件中提取自定義資源并保存為獨立的文件。在這篇博客文章中,我們將討論如何使用C++和WinAPI實現這個目標。

簡介

首先,讓我們考慮一個場景:我們有一個 Windows 應用程序,其中包含了一個自定義的二進制資源比如默認的配置文件,我們希望將這個資源提取出來并保存為一個獨立的文件以用于初始化程序配置項。為了實現這個目標,我們可以使用Windows API提供的相關函數,來完成對資源的釋放工作。

關鍵函數概述

GetModuleHandle

該函數用于獲取指定模塊的句柄。模塊可以是一個可執行文件(例如 .exe 文件)或一個動態鏈接庫(例如 .dll 文件)。該函數返回指定模塊的實例句柄,以便在后續的操作中使用。

以下是 GetModuleHandle 函數的一般形式:

HMODULE GetModuleHandle(LPCTSTR lpModuleName
);

參數說明:

  • lpModuleName:指定要獲取句柄的模塊的名稱。如果為 NULL,則返回調用線程的可執行模塊句柄。

在許多情況下,GetModuleHandle 主要用于獲取當前進程的模塊句柄,以便在后續的操作中使用該句柄。模塊句柄通常用于在進程中查找資源、定位函數地址等目的。

FindResource

該函數用于定位并返回指定模塊(通常是 .exe 或 .dll 文件)中的資源。資源可以是諸如位圖、圖標、對話框模板、字符串等等的數據。

以下是 FindResource 函數的一般形式:

HRSRC FindResource(HMODULE hModule,LPCTSTR lpName,LPCTSTR lpType
);

參數說明:

  • hModule:指定包含資源的模塊的句柄。如果為 NULL,則表示使用當前可執行模塊的句柄。
  • lpName:指定資源的名稱或標識符。可以是字符串或整數標識符。
  • lpType:指定資源的類型。通常是一個字符串,如 “RT_BITMAP” 表示位圖資源。

如果找到,則返回指向資源的句柄(HRSRC)。這個句柄可以用于后續的資源加載和操作,函數的第二個參數經常配合MAKEINTRESOURCE一起使用,MAKEINTRESOURCE 是一個宏(macro),用于將整數標識符(ID)轉換為字符串指針。在 Windows 編程中,通常用于標識資源的 ID。

#define MAKEINTRESOURCE(i) ((LPCTSTR)((DWORD)((WORD)(i))))

這個宏接受一個整數參數 i,然后將其轉換為字符串指針。在資源標識符上下文中,通常將整數標識符轉換為字符串是為了在使用相關資源函數時傳遞正確的參數。

舉個例子,如果有一個字符串資源的標識符是 IDR_MYSTRING,則可以使用 MAKEINTRESOURCE 將其轉換為字符串:

LPCTSTR pszResourceName = MAKEINTRESOURCE(IDR_MYSTRING);

在這里,pszResourceName 將指向字符串 “IDR_MYSTRING”。

在前面提到的 FindResource 中,通常將 MAKEINTRESOURCE(IDR_MYSTRING) 作為 lpName 參數傳遞給 FindResource。這是因為 FindResource 函數期望資源名稱是字符串類型,而 IDR_MYSTRING 可能是一個整數標識符。通過使用 MAKEINTRESOURCE,則可以將整數標識符轉換為字符串,以便正確地在資源中查找。

SizeofResource

該函數用于獲取指定資源的大小。它返回資源的字節數,可以用于確定加載資源所需的內存大小。

以下是 SizeofResource 函數的一般形式:

DWORD SizeofResource(HMODULE hModule,HRSRC   hResInfo
);

參數說明:

  • hModule:指定包含資源的模塊的句柄。如果為 NULL,則表示使用當前可執行模塊的句柄。
  • hResInfo:指定資源的句柄,通常由 FindResource 返回。

SizeofResource 返回資源的大小,以字節為單位。這個函數在加載資源之前可以用來分配足夠的內存空間。

LoadResource

該函數用于加載指定資源的數據。該函數返回一個全局內存塊的句柄,該內存塊包含了資源的實際數據,你可以通過 LockResource 函數獲取該內存塊的指針來訪問資源數據。

以下是 LoadResource 函數的一般形式:

HGLOBAL LoadResource(HMODULE hModule,HRSRC   hResInfo
);

參數說明:

  • hModule:指定包含資源的模塊的句柄。如果為 NULL,則表示使用當前可執行模塊的句柄。
  • hResInfo:指定資源的句柄,通常由 FindResource 返回。

LoadResource 用于將資源數據加載到全局內存塊中,并返回該內存塊的句柄。在加載資源后,可以使用 LockResource 函數獲取指向資源數據的指針。

LockResource

用于獲取指定資源的數據指針。它接受一個全局內存塊的句柄,該內存塊通常由 LoadResource 函數返回,然后返回一個指向資源數據的指針。

以下是 LockResource 函數的一般形式:

LPVOID LockResource(HGLOBAL hResData
);

參數說明:

  • hResData:指定資源數據的全局內存塊句柄,通常由 LoadResource 函數返回。

LockResource 用于鎖定指定資源的全局內存塊,并返回指向資源數據的指針。請注意,這個函數實際上并不執行拷貝,而是返回指向內存塊的指針,因此對返回指針的任何修改都會直接影響到內存塊本身。

FreeResource

用于釋放由 LoadResource 函數加載的資源。這個函數通常用于釋放不再需要的資源,以防止資源泄漏。

以下是 FreeResource 函數的一般形式:

BOOL FreeResource(HGLOBAL hResData
);

參數說明:

  • hResData:指定要釋放的全局內存塊句柄,通常由 LoadResource 函數返回。

FreeResource 用于釋放之前由 LoadResource 加載的資源。請注意,這個函數通常在資源的生命周期結束時調用,以確保釋放資源占用的內存。但在實際應用中,現代 Windows 應用通常不需要顯式調用 FreeResource,因為 Windows 會在程序退出時自動釋放資源。

在實際的應用程序中,FindResource 可以與 LoadResourceLockResource 等函數一起使用,用于加載和操作資源數據。當數據資源被加載到內存之后則可以直接通過fwrite函數將其直接寫出到磁盤中,以此來實現釋放資源的目的。

代碼功能實現

首先新建一個控制臺程序以作為本次的測試環境,接著準備好我們需要寫出的數據,這里就準備一個lyshark.ini配置文件,在項目中右鍵選擇添加并添加資源,此時會彈出如下圖所示的提示信息;

此時會彈出添加資源菜單,通過點擊導入按鈕并輸入資源類型為LYSHARK點擊確定保存這個更改,如下圖所示;

此時我們在主程序中引入#include "resource.h"包含資源頭文件,并修改FindResource中的特定位置使其指向我們導入的配置文件,在釋放時同樣需要保持fopen("map\\lyshark.ini", "wb+")配置文件的格式。

這段資源釋放的完整代碼如下所示;

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>
#include <WinUser.h>
#include "resource.h"BOOL UseCustomResource()
{// 定位我們的自定義資源HMODULE hModule = GetModuleHandle(NULL);if (hModule == NULL){std::cerr << "錯誤:獲取模塊句柄失敗。" << std::endl;return FALSE;}HRSRC hRsrc = FindResource(hModule, MAKEINTRESOURCE(IDR_LYSHARK1), TEXT("LYSHARK"));if (hRsrc == NULL){std::cerr << "錯誤:無法找到資源。" << std::endl;return FALSE;}// 獲取資源大小DWORD dwSize = SizeofResource(hModule, hRsrc);if (dwSize == 0){std::cerr << "錯誤:無效的資源大小。" << std::endl;return FALSE;}// 加載資源HGLOBAL hGlobal = LoadResource(hModule, hRsrc);if (hGlobal == NULL){std::cerr << "錯誤:無法加載資源。" << std::endl;return FALSE;}// 鎖定資源LPVOID lpVoid = LockResource(hGlobal);if (lpVoid == NULL){std::cerr << "錯誤:無法鎖定資源。" << std::endl;FreeResource(hGlobal);  // 在返回前釋放資源return FALSE;}// 如果不存在,創建一個“map”目錄if (!CreateDirectory("map", NULL) && GetLastError() != ERROR_ALREADY_EXISTS){std::cerr << "錯誤:無法創建目錄。" << std::endl;FreeResource(hGlobal);return FALSE;}// 將資源寫入文件FILE* fp = fopen("map\\lyshark.ini", "wb+");if (fp == NULL){std::cerr << "錯誤:無法創建或打開文件。" << std::endl;FreeResource(hGlobal);return FALSE;}fwrite(lpVoid, sizeof(char), dwSize, fp);fclose(fp);// 釋放資源FreeResource(hGlobal);return TRUE;
}int main(int argc, char* argv[])
{BOOL ref = UseCustomResource();std::cout << "釋放狀態: " << ref << std::endl;system("pause");return 0;
}

以管理員模式運行上述程序,并等待,此時會釋放一個目錄并包含一個配置文件,如下圖所示的輸出結果;

結語

通過以上的代碼實現,我們成功地將自定義資源提取并保存為一個獨立的文件。這種技術在一些特殊情況下可能會很有用,例如需要動態加載或替換資源的情況。希望這篇博客對你理解如何使用 C++ 和 Windows API 進行資源操作有所幫助。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/208900.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/208900.shtml
英文地址,請注明出處:http://en.pswp.cn/news/208900.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

vivado時序方法檢查7

TIMING-25 &#xff1a; 千兆位收發器 (GT) 上的時鐘波形無效 收發器輸出管腳 <pin_name> 上或連接到該管腳的信號線上定義的時鐘 <clock_name> 的波形與收發器設置不一 致&#xff0c; 或者缺少參考時鐘定義。自動衍生時鐘的周期為 <PERIOD> &#xf…

物聯網后端個人第十四周總結

物聯網方面進度 1.登陸超時是因為后端運行的端口和前端監聽的接口不一樣&#xff0c;所以后端也沒有報錯&#xff0c;將二者修改一致即可 2.登錄之后會進行平臺的初始化&#xff0c;但是初始化的時候會卡住,此時只需要將路徑的IP端口后邊的內容去掉即可 3.閱讀并完成了jetlinks…

通過誤差改變控制的兩種策略

如果反饋誤差越來越大&#xff0c;需要改變調節方向以減小誤差并實現更好的控制。以下是兩種常見的調節方向改變的方法&#xff1a; PID控制器中的積分限制&#xff1a;在PID控制中&#xff0c;積分項可以用來減小穩態誤差。然而&#xff0c;當反饋誤差持續增大時&#xff0c;積…

浪潮信息:數字化轉型的策略與實踐

在數字化浪潮的推動下&#xff0c;浪潮信息正致力于將計算創新推向新的高度。作為科技發展的排頭兵&#xff0c;浪潮信息深知算力的重要性&#xff0c;因此不斷探索前所未有的解決方案。在這個過程中&#xff0c;浪潮信息的研發人員和科技工作者如同探險家&#xff0c;勇敢地迎…

RocketMQ安裝和使用

RocketMQ快速入門 下載RocketMQ 下載地址 環境要求 Linux64位系統 JDK1.8(64位) 安裝RocketMQ 解壓 unzip rocketmq-all-4.4.0-bin-release.zip啟動RocketMQ 啟動NameServer # 1.啟動NameServer nohup sh bin/mqnamesrv & # 2.查看啟動日志 tail -f ~/logs/rocke…

學會用bash在linux寫腳本 (二)

接著上一章繼續 數值的對比 判斷語句 循環語句 22.5 比較、對比、判斷 在寫腳本時&#xff0c;有時需要做一些比較&#xff0c;例如&#xff0c;兩個數字誰大誰小&#xff0c;兩個字符串是否相同等。 做對比的表達式有[]、[[]]、test&#xff0c;其中[]和 test這兩種表達式的…

如何通過3000個傳感器幫助大型大學附屬醫院實現遠程環境監測?

得益于ELPRO提供的可擴展、可信賴和可靠的環境監測解決方案&#xff0c;一家領先的大學研究醫院系統在COVID-19新冠肺炎大流行初始迅速為員工遠程工作做好了準備。 在本案例研究中&#xff0c;您將了解大城市的一家大型大學附屬醫院如何做到&#xff1a; 建立了遠程溫度控制數…

身份統一管理創新與優化 ——華為云OneAccess應用身份管理服務的2023年

2023年&#xff0c;隨著云計算、物聯網、人工智能等技術的快速發展&#xff0c;企業面臨著數字化轉型的巨大挑戰與機遇。身份統一管理是企業數字化轉型的基礎&#xff0c;也是業務發展的關鍵。如何高效、安全、靈活地實現身份統一管理&#xff0c;成為企業亟待解決的首要課題。…

解決MySQL字段名與關鍵字沖突

如果字段名與MySQL內部關鍵字相同&#xff0c;可能會導致語法錯誤、數據訪問問題甚至系統崩潰。 1、避免使用MySQL關鍵字作為字段名。 2、使用反引號&#xff08;backticks&#xff09;&#xff1a; 如果使用一個與MySQL關鍵字相同的字段名&#xff0c;可以使用反引號將其括起…

boost-字符串處理-判斷-查找-裁剪-刪除-替換-分割-合并

文章目錄 1.判斷1.1.equals1.2.all1.3.starts_with1.4.ends_with1.5.contains 2.大小寫轉換3.字符串刪除4.字符串替換5.字符串查找6.字符串修剪7.字符串分割8.字符串合并9.總結 1.判斷 判別式函數和分類函數大多數都是以is_開頭&#xff0c;這些函數如下&#xff1a; 判別式函…

ElasticSearch之線程池

ElasticSearch節點可用的CPU核的數量&#xff0c;通常可以交給ElasticSearch來自行檢測和判定&#xff0c;另外可以在elasticsearch.yml中顯式指定。樣例如下&#xff1a; node.processors: 2如下表格中的processors即CPU核的數量。 線程池的列表 線程池名稱類型線程數量隊列…

屏蔽百度首頁推薦和熱搜的實戰方案

大家好,我是愛編程的喵喵。雙985碩士畢業,現擔任全棧工程師一職,熱衷于將數據思維應用到工作與生活中。從事機器學習以及相關的前后端開發工作。曾在阿里云、科大訊飛、CCF等比賽獲得多次Top名次。現為CSDN博客專家、人工智能領域優質創作者。喜歡通過博客創作的方式對所學的…

電視節目中活動滅燈系統是如何實現的

活動滅燈系統主要用于各種需要亮燈或滅燈的活動節目&#xff0c;如招聘滅燈、相親滅燈等。有多種燈光顏色供選擇&#xff0c;本設備通過按鈕燈軟件組合實現&#xff0c;用戶可以自己設置亮燈或滅燈規則。 軟件功能&#xff1a; 1、后臺統一控制亮燈&#xff0c;重新開始下輪…

華為交換機基本配置

一、配置時間 sys ntp-service unicast-server 192.168.1.1 ntp-service unicast-server 192.168.1.2 clock timezone UTC add 8 clock timezone CST add 08:00:00 undo ntp-service disable q手動設置一個時間 clock datetime 13:43:00 2023-10-10save ysys保存&#xff01;保…

某60內網滲透之域管權限維持[金票利用]

內網滲透 文章目錄 內網滲透域管權限維持【金票利用】實驗目的實驗環境實驗工具實驗原理實驗內容域管權限維持【金票利用】實驗步驟攻擊域管權限維持【金票利用】 實驗目的 讓學員通過該系統的練習主要掌握:利用金票來維持域管理員的權限。 實驗環境 操作機 Windows 7,域…

微信小程序 - 格式化操作 moment.js格式化常用使用方法總結大全

格式化操作使用 1. 首先&#xff0c;下載一個第三方庫 moment npm i moment --save 注&#xff1a;在微信小程序中無法直接npm 下載 導入 的&#xff08;安裝一個就需要構建一次&#xff09; 解決&#xff1a;菜單欄 --> 工具 --> 構建 npm 點擊即可&#xff08;會…

線性回歸模型標準公式

用一組特征 x ( i ) { x^{(i)}} x(i)來預測或估計一個響應變量 y ( i ) y^{(i)} y(i)&#xff0c;公式如下&#xff1a; y ( i ) θ T x ( i ) ? ( i ) y^{(i)} \theta^T x^{(i)} \epsilon^{(i)} y(i)θTx(i)?(i) 各名詞解釋&#xff1a; y ( i ) y^{(i)} y(i)&#xf…

Docker import 命令

docker import&#xff1a;從歸檔文件中創建鏡像。 語法&#xff1a; docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]OPTIONS說明&#xff1a; -c &#xff1a;應用docker指令創建鏡像&#xff1b; -m &#xff1a;提交時的說明文字&#xff1b; 實例&#xff1a…

蝦皮免費分析工具:了解市場趨勢、優化產品和店鋪運營

在如今競爭激烈的電商市場中&#xff0c;了解市場趨勢、優化產品和店鋪運營對于賣家來說至關重要。蝦皮&#xff08;Shopee&#xff09;作為一家知名的電商平臺&#xff0c;為賣家提供了一些免費的分析工具&#xff0c;幫助他們更好地了解市場情況并做出明智的決策。本文將介紹…

C/C++,優化算法——雙離子推銷員問題(Bitonic Travelling Salesman Problem)的計算方法與源代碼

1 文本格式 // C program for the above approach #include <bits/stdc.h> using namespace std; // Size of the array a[] const int mxN 1005; // Structure to store the x and // y coordinates of a point struct Coordinates { double x, y; } a[mxN]; //…