|
Introduction
Over the years, I've seen various flavors of the question "How do I include a file or data with my program that I can extract at run-time and do something with it?" For example, the asker might have had a .WAV file or a .MDB (MS Access) file that s/he wanted to include in the actual executable itself. For one reason or another, they do not want to package the two files separately. One advantage this has over a separate data/configuration file is that it'll never get lost. If the user decides they want to start fresh, they can remove everything but the application itself, and when the application is started up again, it extracts an empty database, all without the user knowing the behind-the-scenes details.
So thre are really two questions on the table here: "How to include the file?" and "Once the file is included, how to extract it and 'use' it?" Let's look at a simple example.
Including the file
In this example, I'll show the necessary code to take the entire Windows calculator (calc.exe) and add it as a resource to some test .EXE. The .EXE could just as easily be the application where these code snippets reside. The first thing we must do is open calc.exe in read-only mode, and read the entire file into a buffer. HANDLE hFile;
DWORD dwFileSize,
dwBytesRead;
LPBYTE lpBuffer;
hFile = CreateFile(L"C:\\Winnt\\System32\\calc.exe", GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
dwFileSize = GetFileSize(hFile, NULL);
lpBuffer = new BYTE[dwFileSize];
if (ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL) != FALSE)
{
}
delete [] lpBuffer;
CloseHandle(hFile);
}
Updating the resource data
Now it's simply a matter of getting access to the resource data of the test file and updating it with the data pointed to by lpBuffer. The third parameter to UpdateResource() is the name we want to give the resource. I just chose an arbitrary name of 104. HANDLE hResource;
hResource = BeginUpdateResource(L"C:\\...\\t3.exe", FALSE);
if (NULL != hResource)
{
if (UpdateResource(hResource,
RT_RCDATA,
MAKEINTRESOURCE(104),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPVOID) lpBuffer,
dwFileSize) != FALSE)
{
EndUpdateResource(hResource, FALSE);
}
}
At this point, you can actually open the test file with Visual Studio and see the addition of our data in the "Data" section. Be sure to open the file as a "resource"!
Extracting the data
So now your application has been delivered, and you need to extract the resource data.
Extracting the resource data uses functions from the same family as UpdateResource(). The required steps are to load the file containing the resource data, find the desired resource, load the resource, and then lock it. HMODULE hLibrary;
HRSRC hResource;
HGLOBAL hResourceLoaded;
LPBYTE lpBuffer;
hLibrary = LoadLibrary(L"C:\\...\\t3.exe");
if (NULL != hLibrary)
{
hResource = FindResource(hLibrary, MAKEINTRESOURCE(104), RT_RCDATA);
if (NULL != hResource)
{
hResourceLoaded = LoadResource(hLibrary, hResource);
if (NULL != hResourceLoaded)
{
lpBuffer = (LPBYTE) LockResource(hResourceLoaded);
if (NULL != lpBuffer)
{
}
}
}
FreeLibrary(hLibrary);
}
Saving the data to a file
All that's left is to create a file with the data pointed to by lpBuffer. Nothing special needs to be done to the data. It's the entire Windows calculator! DWORD dwFileSize,
dwBytesWritten;
HANDLE hFile;
dwFileSize = SizeofResource(hLibrary, hResource);
hFile = CreateFile(L"C:\\Winnt\\Temp\\calc2.exe",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
WriteFile(hFile, lpBuffer, dwFileSize, &dwBytesWritten, NULL);
CloseHandle(hFile);
}
Now you should be able to run the newly created file, calc2.exe! As I indicated at the beginning of the article, this can be done with any sort of file that you want to include along with your main application or DLL.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 24 of 24 (Total in Forum: 24) (Refresh) | FirstPrevNext |
|
|
 |
