Extract file from resource in Windows module - c++

The below code executes, but it only extracts an empty bitmap file. Any ideas as to what is wrong with it?
void Extract(WORD wResId , LPSTR lpszOutputPath)
{ //example: Extract(IDB_BITMAP1, "Redrose.bmp");
HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(wResId) , RT_BITMAP);
HGLOBAL hLoaded = LoadResource( NULL,hrsrc);
LPVOID lpLock = LockResource( hLoaded);
DWORD dwSize = SizeofResource(NULL, hrsrc);
HANDLE hFile = CreateFile (lpszOutputPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
DWORD dwByteWritten;
WriteFile(hFile, lpLock , dwSize , &dwByteWritten , NULL);
CloseHandle(hFile);
FreeResource(hLoaded);
}

You are asking for RT_RCDATA but I bet you didn't add your bitmap via a RCDATA statement. You probably added it via a BITMAP statement, which makes it RT_BITMAP.
In the future, please state which step failed rather than making people guess.

Insert your raw file as a custom data.
Give this custom data a text name, example "MyType", then:
HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(wResId) , _T("MyType"));

The problem is in passing NULL as your HINSTANCE parameter to FindResource, LoadResource, and SizeOfResource.
If you have not already saved your HINSTANCE during startup (from WinMain or DllMain) you can get it using:
MFC:
HINSTANCE hInstance = AfxGetInstanceHandle();
Else:
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);

Related

Show path to a dll in a MessageBox husing handle

I load a dll with this command
HINSTANCE DllEconovent = LoadLibrary(_T("Econovent.dll"));
I want to get the path from where the dll is loaded from disk... In this fake case
C:\TFS_FWG\Acon\Oem\bin\Econovent.20140130_3200\Econovent64\Econovent.dll
And just show it with message box
MessageBox(_T("No valid ProcAddress"), _T("Error"), MB_ICONINFORMATION);
How is this done in the best way?
Have a look at GetModuleFileName: this function "retrieves the fully qualified path for the file that contains the specified module."
DWORD WINAPI GetModuleFileName(
_In_opt_ HMODULE hModule,
_Out_ LPTSTR lpFilename,
_In_ DWORD nSize
);
It should take in your HINSTANCE object and give you back a filename.
A simple example
int main()
{
HINSTANCE test = LoadLibrary("test.dll");
char buffer[MAX_PATH];
GetModuleFileName(test, buffer, MAX_PATH);
std::cout << buffer << std::endl;
return 0;
}
Adapting it to the MessageBox, just remove the line with std::cout and put
MessageBox(buffer, _T("Error"), MB_ICONINFORMATION);

WriteFile writes incorrectly

