Are you like me, Total number of exe files built (plus resource files) try to keep it as few as possible. It's better to have only one file, or some things don't want to put some important things outside exe. Even after encryption, you don't feel at ease. Then rc and windows api can meet your needs. If you want to dazzle you with more than 100 DLLs and more than 100 resource files in a program like adobe, it doesn't matter, Just watch it!
catalogue
Basic knowledge
RC resource file:
RC, full name (Resource), can be called windres Exe compiles and packages the resources in exe. Its basic syntax is as follows:
[resource_id] [Token] [Arguments]
Common keywords: DIALOG,CTEXT,LTEXT,RTEXT,MENU,ICON
Add: RC can also be used to set the icon of packaged exe. Only one line of code is required:
[any name] icon "path of icon, suffix. ico"
In addition, many people on the Internet say that the variable name of "any name" must be MAIN_ICON to make the EXE have an icon. However, in fact, as long as there is an icon file in the resource file, the icon of your exe will change. For example:
//rc.rc THIS_IS_NOT_THE_EXE_ICON_PLEASE ICON "secret.ico" //What's the secret???
Suppose secret ICO is a picture that you don't want to appear on the exe icon, but RC doesn't care. It will use it as the program icon by default.
The RC keyword used in this article is RCDATA
Windows API functions
Needless to say, it's windows Almost all functions in H (except for version incompatibility, for example, GetConsoleWindow is incompatible with Win98, 95 and server 2000)
The main windows functions used this time: GetLastError, findresource, lockresource, sizeofresource, unlockeresource
text
If you want to package resources, first, you need to write the resource file information into rc. You can easily package resources with RCDATA. The RCDATA syntax is as follows:
[resource ID / serial number] RCDATA "resource address"
Suppose you have two texts to support Chinese and English, then the program can be written
//res.h #ifndef RES_H #define RES_H #define STEP 11451 #define STEPN(X) ((STEP) + (X)) #define RES_LAN_ENG STEPN(0) #define RES_LAN_CHI STEPN(1) #endif
#include "res.h" RES_LAN_ENG RCDATA "English.l" RES_LAN_CHI RCDATA "Chinese.l"
The specific file format is as follows:
Chinese.l the contents are as follows:
Hello world!
English.l is
HelloWorld!
OK, with resources, how to read it? At this time, we need to develop a function to solve this problem. My function model is as follows.
/* *@Summary Get resource file pointer (copied) *@Arguments: * exeInstance:The handle of this program, GetModuleHandle(NULL), and the hInstance entry parameter in WinMain can both be used * rcName:The name of the resource. If it is a sequence number, use makeintresource (sequence number) to obtain it * rcType:The type of resource has never been specified in this article_ Rcdata, or RT_ICON,RT_DIALOG et al * err:Error code *@Return: * The data pointer after copy is returned if successful, and NULL if failed */ char * GetResourceDataPtr(HMODULE exeInstance,LPCSTR rcName,LPCSTR rcType,int & err);
So how to achieve it?
It is divided into the following steps:
1. Find the resource and get the handle through FindResource
2. Obtain the HGLOBAL of the resource through LoadResource
3. Obtain the resource pointer through LockResource
4. Copy data through malloc and strncpy
5. Release HGLOBAL in Heap through UnlockResource
Careful smart people may find out why the fifth step is italicized? You'll know why it's italicized later!
OK, now that you have the idea, it's time to write the function body.
If you want the function to resist all exceptions that can be handled, it is very important to judge the exceptions and return them in the function. Here, I define a macro to handle this situation
//C:Condition //S:Statements #define MASSERT(C,S) if((C)){S;}
First, find the resource and get the handle through FindResource, so the code is
FindResource is defined as follows
HRSRC FindResourceA( HMODULE hModule, LPCSTR lpName, LPCSTR lpType );
HRSRC rs = FindResource(exeInstance,rcName,rcType);
Then LoadResource
HGLOBAL LoadResource( HMODULE hModule, HRSRC hResInfo );
HGLOBAL glb = LoadResource(exeInstance,rs);
Lock resource again
LPVOID LockResource( HGLOBAL hResData );
char * sdata = (char*)LockResource(glb)
Then malloc and strncpy copy the data
_CRTIMP void* __cdecl __MINGW_NOTHROW malloc (size_t) __MINGW_ATTRIB_MALLOC; _CRTIMP char* __cdecl __MINGW_NOTHROW strncpy (char*, const char*, size_t);
DWORD size = SizeofResource(exeInstance,rs);//Get Resource size size_t sz = sizeof(BYTE) * (size + 1); char * data = (char *)malloc(sz); ZeroMemory(data,sz); strncpy(data,sdata,sz);
Finally, UnlockResource returns?
NO,NO,NO!
In fact, you don't need UnlockResource at all, because when you look at the place where it is defined, winbase H yes, you'll find that it's defined like this
#define UnlockResource(h) (h)
When I wrote the code, I found that the UnlockResource displayed in Codeblocks is a macro and mingw. When I was warned that this is a meaningless statement (warning: statement has no effect [- wunused value] |), I thought something was wrong. Sure enough, it was empty!
Finally, with our wrong judgment, a function can be written. Of course, in order not to debug is a waste of time, I also designed a debug version. In this way, the resource file will not be changed, and the whole exe will be rebuilt
Finally, I present all the source code:
//ctool. H fileio:: file in debug_ Size comes from it. It is a c + + toolkit. You can get it if you need it #ifndef CTOOL_INC #define CTOOL_INC #include <windows.h> #include <string> #include <stdio.h> #include <iostream> #include <vector> #include <sys/stat.h> #include <math.h> using namespace std; #ifdef BUILD_DEBUG #define O(x) cout << x #define Oln(x) cout << x << endl #endif // BUILD_DEBUG namespace ctk{ struct TMST0{ DWORD all; DWORD offset; }; //Link winmm. Required a. VC #pragma comment (link, "winmm. A") add "winmm" string to linker settings in CodeBlocks buildoption class Clock{ public: Clock(bool start = true); void Start(); TMST0 Stop(); DWORD GetALLTime();//Do not set pre time DWORD GetOffset();//Set Pre Time TMST0 Now();//Do not reset preTime private: DWORD m_StartTime; DWORD m_PreTime; bool m_start; }; } namespace strps{ string GetTranslateString(string in); void split(vector<string> & vct,const string & line,const char sep); string Trim(string & str); void Stringsplit(string str, string splits, vector<string>& res); namespace encoding{ string GBKToUTF8(const string &strGBK); string UTF8ToGBK(const string &strUTF8); } } namespace fileIO{ int file_size(char* filename); bool check_exists(char* filename); } namespace num{ namespace random{ typedef struct RandomShakeStruct{ float shakeValue; float time; float timePerRound; float mn; float mx; float start; int stDirection; ctk::Clock insideClock; } ShakeSt; void ShakeInit(ShakeSt & st,float timePerRound,float minv,float maxv,float start,int startDiection = 1); //Jitter random number, currently in beta status void Shake(ShakeSt & st); } namespace vectors{ //vector struct Vector{ float x; float y; float z; Vector(float v0,float v1,float v2); }; Vector Normalize(Vector); } } #endif // CTOOL_INC
//ctool. cpp ctool. The implementation of H needs to be taken by yourself. Most of the code is found online. It is only used as a toolkit and has no commercial use #include "./ctool.h" #include <iostream> using namespace std; using namespace ctk; using namespace strps; using namespace fileIO; using namespace strps::encoding; using namespace num::random; using namespace num::vectors; Clock::Clock(bool start){ this->m_StartTime = this->m_PreTime = 0; this->m_start = false; if(start){ this->Start(); } } void Clock::Start(){ if(m_start)return; this->m_start = true; this->m_StartTime = timeGetTime(); } TMST0 Clock::Now(){ if(!m_start)return {0,0}; TMST0 t; t.all = timeGetTime() - this->m_StartTime; t.offset = timeGetTime() - this->m_PreTime; return t; } DWORD Clock::GetALLTime(){ if(!m_start)return 0; return Now().all; } DWORD Clock::GetOffset(){ if(!m_start)return 0; DWORD off = Now().offset; this->m_PreTime = timeGetTime(); return off; } TMST0 Clock::Stop(){ if(!m_start)return {0,0}; TMST0 rt = Now(); this->m_StartTime = 0; this->m_start = false; return rt; } string strps::GetTranslateString(string in){ string out = ""; for(size_t i = 0;i < in.length();i++){ if(in[i] == '\\'){ switch(in[++i]){ case 'n'://New Line out += '\n'; break; case '\\'://Backslash out += '\\'; break; case 'v'://vertical out += '\v'; break; case 't'://tab out += '\t'; break; case 'r'://return out += '\r'; break; case 'a'://alll out += '\007'; break; default: i--; out += in[i]; break; } }else{ out += in[i]; } } return out; } int fileIO::file_size(char* filename){ struct stat statbuf; int ret; ret = stat(filename,&statbuf);//Call stat function if(ret != 0) return -1;//Get failed. return statbuf.st_size;//Returns the file size. } string strps::Trim(string & str){ string blanks("\f\v\r\t\n "); string temp; for(int i = 0;i < (int)str.length();i++){ if(str[i] == '\0') str[i] = '\t'; } str.erase(0,str.find_first_not_of(blanks)); str.erase(str.find_last_not_of(blanks) + 1); temp = str; return temp; } void strps::split(vector<string> & vct,const string & line,const char sep){ const size_t size = line.size(); const char* str = line.c_str(); int start = 0,end = 0; for(int i = 0;i < (int)size;i++){ if(str[i] == sep){ string st = line.substr(start,end); Trim(st); vct.push_back(st); start = i + 1; end = 0; }else end++; } if(end > 0){ string st = line.substr(start,end); Trim(st); vct.push_back(st); } } void strps::Stringsplit(string str, string splits, vector<string>& res){ if (str == "") return; //A separator is also added at the end of the string to intercept the last paragraph string strs = str + splits; size_t pos = strs.find(splits); int step = splits.size(); // If the content is not found, the string search function returns npos while (pos != strs.npos) { string temp = strs.substr(0, pos); res.push_back(temp); //Remove the split string and split it in the remaining string strs = strs.substr(pos + step, strs.size()); pos = strs.find(splits); } } inline bool fileIO::check_exists(char* name) { struct stat buffer; return (stat (name, &buffer) == 0); } string strps::encoding::GBKToUTF8(const string &strGBK){ string strOutUTF8 = ""; WCHAR *str1; int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), - 1, NULL, 0); str1 = new WCHAR[n]; MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), - 1, str1, n); n = WideCharToMultiByte(CP_UTF8, 0, str1, - 1, NULL, 0, NULL, NULL); char *str2 = new char[n]; WideCharToMultiByte(CP_UTF8, 0, str1, - 1, str2, n, NULL, NULL); strOutUTF8 = str2; delete [] str1; str1 = NULL; delete [] str2; str2 = NULL; return strOutUTF8; } string strps::encoding::UTF8ToGBK(const string &strUTF8){ int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), - 1, NULL, 0); WCHAR *wszGBK = new WCHAR[len + 1]; memset(wszGBK, 0, (len+1)*sizeof(WCHAR)); MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)strUTF8.c_str(), - 1, wszGBK, len); len = WideCharToMultiByte(CP_ACP, 0, wszGBK, - 1, NULL, 0, NULL, NULL); char *szGBK = new char[len + 1]; memset(szGBK, 0, len + 1); WideCharToMultiByte(CP_ACP, 0, wszGBK, - 1, szGBK, len, NULL, NULL); //strUTF8 = szGBK; string strTemp(szGBK); delete [] szGBK; szGBK = NULL; delete [] wszGBK; wszGBK = NULL; return strTemp; } void num::random::ShakeInit(num::random::ShakeSt & st,float timePerRound,float minv,float maxv,float start,int startDiection){ st.insideClock.Stop(); st.shakeValue = start; if(maxv > minv){ st.mn = minv; st.mx = maxv; }else{ st.mn = maxv; st.mx = minv; } st.stDirection = startDiection; st.timePerRound = timePerRound; st.time = 0; st.insideClock.Start(); } void num::random::Shake(num::random::ShakeSt & st){ float nowOff = ((float)st.insideClock.GetOffset())/((float)1000); //cout << nowOff << endl; float off = (float)(st.mx - st.mn) * ((float)nowOff / (float)st.timePerRound); float off1 = st.shakeValue + off * st.stDirection; if(off1 >= st.mx){ off1 = st.mx; st.stDirection = -1; }else if(off1 <= st.mn){ off1 = st.mn; st.stDirection = 1; } st.shakeValue = off1; } num::vectors::Vector num::vectors::Normalize(num::vectors::Vector v){ float sum = v.x*v.x + v.y*v.y + v.z*v.z; float len = sqrt(sum); return Vector(v.x / len,v.y / len,v.z / len); } num::vectors::Vector::Vector(float v0,float v1,float v2){ this->x = v0; this->y = v1; this->z = v2; }
//ResProcessor.h #ifndef RESPROCESSOR_H_INCLUDED #define RESPROCESSOR_H_INCLUDED #include <malloc.h> #include <windows.h> #include <stdio.h> #include "ctool.h" #define MASSERT(C,S) if(C){S;} char * GetResourceDataPtrDebug(HMODULE,LPCSTR,LPCSTR,int & err,LPCSTR useForDebug = ""); char * GetThisResourceDataPtrDebug(LPCSTR,LPCSTR,int & err,LPCSTR useForDebug = ""); char * GetThisResourceDataPtrRelease(LPCSTR,LPCSTR,int & err); char * GetResourceDataPtrRelease(HMODULE,LPCSTR,LPCSTR,int & err); char * GetResourceDataPtr(HMODULE,LPCSTR,LPCSTR,int & err,LPCSTR useForDebug = "");//handle res type,data is created by malloc char * GetThisResourceDataPtr(LPCSTR,LPCSTR,int & err,LPCSTR useForDebug = ""); #endif // RESPROCESSOR_H_INCLUDED
//ResProcessor.cpp #include "ResProcessor.h" char * GetResourceDataPtr(HMODULE h,LPCSTR s,LPCSTR s1,int & err,LPCSTR useForDebug){ #ifndef BUILD_DEBUG return GetResourceDataPtrRelease(h,s,s1,err); #else return GetResourceDataPtrDebug(h,s,s1,err,useForDebug); #endif // BUILD_DEBUG } char * GetThisResourceDataPtr(LPCSTR s,LPCSTR s1,int & err,LPCSTR useForDebug){ return GetResourceDataPtr(GetModuleHandle(NULL),s,s1,err,useForDebug); } char * GetResourceDataPtrDebug(HMODULE h,LPCSTR s,LPCSTR s1,int & err,LPCSTR useForDebug){ int fileSz = fileIO::file_size((char *)useForDebug); MASSERT(fileSz == -1,err = ERR_GETING_RES_SIZE;return NULL); FILE * filed = fopen(useForDebug,"r"); MASSERT(!filed,err = ERR_GET_RES_DATA;return NULL); char * data = (char *)malloc(sizeof(char) * (fileSz+1)); MASSERT(!data,err = ERR_COPY_DATA;fclose(filed);return NULL); ZeroMemory(data,sizeof(char) * (fileSz+1)); MASSERT(GetLastError(),err = ERR_COPY_DATA;fclose(filed);return NULL); fread(data,sizeof(char),fileSz,filed); return data; } char * GetThisResourceDataPtrDebug(LPCSTR s,LPCSTR s1,int & err,LPCSTR useForDebug){ return GetResourceDataPtrDebug(GetModuleHandle(NULL),s,s1,err,useForDebug); } char * GetThisResourceDataPtrRelease(LPCSTR s,LPCSTR s1,int & err){ return GetResourceDataPtrRelease(GetModuleHandle(NULL),s,s1,err); } char * GetResourceDataPtrRelease(HMODULE h,LPCSTR s,LPCSTR s1,int & err){ typedef char T; HRSRC rs = FindResource(h,s,s1);//Check Resource MASSERT(GetLastError() || !rs,err = ERR_FIND_RES;return NULL); HGLOBAL glb = LoadResource(h,rs);//Load Resource MASSERT(GetLastError() || !glb,err = ERR_LOAD_RES;return NULL); T * sdata = (T*)LockResource(glb);//Do not need to use UnlockResource to Free it MASSERT(GetLastError() || !sdata,err = ERR_GET_RES_DATA;return NULL); DWORD size = SizeofResource(h,rs);//Get Resource size MASSERT(GetLastError() || !size,err = ERR_COPY_DATA;return NULL); size_t sz = sizeof(BYTE) * (size + 1); T * data = (T *)malloc(sz);//CopyData MASSERT(!data,err = ERR_COPY_DATA;return NULL); ZeroMemory(data,sz); strncpy(data,sdata,sz); MASSERT(GetLastError(),err = ERR_COPY_DATA;return NULL); return data; }
Well, there are more than 13000 words unknowingly. This is my first time to write a blog, and I haven't learned c + + for long. It's about a month (not including the time to write code). I still read it casually from the online video. Therefore, I must have misunderstood some things. If there is a mistake, please point out. Thank you very much. Thank you!
reference material:
Microsoft MSDN:
LockResource function (libloaderapi.h) - Win32 apps | Microsoft Docs
LoadResource function (libloaderapi.h) - Win32 apps | Microsoft Docs
FindResourceA function (winbase.h) - Win32 apps | Microsoft Docs
UNICODE GBK UTF-8 transcoding (VC + +) _sunflover454 column - CSDN blog
c language gets the size of the file_ qq_36553031 blog - CSDN blog_ Get file size in c language