I wrote a blog post before. C # Embedding dll into Resource Release . Although there are not so many applications where DLL s are embedded into program resources and then released in C++, compared with C_#, it is necessary to understand the next general process. Combining with my practical thinking of solving such problems in practical work, this paper introduces the most basic solution.
1 Embedding DLL into resources
Some programs may call external DLLs when they are running. Users may accidentally lose these DLLs when they are using them, which may cause the program to not run properly. Therefore, we can consider embedding these DLLs into resources and automatically releasing them to the directory of executable programs (or other directories of environment variables) at startup. This paper takes the DLL file needed for embedded FFmpeg+SDL development as an example, and introduces the tips of C++ program (EXE or DLL) embedding DLL into resources and then running and releasing.
The DLL files that need to be embedded are as follows:
When a new C++ project is created with Visual Studio, a filter named "resource file" is automatically generated.
Right-click - > Add - > Resources - > Customize:
Create a new resource type "dlls" and save it. Then the embedded DLL file is added to the resource file and the corresponding ID is renamed. The results are as follows:
The ID definition of the DLL above is located in the resource.h header file:
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
The mapping relationship between DLL resources and physical paths is stored in the *. rc file. Here is a small suggestion. In order to facilitate the migration of the program, it is better to change the path to a relative path (relative to the path of the project):
*.rc
2 Release DLL files
The whole process of releasing files from resources is not complicated. After the program runs, locate the base address of the program in memory, then load the resource file and release it to the specified path. Below is a release DLL file help class I encapsulated:
releaseHelper.h
#ifndef _RELEASEHELPER_H_
#define _RELEASEHELPER_H_
#include <windows.h>
#define MAX_DLL_PATH 1024
//If the action code is in a DLL project, define the following macro, otherwise comment it out
//#define _USER_RELEASEDLL_
//Release DLL Help Class
class CReleaseDLL
{
public:
CReleaseDLL();
~CReleaseDLL();
/*
*function:Release DLL file help function
*[IN]:
m_lResourceID:ID of resources
m_strResourceType:Resource type
m_strReleasePath:Name of file to be released
*[OUT]:
Release successful, return TRUE, otherwise return FALSE
*/
bool FreeResFile(unsigned long m_lResourceID,const char* m_strResourceType, const char* m_strFileName);
private:
/*
*function:Get the base address of the module
*[IN]:
*[OUT]:
Returns the acquired base address
*/
HMODULE GetSelfModuleHandle();
private:
//Module base address
HMODULE m_hModule;
//Program Current Directory
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:Failure to obtain base address");
}
//Get directory
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)
{
//Construct a complete release file path
char strFullPath[MAX_DLL_PATH]={0};
sprintf_s(strFullPath,"%s\\%s",this->m_filePath,m_strFileName);
//Search resources
HRSRC hResID = ::FindResource(this->m_hModule,MAKEINTRESOURCE(m_lResourceID),m_strResourceType);
//load resources
HGLOBAL hRes = ::LoadResource(this->m_hModule,hResID);
//Lock-in resources
LPVOID pRes = ::LockResource(hRes);
if (pRes == NULL)
{
return FALSE;
}
//Get the size of the resource file to be released
unsigned long dwResSize = ::SizeofResource(this->m_hModule,hResID);
//create a file
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_
//If the released help class is defined in the DLL, the following method is called to get the base address
MEMORY_BASIC_INFORMATION mbi;
return ((::VirtualQuery((LPCVOID)&CReleaseDLL::GetSelfModuleHandle, &mbi, sizeof(mbi)) != 0)?(HMODULE) mbi.AllocationBase : NULL);
#else
//If defined directly in the code of exe itself
return ::GetModuleHandle(NULL);
#endif
}
catch(...)
{
return NULL;
}
}
After initializing the class object, the DLL file can be released by calling the FreeResFile function directly. The point that needs to be explained here is that CReleaseDLL is defined in a dynamic link library for program invocation, and CReleaseDLL is defined directly in the code of the program itself. The two ways of getting the program base address are different, so the _USER_RELEASEDLL_macro is added to the above code to compatible with the two modes.
Following is an example code that calls the above wrapper class to complete DLL release:
main.cpp
#include <iostream>
#include "resource.h"
#include "releaseHelper.h"
using namespace std;
#define PAUSE cout<<"Please Entry Any Code..."<<endl;getchar();
int main()
{
//Defining Operational Class Objects
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 Document Release Successful"<<endl;
}
else
{
cout<<"DLL File Release Failed"<<endl;
}
PAUSE;
return 0;
}
3 postscript
Embedding DLL files into program resources and releasing them has practical significance, which can reduce the laziness of developing programs to external environment. Of course, the above method is not limited to releasing DLL files, in theory, any file can be. The above approach may be intercepted by some anti-virus software, because many malicious programs such as remote Trojans adopt similar technology, which leads to the prohibition of such loading behavior.