C++嵌入DLL到資源執行釋放的問題
以前寫過一篇博文《C#嵌入dll到資源釋放的問題》。雖然相對於C#,C++中嵌入DLL到程式資源中,然後再釋放出來的應用場合並沒有那麼多,但是還是有必要了解下一般的過程。結合本人在實際工作中解決此類問題的實踐思路,這裡介紹下最基本的一種解決方案。
1 嵌入DLL到資源
有些程式執行的時候,可能呼叫外部的DLL,使用者使用時可能會不小心丟失這些DLL,導致程式無法正常執行,因此可以考慮將這些DLL嵌入到資源中,啟動時自動釋放到可執行程式目錄(或者其他環境變數目錄)。這裡以嵌入FFmpeg+SDL開發所需要的DLL檔案為例,介紹下C++程式(EXE或者DLL)嵌入DLL到資源後再執行釋放的小技巧。
需要嵌入的DLL檔案如下:
利用Visual Studio新建C++專案後,會自動生成一個“資原始檔”的篩選器:
右鍵->“新增”->“資源”->”自定義”:
新建一種新的資源型別“dlls”並儲存。然後將需要嵌入的DLL檔案加入資原始檔中,重新命名相應的ID,結果如下:
上面DLL的ID定義位於resource.h標頭檔案中:
resource.h
#define IDR_avcodec_55 102
#define IDR_avdevice_55 103
#define IDR_avfilter_4 104
#define IDR_avformat_55 105
#define IDR_avutil_52 106
#define IDR_postproc_52 107
#define IDR_SDL 108
#define IDR_swresample_0 109
#define IDR_DLLS9 110
#define IDR_swscale_2 110
DLL資源與實際物理路徑的對映關係都儲存在*.rc檔案中。這裡給個小建議,為了方便程式的移植,最好把路徑改成相對路徑(相對於工程的路徑):
*.rc
2 釋放DLL檔案
從資源中釋放檔案,整個過程並不複雜。程式執行後,在記憶體中定位程式的基址,然後載入資原始檔,並將其釋放到指定路徑即可。下面是我封裝的一個釋放DLL檔案幫助類:
releaseHelper.h
#ifndef _RELEASEHELPER_H_
#define _RELEASEHELPER_H_
#include <windows.h>
#define MAX_DLL_PATH 1024
//如果操作程式碼位於DLL工程中,就定義下面的巨集,否則註釋掉
//#define _USER_RELEASEDLL_
//釋放DLL幫助類
class CReleaseDLL
{
public:
CReleaseDLL();
~CReleaseDLL();
/*
*function:釋放DLL檔案幫助函式
*[IN]:
m_lResourceID:資源的ID
m_strResourceType:資源型別
m_strReleasePath:需要釋放的檔名稱
*[OUT]:
釋放成功,返回TRUE,否則返回FALSE
*/
bool FreeResFile(unsigned long m_lResourceID,const char* m_strResourceType, const char* m_strFileName);
private:
/*
*function:獲取模組的基址
*[IN]:
*[OUT]:
返回獲取的基址
*/
HMODULE GetSelfModuleHandle();
private:
//模組基址
HMODULE m_hModule;
//程式當前目錄
char m_filePath[MAX_DLL_PATH];
};
#endif
releaseHelper.cpp
#include "releaseHelper.h"
#include <cstdio>
#include <string.h>
#include <direct.h>
#include <exception>
CReleaseDLL::CReleaseDLL()
{
this->m_hModule=GetSelfModuleHandle();
if(m_hModule==NULL)
{
throw std::exception("Error:獲取基址失敗");
}
//獲取目錄
memset(this->m_filePath,0,MAX_DLL_PATH);
_getcwd(this->m_filePath,MAX_DLL_PATH);
}
CReleaseDLL::~CReleaseDLL()
{
}
bool CReleaseDLL::FreeResFile(unsigned long m_lResourceID, const char* m_strResourceType, const char* m_strFileName)
{
//構造完整釋放檔案路徑
char strFullPath[MAX_DLL_PATH]={0};
sprintf_s(strFullPath,"%s\\%s",this->m_filePath,m_strFileName);
//查詢資源
HRSRC hResID = ::FindResource(this->m_hModule,MAKEINTRESOURCE(m_lResourceID),m_strResourceType);
//載入資源
HGLOBAL hRes = ::LoadResource(this->m_hModule,hResID);
//鎖定資源
LPVOID pRes = ::LockResource(hRes);
if (pRes == NULL)
{
return FALSE;
}
//得到待釋放資原始檔大小
unsigned long dwResSize = ::SizeofResource(this->m_hModule,hResID);
//建立檔案
HANDLE hResFile = CreateFile(strFullPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hResFile)
{
return FALSE;
}
return TRUE;
}
HMODULE CReleaseDLL::GetSelfModuleHandle()
{
try
{
#ifdef _USER_RELEASEDLL_
//如果釋放的幫助類定義在DLL中,將呼叫下面的方式獲取基址
MEMORY_BASIC_INFORMATION mbi;
return ((::VirtualQuery((LPCVOID)&CReleaseDLL::GetSelfModuleHandle, &mbi, sizeof(mbi)) != 0)?(HMODULE) mbi.AllocationBase : NULL);
#else
//如果直接定義在exe本身的程式碼中
return ::GetModuleHandle(NULL);
#endif
}
catch(...)
{
return NULL;
}
}
初始化類物件後,直接呼叫FreeResFile函式就可以完成DLL檔案的釋放。這裡需要說明的一點就是,將CReleaseDLL定義在一個動態連結庫中供程式來呼叫,和直接將CReleaseDLL定義在程式本身的程式碼中,這兩種獲取程式基址的方式是不一樣的,所以上述程式碼中增加了_USER_RELEASEDLL_
巨集,用來相容這兩種模式。
下面是呼叫上述封裝類完成DLL釋放的示例程式碼:
main.cpp
#include <iostream>
#include "resource.h"
#include "releaseHelper.h"
using namespace std;
#define PAUSE cout<<"Please Entry Any Code..."<<endl;getchar();
int main()
{
//定義操作類物件
CReleaseDLL releasehelper;
bool blRes;
blRes=releasehelper.FreeResFile(IDR_avcodec_55,"dlls","avcodec-55.dll");
blRes=releasehelper.FreeResFile(IDR_avdevice_55,"DLLS","avdevice-55.dll");
blRes=releasehelper.FreeResFile(IDR_avfilter_4,"DLLS","avfilter-4.dll");
blRes=releasehelper.FreeResFile(IDR_avformat_55,"DLLS","avformat-55.dll");
blRes=releasehelper.FreeResFile(IDR_avutil_52,"DLLS","avutil-52.dll");
blRes=releasehelper.FreeResFile(IDR_postproc_52,"DLLS","postproc-52.dll");
blRes=releasehelper.FreeResFile(IDR_SDL,"DLLS","SDL.dll");
blRes=releasehelper.FreeResFile(IDR_swresample_0,"DLLS","swresample-0.dll");
blRes=releasehelper.FreeResFile(IDR_swscale_2,"DLLS","swscale-2.dll");
if(blRes)
{
cout<<"DLL檔案釋放成功"<<endl;
}
else
{
cout<<"DLL檔案釋放失敗"<<endl;
}
PAUSE;
return 0;
}
3 後記
把DLL檔案嵌入到程式資源中並執行釋放有一定的現實意義,可以減少開發程式對外部環境的依懶性。當然了,上面的方法不僅僅侷限於釋放DLL檔案,理論上什麼檔案都是可以的。上面的做法可能會被某些防毒軟體攔截,原因是很多遠控木馬等惡意程式採用了類似的技術,導致殺軟禁止了這種載入行為。
相關推薦
C++嵌入DLL到資源執行釋放的問題
以前寫過一篇博文《C#嵌入dll到資源釋放的問題》。雖然相對於C#,C++中嵌入DLL到程式資源中,然後再釋放出來的應用場合並沒有那麼多,但是還是有必要了解下一般的過程。結合本人在實際工作中解決此類問題的實踐思路,這裡介紹下最基本的一種解決方案。 1 嵌入DL
C#嵌入dll到資源釋放的問題
http://blog.csdn.net/kikaylee/article/details/44536231 有些程式執行的時候,可能呼叫外部的dll,使用者使用時可能會不小心丟失這些dll,導致程式無法正常執行,因此可以考慮將這些dll嵌入到資源中,啟動時自動釋放。對於託管的dll,我們可以用打包
C# 嵌入dll
resolv appdomain his 一個 我們 文件 跟著 完成後 replace 在很多時候我們在生成C#exe文件時,如果在工程裏調用了dll文件時,那麽如果不加以處理的話在生成的exe文件運行時需要連同這個dll一起轉移,相比於一個單獨幹凈的exe,這種形式
C#將DLL嵌入到exe當中
visual 資源 sse .cn 體積 body [] log sin 原文:C#將DLL嵌入到exe當中一、將dll文件加入工程 1.找到dll文件 可以在項目的“引用”下找到dll,並且根據屬性中的“路徑”找到文件所在目錄;也可以使用bin目錄下自動生成(其實就是
關於 C#呼叫C庫Dll,有回撥函式時,只執行一次回撥函式就直接掛掉 的解決方法
錯誤 直接當機,如下圖: 錯誤原因 回撥函式宣告原因,跟堆疊有關係
C++沒有final或finally,如何解決異常情況下資源的釋放問題?
#include "stdafx.h" #include <iostream> class TestA { public: TestA() { std::cout << "TestA" << std::endl; } ~Tes
關於 C#呼叫一個C/C++dll庫執行時實現多個應用(靜態變數區分) 的解決方法
需求 VS編寫了純C(windows)通訊庫,需要多例項(靜態變數標誌一個例項,達到互相靜態變數不干涉)。 當前問題 dll中使用了全域性static的標
C#語言中的Using語句塊確保資源被釋放
在開發C#的過程中,.NET在物件不再引用之後,清理它們的方法是使用非析構方式。 在C++中,物件只要使用完畢,就會自動呼叫其解構函式。這對於基於資源的類的設計人員是非常好的訊息,因為如果使用者忘記關閉資源,則最好使用解構函式。只要物件使用完畢,就會呼叫C+
【已解決】C#將DLL嵌入到exe當中
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { string dllName = args.Name.Contains(",
Java執行緒之釋放鎖,釋放資源,釋放CPU
多執行緒中的wait與sleep到底誰釋放了鎖 首先,多執行緒中會使用到兩個延遲的函式,wait和sleep。 wait是Object類中的方法,而sleep是Thread類中的方法。 sleep是Thread類中的靜態方法。無論是在a執行緒中呼叫b的sl
C#裡using的作用------釋放資源
很高興今天看到一個可以拿出來分享的知識點,那就是using的使用。 其實關於using的作用,我想大家最多的用在引入名稱空間。:)其實我在這之前也跟大家一樣,不過今天在看一個小例子後,則讓我產生了疑問。好拉,我先把程式碼附上吧。 using System; using Sys
(C#) 銷燬資源和釋放記憶體
0. 什麼是資源? .NET 框架中如何訪問資源?所謂的資源就是程式中可利用的資料,譬如:字串、圖片和任何二進位制資料,包括任何型別的檔案。在面向物件的環境中,每一個型別都標識為某些程式所用的資源,要想使用這些資源,必須為相應的型別分配一定的記憶體空間。訪問一個資源需要如下幾
C#監控代碼執行效率
light 運行時 測量 pan 獲取 min mes csharp stopwatch System.Diagnostics.Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // 開始監視代碼運行時間
C# 引用DLL版本沖突
src 中一 ~~ 嘗試 .html 1.2 title 代碼 fig 已解決,到官網上下載舊key版本,然後再重定向即可。 手動引用兩個版本的DLL錯誤的原因是我 publicKeyToken 大小寫的問題(竟然沒校驗~~) 但我想不明白,這樣搞如果依賴一多的話,甚至那
C++ Boost 學習資源列表
splay style blog 推薦 trac ffffff color border search 文檔書籍下載 Boost Documentation Boost代碼下載 優秀網站導航 Boos
C# 版dll 程序集合並工具
集合 命令 支持 log 基本 ron 其他 依賴 使用 微軟的ILMerge工具。 下載地址:https://www.microsoft.com/en-us/download/details.aspx?id=17630 這個支持將EXE依賴的DLL合並到EXE
C# 引用DLL調用時註釋無法顯示
spa 目錄 log 生成頁面 調用 dll文件 .com 生成 註釋 修改前,調用DLL中的方法沒有註釋: 修改後,調用DLL中的方法有註釋: 解決辦法: 在生成DLL時,將項目屬性的生成頁面中,勾選“XML文檔文件”
C#引用C++的DLL方案(C#調用非托管動態鏈接庫)
方法 str tor urn pcc tcl ges bin log SocketClientInit是C++裏面定義的方法,通過EntryPoint = "[email protected]@[email protected]"指出這個
java 利用jna調用c#的dll
運行 pat bapi services 包含 外部 生成 輸出 64位 一、需求闡述: 如果我們的項目利用c#開發,到了開發後期需要和java組進行合作,其中有一部分業務邏輯利用c#已經code completed,那麽我們可能會
c#解決dll調用的問題
appdomain 問題 net dep ase lan depend class eve 在做一個c#中間程序時,調用第三方的dll安裝路徑“Program Files” 和“Program Files (x86)”的問題,經過一段時間的研究,找到了下面的解決方案: 思