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 “..\\debug\\TaskbarExtHk.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_DEBUG 130
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 “..\\debug\\TaskbarExtHk.dll”
#else // _DEBUG
IDR_TBEHK_RELEASE BINARY MOVEABLE PURE “..\\release\\TaskbarExtHk.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 file CopyMemory(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?
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
By: Afshan Raees on February 20, 2008
at 7:29 pm
Ok, I resolved my earlier problem but still the .res file does not have my dll embeded in it.
By: Afshan Raees on February 21, 2008
at 2:03 am
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.
By: syedgakbar on February 22, 2008
at 10:25 am
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 Files\Common Files\Microsoft Shared\OFFICE12\mso.dll”
IDR_VB6_DLL BINARY MOVEABLE PURE “C:\Program Files\Common Files\Microsoft Shared\VBA\VBA6\VBE6EXT.OLB”
IDR_EXCEL_DLL BINARY MOVEABLE PURE “C:\Program Files\Microsoft Office\OFFICE12\excel.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
By: Afshan Raees on February 26, 2008
at 6:41 pm
Sorry I forgot to give details of my enviroment;
OS: Microsoft Windows XP Version 2002 SP2
Visual Studio 2005
By: Afshan Raees on February 26, 2008
at 6:44 pm
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.
By: syedgakbar on February 26, 2008
at 7:03 pm
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
By: Afshan Raees on February 26, 2008
at 8:46 pm
Anybody tried http://boxedapp.com
It seems it can create a virtual file with a DLL…
Thank you in advance.
By: John Garkins on October 7, 2008
at 1:00 am
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!
By: IvanV on January 18, 2009
at 7:36 am
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
By: syedgakbar on January 21, 2009
at 12:19 pm
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.
By: Matt Blackler on March 26, 2009
at 7:33 pm
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 ”res\\Project.dll”
Any suggestions? – I’m guessing it wants a type? (CURSOR, BITMAP etc?)
By: Dave on April 6, 2009
at 5:28 pm
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 “res\\Project.dll”
Hope this helps.
By: syedgakbar on April 9, 2009
at 12:04 pm
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 ?
By: serup on June 24, 2009
at 12:36 pm
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
By: serup on June 24, 2009
at 1:40 pm
bat file looks like this
DEL mydll.dll
DEL remove_dll.bat
By: serup on June 24, 2009
at 1:41 pm
It seems that in the original code one vital line was commented out see above:
// Write the file CopyMemory(lpBaseAddress, lpFile, dwSize);
making sure comment is on seperate line – then the whole thing works ! hmmm! small mistake
By: serup on June 24, 2009
at 11:14 am