I'm trying to copy a file from resources to %localappdata%. I've something like this:
HINSTANCE hInstance = GetModuleHandle(NULL);
HANDLE hFile = INVALID_HANDLE_VALUE;
HRSRC hrsrc = FindResource(hInstance, MAKEINTRESOURCE(MSIE), RT_RCDATA);
HGLOBAL exeRes = LoadResource(hInstance, hrsrc);
DWORD size = SizeofResource(hInstance, hrsrc);
TCHAR szPath[MAX_PATH];
HANDLE hfile;
if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, szPath))) {
PathAppend(szPath, TEXT("test.exe"));
hFile = CreateFile(szPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
LPVOID exePtr = LockResource(hrsrc);
DWORD exeWritten = 0;
BOOL writeResult = WriteFile(hFile, exePtr, size, &exeWritten, NULL);
cout << GetLastError() << endl;
BOOL closed = CloseHandle(hFile);
system("PAUSE");
return 0;
I'm able to locate the HRSRC and confirm the size using SizeofResource() just fine. CreateFile is in fact creating the file and returning the handle. GetLastError() reports that there are no errors. The amount of bytes written to disk is exactly right.
The output exe however is corrupted (the version of this file is incompatible with the version of Windows... blah blah) - it's lost its icon and everything. Looking at the original and the output file side-by-side in a hex editor it appears there's random data at the start of file.
What am I missing here?
Your LockResource is not correct. It should be passed the HGLOBAL exeRes you loaded previously.
LockResource(hrsrc);
should be
LockResource(exeRes);
From the MS documentation on LockResource() :
Do not try to lock a resource by using the handle returned by the FindResource or FindResourceEx function. Such a handle points to random data.
And as a side note, you may want to try cleaning up that loaded-and-locked resource when you're through with it.

How to get size of a loaded icon in c++ winapi

i have loaded an icon ("c:\test.ico") using LoadImage() function
how can i get the size of this icon? (number of bytes in it)
i am using c++ & winapi
HRSRC hRes = LoadImage ( NULL, icon, IMAGE_ICON, 0, 0, LR_LOADFROMFILE );
LPVOID lpResLock = LockResource(hRes);
(more precisely, size of data pointed to by "lpResLock")
========update======
i know about sizeofresource() But the problem is, its to load resource from an executable files. As i shown in my question, i am loading a standalone- local resource from disk file. Second issue is, the hResInfo parameter must have to be created using FindResource function, in my case i am using LoadImage().. So this cant be of help
Google for SizeofResource(). Its a standard win32 API function IIRC
This is the function prototype:
DWORD WINAPI SizeofResource(
_In_opt_ HMODULE hModule,
_In_ HRSRC hResInfo
);
Parameters:
hModule [in, optional] Type: HMODULE
A handle to the module whose executable file contains the resource.
hResInfo [in] Type: HRSRC
A handle to the resource. This handle must be created by using the FindResource or FindResourceEx function.
Update-
Then, the length of resource from a file = sizeof the file.
use: GetFileLength() function coded like this:
DWORD GetFileLength(LPSTR fileName)
{
DWORD len = 0;
OFSTRUCT of;
HFILE hFile = OpenFile(fileName,&of, OF_READ);
GetFileSize(hFile,&len);
CloseHandle(hFile);
return len;
}

Converting a PIDL to file path with SHGetPathFromIDList

My application receives a PIDL as a string:
QString pidl = "::{20D04FE1-3AEA-1069-A2D8-08002B30309B}";
In this case it corresponds to My Computer. I need to convert it to My Computer.
Theres a WINAPI function SHGetPathFromIDList which requires the LPCITEMIDLIST as the first parameter and converts it to a string.
How can I build that LPCITEMIDLIST?
UPDATE
This is what I got so far:
LPCWSTR csPath = (LPCWSTR)"::{20D04FE1-3AEA-1069-A2D8-08002B30309B}";
LPITEMIDLIST stId = 0;
SFGAOF stSFGAOFIn = 0;
SFGAOF stSFGAOFOut = 0;
if(!FAILED(SHParseDisplayName(csPath, 0, stId, stSFGAOFIn, &stSFGAOFOut)))
msgBox("not failed")
Unfortunately this code crashes.
Your code crashes because you are not setting up the 1st and 3rd parameters of SHParseDisplayName() correctly. Try this instead:
LPCWSTR csPath = L"::{20D04FE1-3AEA-1069-A2D8-08002B30309B}";
PIDLIST_ABSOLUTE stId = NULL;
SFGAOF stSFGAOFIn = 0;
SFGAOF stSFGAOFOut = 0;
if (!FAILED(SHParseDisplayName(csPath, NULL, &stId, stSFGAOFIn, &stSFGAOFOut)))
msgBox("not failed")
The function you need is not SHGetPathFromIDList, because there is no path for "My Computer".
To convert your QString pidl to an PIDLIST_ABSOLUTE you need to use SHParseDisplayName.
To convert the PIDLIST_ABSOLUTE to a localised string like "My Computer" you need SHGetNameFromIDList.
I think may be:
SHParseDisplayName(csPath, 0, &stId, stSFGAOFIn, &stSFGAOFOut)
Declaration of SHParseDisplayName from MSDN:
HRESULT SHParseDisplayName(
__in LPCWSTR pszName,
__in_opt IBindCtx *pbc,
__out PIDLIST_ABSOLUTE *ppidl,
__in SFGAOF sfgaoIn,
__out_opt SFGAOF *psfgaoOut
);

How to ensure only one process is created by CreateProcess when calling concurrently in c++?

Quoted from here:
BOOL WINAPI CreateProcess(
__in_opt LPCTSTR lpApplicationName,
__inout_opt LPTSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCTSTR lpCurrentDirectory,
__in LPSTARTUPINFO lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
I have two independant programe that creates exactly the same process, how can I ensure that if one of them has already created the process, the other won't create it twice?
The most simple way is if you create a named object after the start of the program. For example CreateEvent, CreateMutex and so on. To verify existance of the application you can just use OpenEvent, OpenMutex and so on before creating of the object. You can choose (if desired) the name of the object with the the "Global\" prefix (see http://msdn.microsoft.com/en-us/library/aa382954.aspx) to allow only one process for all terminal server session.
UPDATED: Because how I can see there are different opinions about my suggestion I try to explain it more exactly and add the corresponding test example.
The main idea is that the application which are started create any named object is the object with the same name not yet exist. This only reserve the name in the Kernel Object Namespaces. No real usage of the object are needed. The advantaged of this way compared with creating of a file on the disk is that named objects are temporary and are owned by a application. So if the application are ended, be killed or be terminated in any other way (because of unhanded exception for example) the named object will be automatically deleted by the operation system. In the following example I don't use CloseHandle at all. How you can test the application can successfully determine whether it runs as the first instance or not.
#include <windows.h>
//#include <Sddl.h>
LPCTSTR g_pszEventName = TEXT("MyTestEvent"); // TEXT("Global\\MyTestEvent")
void DisplayFirstInstanceStartedMessage()
{
TCHAR szText[1024];
wsprintf (szText,
TEXT("The first instance are started.\nThe event with the name \"%s\" is created."),
g_pszEventName);
MessageBox (NULL,
szText,
TEXT("CreateEventTest"), MB_OK);
}
void DisplayAlreadyRunningMessage ()
{
TCHAR szText[1024];
wsprintf (szText,
TEXT("The first instance of the aplication is already running.\nThe event with the name \"%s\" already exist."),
g_pszEventName);
MessageBox (NULL,
szText,
TEXT("CreateEventTest"), MB_ICONWARNING | MB_OK);
}
void DisplayErrorMessage (DWORD dwErrorCode)
{
if (dwErrorCode == ERROR_ALREADY_EXISTS)
DisplayAlreadyRunningMessage();
else {
LPTSTR pErrorString;
if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | // Always search in system message table !!!
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
0, NULL, // source of message definition
dwErrorCode, // message ID
// 0, // language ID
// GetUserDefaultLangID(), // language ID
// GetSystemDefaultLangID(),
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&pErrorString, // pointer for buffer to allocate
0, // min number of chars to allocate
NULL)) {
MessageBox (NULL, pErrorString, TEXT("CreateEventTest"), MB_OK);
LocalFree (pErrorString);
}
else {
TCHAR szText[1024];
wsprintf (szText, TEXT("Error %d in the CreateEvent(..., \"%s\")"), dwErrorCode, g_pszEventName);
MessageBox (NULL, szText, TEXT("CreateEventTest"), MB_OK);
}
}
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//SECURITY_ATTRIBUTES sa;
//BOOL bSuccess;
HANDLE hEvent = OpenEvent (EVENT_MODIFY_STATE, FALSE, g_pszEventName);// EVENT_ALL_ACCESS
if (hEvent == NULL) {
DWORD dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_FILE_NOT_FOUND) {
DisplayErrorMessage(dwErrorCode);
return 1;
}
}
else {
DisplayAlreadyRunningMessage();
return 0;
}
//sa.bInheritHandle = FALSE;
//sa.nLength = sizeof(SECURITY_ATTRIBUTES);
//bSuccess = ConvertStringSecurityDescriptorToSecurityDescriptor (
// TEXT("D:(A;OICI;GA;;;WD)"), // Allow full control
// SDDL_REVISION_1,
// &sa.lpSecurityDescriptor,
// NULL);
hEvent = CreateEvent (NULL, // &sa
TRUE, FALSE, g_pszEventName);
//sa.lpSecurityDescriptor = LocalFree (sa.lpSecurityDescriptor);
if (hEvent == NULL) {
DWORD dwErrorCode = GetLastError();
DisplayErrorMessage(dwErrorCode);
return 1;
}
else
DisplayFirstInstanceStartedMessage();
return 0;
UNREFERENCED_PARAMETER (hInstance);
UNREFERENCED_PARAMETER (hPrevInstance);
UNREFERENCED_PARAMETER (lpCmdLine);
UNREFERENCED_PARAMETER (nShowCmd);
}
If one want support that different users from the same desktop or from the different desktops could start only one instance of the program, one can uncomment some parts of the commented code or replace the name MyTestEvent of the event to Global\MyTestEvent.
I hope after the example my position will be clear. In such kind of the event usage no call of WaitForSingleObject() are needed.
You cannot do this by letting the process you start creating a named object. That's an inherent race condition, it takes time for the process to get started. Both programs need to call CreateMutex at some point before trying to create the 3rd process with an agreed-upon name. Then they need to call WaitForSingleObject() with a zero wait time to try to acquire the mutex. Whomever gets it is the one that should call CreateProcess().
More work is needed after this to deal with this 3rd process terminating.
You can use this function
BOOL WINAPI EnumProcesses(
__out DWORD *pProcessIds,
__in DWORD cb,
__out DWORD *pBytesReturned
);
to get a list of all the pids of all currently running processes and check if the process is running?