|
|
If GetFileSize fails, everything below it will fail too if (dwFileSize==0xFFFFFFFF || dwFileSize <= 0 ) return 1;
-- Chizl
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
ChizI wrote: If GetFileSize fails, everything below it will fail too
No kidding! It stands to reason that unless the scope of the article is about error checking, the user of this code, and any other, is obviously responsible for employing such error checking practices.
Most articles omit error-checking code for brevity reasons. Competent developers will know that they must check for errors.
"Love people and use things, not love things and use people." - Unknown
"To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Excellent article! However I have been trying to add a .ico resource to a dll with this code, derived from yours:
if (UpdateResource(hResource, RT_ICON, MAKEINTRESOURCE(101), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPVOID) lpBuffer, dwFileSize) != FALSE){ MessageBox(0,"UpdateResource OK","OK",0); EndUpdateResource(hResource, FALSE); }
Works, but the icon never shows up as a resource (using VS2005, Axialis and Microangelo to check). I've searched high and low on the web and can not find any info on how to do this, guess not many people do this sort of thing Any help or ideas would be extremely welcome
Arnor Baldvinsson San Antonio, Texas
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The structures used to store icon images in .EXE and .DLL files (as resources) differ only slightly from those used in .ICO files. While it's possible to convert from one to the other, I don't have the time right now. I'll make a note for a later update.
"Approved Workmen Are Not Ashamed" - 2 Timothy 2:15
"Judge not by the eye but by the heart." - Native American Proverb
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks - I have located information on MSDN on how to construct resource files (.res) with icons etc. and I think I can work it out. Examples would be awsome, but your article has helped me a lot already
Arnor Baldvinsson San Antonio, Texas
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Thanks for your efforts David. This is going to be of great use. The article is simple, but very informative. Got my five too.
Regards, Rajesh R. Subramanian
You have an apple and me too. We exchange those and We have an apple each. You have an idea and me too. We exchange those and We have two ideas each.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks. I like your Shaw quote.
"The largest fire starts but with the smallest spark." - David Crow
"Judge not by the eye but by the heart." - Native American Proverb
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
You'll need to be more explicit about what you are trying to do, and what is not working.
"The largest fire starts but with the smallest spark." - David Crow
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Is it possible to update a resource within the currently running process? I know I can modify the contents of the memory once its loaded, but I'd like for the changes to the resource to actually be written to disk and persist across the next execution of the program. Any thoughts?
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Persetech wrote: ...but I'd like for the changes to the resource to actually be written to disk and persist across the next execution of the program.
If the process is running, and thus locked, I don't know how to do this.
"The greatest good you can do for another is not just to share your riches but to reveal to him his own." - Benjamin Disraeli
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thank you SO much! exactlyyyyyy what i've been looking for. coders like you make website like this ( http://www.codeproject.com ) worth a fortune!!
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Sir! i have got the Handle to THE ICON using ExtractIcon , now i Want to Update the Icon of Some Other EXE using above code.
Could you Please Tell me the Way to how to Proceed.
Thanks Sir!!!
"I Think this Will Help" Alok Gupta visit me at http://www.thisisalok.tk
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Nice article Dave . It would improve the look and readability of your article if you would edit the source code sections (inside the <pre></pre> blocks) such that they were limited to 60 character lines. When the lines are longer, they stretch the width used for the normal article text, and you end up having to scroll horizontally.
Software Zen: delete this;
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Ok every thing is ok, but 1 if there is resource in the destination file, Updateresource doesn't work 2 Updateresource doesn't work under w95 3 for a mysterious reson, under xp (maybe all NT) if you add a lot of new resources, updateresource fail.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
eco wrote: 1 if there is resource in the destination file, Updateresource doesn't work
What good would this function be if it failed simply because the destination file already had resources, especially since the second parameter to BeginUpdateResource() is just for this situation?
eco wrote: 2 Updateresource doesn't work under w95
Right, nor does it claim to.
eco wrote: 3 for a mysterious reson, under xp (maybe all NT) if you add a lot of new resources, updateresource fail.
I've not seen this. The documentation mentions nothing about a maximum number of resources that can be added. Do you have any code that reproduces the problem?
|
| Sign In·View Thread·PermaLink | 5.00/5 (2 votes) |
|
|
|
 |
|
|
I've had some experience with UpdateResource when adding resource dll creation into my program (Freelancer Mod Manager), and have encountered that same problem where UpdateResource fails when adding a lot of resources to it. Speficially, somewhere around 82 resources (mine were raw xml data). I couldn't figure out why it'd be failing, but I found a work-around: if you have more than ~82 resources (I think I set the max in FLMM to 60, to be on the safe side), just call UpdateResource multiple times, being sure to tell it to append onto the existing resources. Works great, is an easy fix, and doesn't affect speed too much.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I would not have thought to call UpdateResource() with more than one resource. I'm curious how you would do so since the third parameter is the name used to identify the resource.
Five birds are sitting on a fence. Three of them decide to fly off. How many are left?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Shoot, let me rephrase that; been away from programming working on my new Shuttle computer too long . What I should of said is that EndUpdateResouce fails if UpdateResource is called about 82+ times. What I did to fix it was call EndUpdateResource and immediately BeginUpdateResource after adding 60 resources. Here's the code I have in my XML resource adding loop:
if(i%60==0) { no_error &= EndUpdateResourceW(resources_handle, FALSE ); resources_handle = BeginUpdateResourceW(A2CW(DLLPath.GetBuffer()),FALSE); DLLPath.ReleaseBuffer(); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
If there any way to update existing app defined resource ? I'm trying
HANDLE h = BeginUpdateResource("my.dll",FALSE); UpdateResource(h,"DB",MAKEINTRESOURCE(resourceID),MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),(LPVOID)data,dataSize)) EndUpdateResource(h,FALSE))
The function returns TRUE, but resource isn't updated. Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Does resource resourceID or type "DB" actually exist in my.dll? Check out the EnumResourcexxx() functions to be sure.
A rich person is not the one who has the most, but the one that needs the least.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Be careful with the Language ID when using this function. If the existing resource in your binary file (in your case, a DLL) has a different language ID then the one you specify in the UpdateResource() function, the function will add a new resource and not replace the old one. Now you have 2 resources in your binary file with the same Resource ID, just under 2 different languages. Yikes!
Sometimes people use the MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) when specifying the Language ID in this function; like David did in his article. This is fine, but Visual C++ by default takes the current language setting of your Windows OS when creating a new project. This is easily changed (in VC++ 6.0) by going to Project | Settings, choosing the Resources tab, and messing with the Language dropdown combobox list. But note that whatever this setting is, it is NOT the same as MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) thus giving you the problem outlined above.
A great way of checking to see if this is your problem is by loading your DLL in VC++ in resource edit mode. Choose File | Open, select your DLL from the file dialog box, but before you say OK, change the Open As combo box to “Resources” instead of the default “Auto”. Now you can see if you indeed have 2 instances of your resource under different languages.
Regards
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
That's definitely right!! I encountered the problem said by Micheal R just now!! What all I want is to midify the icon of a existed EXE. I used UpDateResource with MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) to replace the original icon, but it turned out that it has two icons with the same ID!!!  After read Micheal's I tried EnumResourceLanguages to get the language of the original icon, and then UpDateResource with the same language ID. It works now!! img src="/script/Forums/Images/smiley_laugh.gif" align="top" alt="Laugh" />
Coding is my life!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|