Show path to a dll in a MessageBox husing handle - c++

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);

Related

Hooking CreateFile in notepad.exe does not catch API calls

My ultimate goal is to track file operations done by explorer.exe via hooking file api in kernel32.dll, however I have yet to get that working (either explorer.exe is not calling the APIs, or something is wrong on my end). In order to figure out what is going on, I've set a goal to track whenever notepad.exe creates a file, however this has failed for some reason as well!
I have 3 Visual Studio 2012 C++ projects: my DLL, a DLL injector that will force any executable to load my dll (although it may fail if Unicode/Multibyte and 32/64bit settings don't match up), and a test program that calls API. I have a batch file that will start my test program, and then use the injector program to load my DLL into the test program. The weird part is that the outputs do show that the APIs are being tracked on the test program (spawns the console and prints everything!) but nothing happens for notepad.exe (no console = no operations caught).
Here is the DLL that hooks the API (uses the mhook library). The format and concepts are taken from this guide. The important things to note are that I hook CreateFile(A/W), and spawn a console to print file I/O logs when the first operation occurs.
#include "stdafx.h"
#include "mhook/mhook-lib/mhook.h"
//////////////////////////////////////////////////////////////////////////
// Defines and typedefs
typedef HANDLE (WINAPI *CreateFileWFP)(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
typedef HANDLE (WINAPI *CreateFileAFP)(
_In_ LPCSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
//////////////////////////////////////////////////////////////////////////
// Original function
CreateFileWFP OriginalCreateFileW = (CreateFileWFP)::GetProcAddress(::GetModuleHandle(TEXT("kernel32")), "CreateFileW");
CreateFileAFP OriginalCreateFileA = (CreateFileAFP)::GetProcAddress(::GetModuleHandle(TEXT("kernel32")), "CreateFileA");
//////////////////////////////////////////////////////////////////////////
// Some Helper Stuff
struct Console{
HANDLE handle;
Console(){ handle = INVALID_HANDLE_VALUE; }
void write(LPCWSTR text){
if(handle==INVALID_HANDLE_VALUE){
AllocConsole();
handle = GetStdHandle(STD_OUTPUT_HANDLE);
}
DWORD numCharsWritten = 0;
WriteConsoleW(handle, text, (DWORD)wcslen(text), &numCharsWritten,NULL);
}
void write(LPCSTR text){
if(handle==INVALID_HANDLE_VALUE){
AllocConsole();
handle = GetStdHandle(STD_OUTPUT_HANDLE);
}
DWORD numCharsWritten = 0;
WriteConsoleA(handle, text, (DWORD)strlen(text), &numCharsWritten,NULL);
}
} console;
void operationPrint(LPCWSTR left, LPCWSTR middle, LPCWSTR right){
console.write(left);
console.write(middle);
console.write(right);
console.write(L"\n");
}
void operationPrint(LPCSTR left, LPCSTR middle, LPCSTR right){
console.write(left);
console.write(middle);
console.write(right);
console.write(L"\n");
}
//////////////////////////////////////////////////////////////////////////
// Hooked function
HANDLE HookedCreateFileW(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
){
HANDLE out = OriginalCreateFileW(
lpFileName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
if(out == INVALID_HANDLE_VALUE) return out; //ignore failiures
operationPrint(L"CreatedW file",L" at ",lpFileName);
return out;
}
HANDLE HookedCreateFileA(
_In_ LPCSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
){
HANDLE out = OriginalCreateFileA(
lpFileName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
if(out == INVALID_HANDLE_VALUE) return out; //ignore failiures
operationPrint("CreatedA file"," at ",lpFileName);
return out;
}
//////////////////////////////////////////////////////////////////////////
// Entry point
BOOL WINAPI DllMain(
__in HINSTANCE hInstance,
__in DWORD Reason,
__in LPVOID Reserved
)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
Mhook_SetHook((PVOID*)&OriginalCreateFileW, HookedCreateFileW);
Mhook_SetHook((PVOID*)&OriginalCreateFileA, HookedCreateFileA);
break;
case DLL_PROCESS_DETACH:
FreeConsole();
Mhook_Unhook((PVOID*)&OriginalCreateFileW);
Mhook_Unhook((PVOID*)&OriginalCreateFileA);
break;
}
return TRUE;
}
I can't find exactly where I found the injector program, but it is nearly identical to this guide. Some of the comments are even the same, so I'm pretty sure one took from the other (not sure which from whom though). In any case, I just made minor alterations so that it works when compiled either under Unicode or Multibyte. I won't post the entire code here unless requested because I think it's a waste of space, but here is the important part.
#include "Injector.h"
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <conio.h>
#include <stdio.h>
#include "DebugPrint.h"
#include <atlbase.h>
using namespace std;
Injector::Injector(void)
{
}
Injector::~Injector(void)
{
}
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
bool Injector::Inject(string procName, string dllName){
DWORD pID = GetTargetThreadIDFromProcName(procName.c_str());
return Inject(pID,dllName);
}
bool Injector::Inject(DWORD pID, string dllName){
const char* DLL_NAME = dllName.c_str();
HANDLE Proc = 0;
HMODULE hLib = 0;
LPVOID RemoteString, LoadLibAddy;
if(!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if(!Proc)
{
DEBUG_PRINT("OpenProcess() failed: %d", GetLastError());
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
// Allocate space in the process for our <strong class="highlight">DLL</strong>
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our <strong class="highlight">DLL</strong> in the memory allocated
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
// Load our <strong class="highlight">DLL</strong>
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
CloseHandle(Proc);
return true;
}
DWORD Injector::GetTargetThreadIDFromProcName(const char* ProcName)
{
PROCESSENTRY32 pe;
HANDLE thSnapShot;
BOOL retval, ProcFound = false;
thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapShot == INVALID_HANDLE_VALUE)
{
//MessageBox(NULL, "Error: Unable to create toolhelp snapshot!", "2MLoader", MB_OK);
DEBUG_PRINT("Error: Unable to create toolhelp snapshot!");
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapShot, &pe);
while(retval)
{
#ifdef _UNICODE
char peSzExeFile[MAX_PATH];
wcstombs_s(NULL,peSzExeFile,MAX_PATH,pe.szExeFile,MAX_PATH);
#else
const char* peSzExeFile = pe.szExeFile;
#endif
DEBUG_PRINT("\nSearching for process: %s ",peSzExeFile);
if(!strcmp(peSzExeFile, ProcName))
{
DEBUG_PRINT(" Found!\n\n");
return pe.th32ProcessID;
}
retval = Process32Next(thSnapShot, &pe);
}
return 0;
}
Finally, my test program just calls some file APIs to see if the injected DLL can catch them. As mentioned before, it does catch the calls quite successfully.
#include <windows.h>
#include <tchar.h>
using namespace std;
#ifdef _UNICODE
#define printf(X,...) wprintf(TEXT(X),__VA_ARGS__); //I don't want to have to keep replacing printf whenever I switch to Unicode or Multibyte
#endif
#ifdef _DEBUG
int _tmain(int argc, TCHAR* argv[]){ //makes a console. printf() will have a place to go in this case
#else
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ //no console
#endif
Sleep(2000); //let DLL finish loading
LPCTSTR fileSrc = TEXT("C:\\Users\\jajoach\\Desktop\\hi.txt");
LPCTSTR fileDst = TEXT("C:\\Users\\jajoach\\Desktop\\hi\\hi.txt");
printf("Moving file from %s to %s\n",fileSrc,fileDst);
MoveFile(fileSrc,fileDst);
Sleep(1000);
printf("Moving file from %s to %s\n",fileSrc,fileDst);
MoveFile(fileDst,fileSrc);
Sleep(1000);
printf("Copying file from %s to %s\n",fileSrc,fileDst);
CopyFile(fileSrc,fileDst,true);
Sleep(1000);
printf("Deleting file %s\n",fileDst);
DeleteFile(fileDst);
Sleep(1000);
printf("Creating file %s\n",fileDst);
HANDLE h=CreateFile(fileDst,0,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
Sleep(1000);
printf("Deleting file %s\n",fileDst);
CloseHandle(h);
DeleteFile(fileDst);
Sleep(5000);
return 0;
}
Here is the confirmed output for Unicode (as noted by the 'W's) and Release mode, and what I was expecting (but didn't get) from both notepad.exe and explorer.exe. For the record, the test also works for Multibyte, but instead gives 'A's as expected.
I had thought that maybe explorer.exe and notepad.exe don't use these API for their file I/O, but my research says otherwise. This post hooks CreateFile in notepad.exe using Detours and reports success for that application. Additionally, ProgramMonitor clearly shows notepad.exe calling CreateFile during a Saveas operation (after many failed requests with different parameters...):
Nevermind about explorer.exe for now; why isn't my hook working for notepad.exe when I do Saveas?
EDIT: I forgot to mention that I also hook MoveFile(A/W) and CopyFile(A/W) with the test program, but I removed that code from the DLL on this post for brevity.
As noted in the comments of the OP, it seems that that notepad.exe uses ASLR and your test program does not. With that the address of LoadLibraryA would be different in each process, and your injection code fails.
The situation is that you are getting the addres of LoadLibraryA in the injector address space and assume that it is the same that in the target process. That would be usually right, but ASLR is designed specifically to make that assumption fail. And so it does... the thread you create get a -most likely- invalid address, and fails.
A couple of reasons:
Bitness of your hook code must match the target.
CreateFileA/W is quite low, but not low enough to catch em all!
To solve 2. you must hook Zw/NtCreateFile from Ntdll.dll which is what you're seeing in procmon. There is nothing lower than these API's in user land.

EnumResourceNames Function C++

So I try to read resource types and names from given file (in my case, .msstyle on my desktop) using C++
But somehow the resinfo result is sort of weird and not accurate. It doesnt write what actually was found. For example, the msstyle gives a result of: http://pastebin.com/ZhnkPmUe
#include <windows.h>
#include <strsafe.h>
#include <stdio.h>
HANDLE g_hFile;
BOOL EnumTypesFunc(HMODULE hModule, LPTSTR lpType, LONG lParam);
BOOL EnumNamesFunc(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG lParam);
BOOL EnumLangsFunc(HMODULE hModule, LPCTSTR lpType, LPCTSTR lpName, WORD wLang, LONG lParam);
void main(void)
{
HMODULE hExe;
TCHAR szBuffer[80];
DWORD cbWritten;
size_t cbString;
HRESULT hResult;
// Load the .EXE whose resources you want to list.
hExe = LoadLibrary(TEXT("C:\\Users\\Kala\\Desktop\\776.msstyles"));
g_hFile = CreateFile(TEXT("C:\\Users\\Kala\\Desktop\\resinfo.txt"), GENERIC_READ | GENERIC_WRITE, 0, (LPSECURITY_ATTRIBUTES) NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
// Find all of the loaded file's resources.
hResult = StringCchPrintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR),TEXT("The file contains the following resources:\r\n\r\n"));
hResult = StringCchLength(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), &cbString);
WriteFile(g_hFile, szBuffer, (DWORD) cbString, &cbWritten, NULL);
//Calls the function to find types
EnumResourceTypes(hExe, (ENUMRESTYPEPROC)EnumTypesFunc, 0);
// Unload the executable file whose resources were
FreeLibrary(hExe);
CloseHandle(g_hFile);
}
// FUNCTION: EnumTypesFunc(HANDLE, LPSTR, LONG)
//
// PURPOSE: Resource type callback
BOOL EnumTypesFunc(HMODULE hModule, LPTSTR lpType, LONG lParam)
{
TCHAR szBuffer[80]; // print buffer for info file
DWORD cbWritten; // number of bytes written to resource info file
size_t cbString;
HRESULT hResult;
// Write the resource type to a resource information file.
// The type may be a string or an unsigned decimal
// integer, so test before printing.
if (!IS_INTRESOURCE(lpType))
{
hResult = StringCchPrintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), TEXT("Type: %s\r\n"), lpType);
}
else
{
hResult = StringCchPrintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), TEXT("Type: %u\r\n"), (USHORT)lpType);
}
hResult = StringCchLength(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), &cbString);
WriteFile(g_hFile, szBuffer, (DWORD) cbString, &cbWritten, NULL);
// Find the names of all resources of type lpType.
EnumResourceNames(hModule, lpType, (ENUMRESNAMEPROC)EnumNamesFunc, 0);
return TRUE;
}
// FUNCTION: EnumNamesFunc(HANDLE, LPSTR, LPSTR, LONG)
//
// PURPOSE: Resource name callback
BOOL EnumNamesFunc(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG lParam)
{
TCHAR szBuffer[80]; // print buffer for info file
DWORD cbWritten; // number of bytes written to resource info file
size_t cbString;
HRESULT hResult;
// Write the resource name to a resource information file.
// The name may be a string or an unsigned decimal
// integer, so test before printing.
if (!IS_INTRESOURCE(lpName))
{
hResult = StringCchPrintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), TEXT("\tName: %s\r\n"), lpName);
}
else
{
hResult = StringCchPrintf(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), TEXT("\tName: %u\r\n"), (USHORT)lpName);
}
hResult = StringCchLength(szBuffer, sizeof(szBuffer)/sizeof(TCHAR), &cbString);
WriteFile(g_hFile, szBuffer, (DWORD) cbString, &cbWritten, NULL);
return TRUE;
}
I think I must be missing something because I dont seem to get a proper strings I wanted from it, so if anyone could point me to right direction I would be very thankful
Your file is UTF-16 encoded because you are using the Unicode version of the Win32 API. Your text editor is interpreting the file as being 8 bit encoded. So you simply need to get your text editor to interpret the file as UTF-16. Probably the easiest way to do that is to put the UTF-16LE BOM at the beginning of the file.
As an aside I would advise you to stop coding to support MBCS character sets, stop using TCHAR and so on. Just write your program assuming that you will be targeting the Unicode version of the Win32 API. It will make your code much easier to read if you write L"..." rather than TEXT("...") and so on. Of course, if you need to support Windows 9x then forget I said this and carry on writing code that will compile in both MBCS and Unicode modes.

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;
}

Extract file from resource in Windows module

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);

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?