Embedding DLL and binary files in the Win32 Executable
Embedding DLL and binary files in the Executable applications Though for most of the cases, it’s recommended keep the resources and other libraries separate from the main executable. This makes the main application executable size small, and thus that application will take less memory on load and will load/unload the external resources as required. Yet sometimes, it makes sense to append the external files as part of executable. A popular example of this is self extracting installer. The basic technique behind this whole process is simple. Here is what needs to be done:
Write a resource script file which provides path to the external files you want to append in the final resource object.
- Use the Resource Compiler to build a RES file from the above script.
- Bind the RES file with executable.
- Call the APIs to extract and load the resources from the executable memory space at run-time.
- First one to add a Resource Script file in the executable project. Here is a sample code to define the binary resource in
- the resource script file
IDR_TBEHK_DEBUG BINARY MOVEABLE PURE "..debugTaskbarExtHk.dll" |
IDR_TBEHK_DEBUG BINARY MOVEABLE PURE "..debugTaskbarExtHk.dll"
Please note that “IDR_TBEHK_DEBUG” is user defined constant and must be declared before this line. Here is how I have defined this at top:
#define IDR_TBEHK_DEBUG130 |
#define IDR_TBEHK_DEBUG130
There is catch here. Some of the files are conditional and thus we may need some checks on which version of file to include. One way of doing this is to use the standard C++ compiler directives (these syntax is almost same for Resource Compiler):
#ifdef _DEBUG IDR_TBEHK_DEBUG BINARY MOVEABLE PURE "..debugTaskbarExtHk.dll" #else// _DEBUG IDR_TBEHK_RELEASE BINARY MOVEABLE PURE "..releaseTaskbarExtHk.dll" #endif |
#ifdef _DEBUG IDR_TBEHK_DEBUG BINARY MOVEABLE PURE "..debugTaskbarExtHk.dll" #else// _DEBUG IDR_TBEHK_RELEASE BINARY MOVEABLE PURE "..releaseTaskbarExtHk.dll" #endif
But wait, we also need to define the value for the _DEBUG symbol (the one defined for C++ project will not work here, as this file is read by resource compiler and is a totally different context). In Visual Studio, you can easily define these Resource preprocessor directives in the project properties. Simply add “_DEBUG” for the DEBUG configuration and it will add the conditional embedding of the correct version.
Another simple option for including binary libraries is to change the project settings is to set a single output folder for both Debug and Release configurations and then just include that single file. Once the RC file is ready, it can be compiled to RES file using the Resource Compiler. Here is a sample command line for this: rc.exe /fo”Release/TaskbarExt.res” “.TaskbarExt.rc” If you are using Visual Studio, then it will automatically call this for you and will build the RES file and will also bind it with executable.
The next big part is finding and loading the resource from the executable. Here is a sample code to do this:
bool ExtractResource(const HINSTANCE hInstance, WORD resourceID, LPCTSTR szOutputFilename) { bool bSuccess = false; try { // First find and load the required resource HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(resourceID), _T("BINARY")); HGLOBAL hFileResource = LoadResource(hInstance, hResource); // Now open and map this to a disk file LPVOID lpFile = LockResource(hFileResource); DWORD dwSize = SizeofResource(hInstance, hResource); // Open the file and filemap HANDLE hFile = CreateFile(szOutputFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); HANDLE hFilemap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL); LPVOID lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0); // Write the fileCopyMemory(lpBaseAddress, lpFile, dwSize); // Unmap the file and close the handles UnmapViewOfFile(lpBaseAddress); CloseHandle(hFilemap); CloseHandle(hFile); } catch(...) { // Ignore all type of errors } return bSuccess; } |
bool ExtractResource(const HINSTANCE hInstance, WORD resourceID, LPCTSTR szOutputFilename) { bool bSuccess = false; try { // First find and load the required resource HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(resourceID), _T("BINARY")); HGLOBAL hFileResource = LoadResource(hInstance, hResource); // Now open and map this to a disk file LPVOID lpFile = LockResource(hFileResource); DWORD dwSize = SizeofResource(hInstance, hResource); // Open the file and filemap HANDLE hFile = CreateFile(szOutputFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); HANDLE hFilemap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL); LPVOID lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0); // Write the fileCopyMemory(lpBaseAddress, lpFile, dwSize); // Unmap the file and close the handles UnmapViewOfFile(lpBaseAddress); CloseHandle(hFilemap); CloseHandle(hFile); } catch(...) { // Ignore all type of errors } return bSuccess; }
Once you are done with resource, you can remove it by calling the DeleteFile API.
Simple is that! Isn’t it?
Tags: C++, DLL, Resouces, Win32
This entry was posted
on Wednesday, November 7th, 2007 at 12:41 am and is filed under Visual C++, Win32 API.
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.
Howto remove dll after use from inside your program which initially extracted the dll file :
***
//+ REMOVE THE DLL AFTER THE PROGRAM ENDS (DLL WILL NOT BE POSSIBLE TO REMOVE BEFORE IT HAS BEEN UNLOADED, THUS THIS BULKY SOLUTION)
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line).
TEXT(“remove_dll.bat”), // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent’s environment block.
NULL, // Use parent’s starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
{
printf( “CreateProcess failed (%d).n”, GetLastError() );
return;
}
//-
***
The bat file looks like this
DEL
DEL
How is it possible for me to unload the dll after my program has used it ?
– First I extract it
– Then I use it.
– Then my program is shutting down and trying to delete my extracted dll file, however it is somehow still in used, hence not possible to delete
How is it possible for me to unload the dll first ?
Even if I add the GENERIC_EXECUTE in CreateFile, the resulting file when extracted is not the same as the original one being embedded ??
thus the dll will not work !!
Code is in a MFC project, otherwise exactly the same as described here – Any suggestions to solving this ?
Dave,
Sorry for the late reply. I was busy with something else. Regarindg your problem, please make sure that the line you added in the resource file has correct double quotes character (if you copied these directly from the web-page, they might not be double quotes characters (due to encoding difference). Basically, try this:
IDR_PKEY_DLL BINARY MOVEABLE PURE “resProject.dll”
Hope this helps.
Hi,
Just tried this, but windres doesn’t like it:
compiling: resource.rc
windres.exe: resource.rc:17: syntax error
In my header, I have:
#define IDR_PKEY_DLL 102
And in the resource file I have:
IDR_PKEY_DLL BINARY MOVEABLE PURE ”resProject.dll”
Any suggestions? – I’m guessing it wants a type? (CURSOR, BITMAP etc?)
Thanks for this, you’ve saved me hours of frustration. I’ll just add that if you embed the resource using visual studio, _T(“BINARY”) in the above code should be replaced with _T(“resourceType”) where resourceType is the name of the folder-like thing in the resource editor created when you add the resource.
Hi IvanV,
It looks like the error you are describing is coming even before your code reach the resource extraction point. To confirm this, add some alert at the very first line of you application. See if you get that alert first or the above message?
If you get the above message first, then most probably the problem is that you have binded some DLLs with your application and it’s failing when it doesn’t find those.
Let me know what are you findings and then I can suggest more.
Regards,
Akbar
I tried to embed libmysql.dll in my app, but I still have problem. Length of exe and res file are OK and dll is embedded.
But when I start .exe app search for libmysql.dll and refuse to start with following error:
“This application has failed to start beacause libmysql.dll was not found. Re-installing the application may fix this problem”
I call your ExtractResource like this:
BOOL qw = ExtractResource( (HINSTANCE) hwnd, ID_MYSQL_DLL, TEXT(“libmysql.dll”) );
When I put .exe in the same folder with libmysql.dll and change:
BOOL qw = ExtractResource( (HINSTANCE) hwnd, ID_MYSQL_DLL, TEXT(“mydll.dll”) );
application starts and create mydll.dll which means that dll is embedded, but compilation is wrong.
Help please!
Anybody tried http://boxedapp.com
It seems it can create a virtual file with a DLL…
Thank you in advance.
I guess adding the extra flag GENERIC_EXECUTE in CreateFile method solved the problem. I have them all working now. Thanks for all your help!
Afshan
Afshan,
What exactly you mean by the problem that extracted binaries are not intact? Does the size of the extracted files match with the original? If no, please carefully check/debug the file extraction code and see where the problem appears.
Also try checking the size of the embedded resources (binar files) using Visual Studio or any other resource explorer to make sure that embedded resources are of correct size.
Hope this helps.
Sorry I forgot to give details of my enviroment;
OS: Microsoft Windows XP Version 2002 SP2
Visual Studio 2005
Thank you for your prompt reply, I was able to resolve my compilation problems but now the issue is that the embedded dlls are getting mangled.
Here is what I am trying to do:
– My application is an MS Office automation application using Office 2007.
– I wanted to embed EXCEL.EXE, VBE6EXT.OLB and mso.dll to provide excel 2007 functionality.
– The idea was to make it a stand alone application that does not require installation of Office 2007 on the server. Now the embedding piece is OK as follows:
IDR_OFFICE_DLL BINARY MOVEABLE PURE “C:Program FilesCommon FilesMicrosoft SharedOFFICE12mso.dll”
IDR_VB6_DLL BINARY MOVEABLE PURE “C:Program FilesCommon FilesMicrosoft SharedVBAVBA6VBE6EXT.OLB”
IDR_EXCEL_DLL BINARY MOVEABLE PURE “C:Program FilesMicrosoft OfficeOFFICE12excel.exe”
But when I write the dlls out to make the temporary copy, the binaries are not intact.
Any idea how I could get around this problem. Thanks a lot for your help!
Afshan
Afshan,
You are using Visual Studio for this? If yes, I would recommend that you review the compilation log. This should be in your DEBUG or RELEASE folder depending on the setting. This will give you clue on why the system is ignoring your resource file.
If that doesn’t make sense, post the content of that compile file here and I can review it for you and can help you pin point the issue.
Ok, I resolved my earlier problem but still the .res file does not have my dll embeded in it.
I am trying to embed excel type library in my project binary and am running into problems. This is an MFC project that I am working on it complains about L”BINARY” being undeclared. Not sure if this solution will work in MFC. Thanks