When i use CloseHandle(); why is Event still visible/running - c++

I believe that calling CloseHandle() only closes the reference made to the handle? But the Event is still visible in Process Explorer, and the desired functionality isn't met.
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (stricmp(entry.szExeFile, "program.exe") == 0)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
HANDLE hEvent = OpenEventA(EVENT_ALL_ACCESS,FALSE,"openEvent");
// Do stuff..
int sucess = CloseHandle(hEvent);
}
}
count = 0;
}
CloseHandle(snapshot);
Is there something I'm doing wrong? Why would the Event still be visible in Process Explorer?

Kernel objects are reference counted. Calling CloseHandle decrements the reference count, but the referenced object doesn't get removed, until the final handle to it gets closed.
In the code for OpenEventA to return a non-NULL value, the event referenced by name must already exist (i.e. its reference count must be at least 1). OpenEventA increments the reference count, and CloseHandle decrements it, but it's still at least 1 (unless the other handles to that event object have been closed).
Consequently the event object doesn't get closed, and Process Explorer rightfully reports that the event object still exists.

Related

I want to write a kernel driver program where when a file is created I need to be notified

I used the reference of this project where it creates a handler for IRP_MJ_CREATE. which displays all the files which are created or opened the system.
The documentation of IRP_MJ_CREATE is this:
The I/O Manager sends an IRP_MJ_CREATE request when a new file or
directory is being created, or when an existing file, device,
directory, or volume is being opened.
Normally this IRP is sent on behalf of a user-mode application that
has called a Microsoft Win32 function such as CreateFile or on behalf
of a kernel-mode component that has called a function such as
IoCreateFile, IoCreateFileSpecifyDeviceObjectHint, ZwCreateFile, or
ZwOpenFile.
If the create request is completed successfully, the application or
kernel-mode component receives a handle to the file object.
This program below prints all the files or volumes which are opened, created.
main.c
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
{
DriverObject->MajorFunction[i] = FsFilterDispatchPassThrough;
}
//creating handle for IRP_MJ_CREATE.
DriverObject->MajorFunction[IRP_MJ_CREATE] = FsFilterDispatchCreate;
// IRP_MJ_CREATE IRP Handler
NTSTATUS FsFilterDispatchCreate(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp
)
{
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
DbgPrint("%wZ\n", &pFileObject->FileName);
return FsFilterDispatchPassThrough(DeviceObject, Irp);
}
I just need the driver to print only when a file or directory is created.
Your filter driver is being called before the actual file system driver. However you want to check the result after the file system driver handled the irp. according to this article, you can simply check irp->IoStatus.Information == FILE_CREATED.
Now you only need to let the file system driver know that you have more processing to do with the irp, so it won't call IoCompleteRequest and free the irp. To do so we can use scenario 2 out of the Cheat Sheet. It will end up something like this:
NTSTATUS
CompletionRoutine_2(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
if (Irp->PendingReturned == TRUE) {
//
// You will set the event only if the lower driver has returned
// STATUS_PENDING earlier. This optimization removes the need to
// call KeSetEvent unnecessarily and improves performance because the
// system does not have to acquire an internal lock.
//
KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
}
// This is the only status you can return.
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
FsFilterDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KEVENT event;
NTSTATUS status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// You are setting completion routine, so you must copy
// current stack location to the next. You cannot skip a location
// here.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
CompletionRoutine_2,
&event,
TRUE,
TRUE,
TRUE
);
PFSFILTER_DEVICE_EXTENSION pDevExt = (PFSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
status = IoCallDriver(pDevExt->AttachedToDeviceObject, Irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event,
Executive, // WaitReason
KernelMode, // must be Kernelmode to prevent the stack getting paged out
FALSE,
NULL // indefinite wait
);
status = Irp->IoStatus.Status;
}
// Your logic
if (Irp->IoStatus.Information == FILE_CREATED) {
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
DbgPrint("%wZ\n", &pFileObject->FileName);
}
//
// Because you stopped the completion of the IRP in the CompletionRoutine
// by returning STATUS_MORE_PROCESSING_REQUIRED, you must call
// IoCompleteRequest here.
//
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
When using the example you based on, you can simply change the function to this.

Why can't I reuse an event even after explicit ResetEvent call?

I want to watch for changes done with a file (the event i'm waiting for is change contents event, i.e. last modified date is updated)
I have a code like this (minimalized example of actual code)
I expect that each iteration of the while loop the event gets reset and is available to be fired again but that doesn't happen
Why it fires change event only once?
int main()
{
const wchar_t *dir_path = L"C:\\Users\\IC\\AppData\\Roaming\\JetBrains\\CLion2021.3\\scratches\\";
HANDLE hDir = ::CreateFileW(
dir_path,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL
);
FILE_NOTIFY_INFORMATION fni;
OVERLAPPED overlapped;
overlapped.hEvent = ::CreateEventA(NULL, FALSE, FALSE, NULL);
::ReadDirectoryChangesW(
hDir,
&fni,
sizeof(fni),
TRUE,
FILE_NOTIFY_CHANGE_LAST_WRITE,
NULL,
&overlapped,
NULL
);
while (true)
{
std::vector<HANDLE> all_job_event_handles;
if (::ResetEvent(overlapped.hEvent) == FALSE)
{
printf("ResetEvent failed\n");
fflush(stdout);
return 1;
}
all_job_event_handles.push_back(overlapped.hEvent);
DWORD result = ::WaitForMultipleObjects(all_job_event_handles.size(), all_job_event_handles.data(), FALSE, INFINITE);
if (result == WAIT_FAILED)
{
printf("WaitForMultipleObjects failed\n");
fflush(stdout);
return 1;
}
if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + all_job_event_handles.size())
{
printf("file changed\n");
fflush(stdout);
}
}
}
Because that's just not how ReadDirectoryChanges works. It doesn't continuously send you changes. It sends you one batch of changes. You process them. You call the function again to tell the system that you want more changes.
I found a correct usage example of the function here: https://gist.github.com/nickav/a57009d4fcc3b527ed0f5c9cf30618f8
Some side notes:
You don't check whether ReadDirectoryChanges succeeds. This is bad; if it failed, you will hang on the Wait call forever.
You don't zero-initialize the OVERLAPPED structure.
You create the event as an auto-reset event (second parameter is FALSE). ResetEvent on such an event does nothing.
All the event handles you add into your vector are the same event object. You just have an ever-growing list of the same event repeatedly that you pass to WaitForMultipleObjects. This does nothing at best, but will eventually fail because WFMO doesn't allow more than MAXIMUM_WAIT_OBJECTS handles, and this number is fairly low (32, I think).
You probably want a more permissive share mode on the directory you open.

Windows prevent multiple instances code not working

I am using CreateEvent to prevent multiple instances of my application:
CreateEvent(NULL, TRUE, FALSE, "MyEvent");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
However, at startup I have noticed that this doesn't work:
After the desktop is shown I automatically run a batch script that attempts to launch multiple instances of my program. The batch script succeeds and I can indeed see multiple instances.
Investigation so far:
OutputDebug shows that each instance does not get ERROR_ALREADY_EXISTS
ProcessExplorer.exe shows that each instance was able to get a handle to the event "MyEvent".
Can anybody think why this might be happening, and how I could solve it?
We use the function below, which is in our common utility DLL. The method is derived from a Microsoft article explaining how to prevent multiple instances in WIN32.
#define STRICT
#include <stdheaders.h>
HANDLE ghSem;
BOOL IExist( LPSTR lpszWindowClass )
{
HWND hWndMe;
int attempt;
for( attempt=0; attempt<2; attempt++ )
{
// Create or open a named semaphore.
ghSem = CreateSemaphore( NULL, 0, 1, lpszWindowClass );
// Close handle and return NULL if existing semaphore was opened.
if( (ghSem != NULL) &&
(GetLastError() == ERROR_ALREADY_EXISTS) )
{ // Someone has this semaphore open...
CloseHandle( ghSem );
ghSem = NULL;
hWndMe = FindWindow( lpszWindowClass, NULL );
if( hWndMe && IsWindow(hWndMe) )
{ // I found the guy, try to wake him up
if( SetForegroundWindow( hWndMe ) )
{ // Windows says we woke the other guy up
return TRUE;
}
}
Sleep(100); // Maybe the semaphore will go away like the window did...
}
else
{ // If new semaphore was created, return FALSE.
return FALSE;
}
}
// We never got the semaphore, so we must
// behave as if a previous instance exists
return TRUE;
}
Just do something like this in your WinMain:
if( IExist("MyWindowClass") )
{
return 1;
}
Of course, you could replace the return with whatever you need to do when you are not the first instance (such as activating the existing instance).

How can I get which object timed out when using WaitForMultipleObjects?

If I'm using WaitForMultipleObjects, and the function returns WAIT_TIMEOUT, how can I get which object or objects caused the timeout to occur?
Another question I have is if multiple objects are signaled, since the return value only returns the first object that it detects as signaled, how do I get the other objects which are signaled?
#include <windows.h>
#include <stdio.h>
HANDLE ghEvents[2];
DWORD WINAPI ThreadProc( LPVOID );
int main( void )
{
HANDLE hThread;
DWORD i, dwEvent, dwThreadID;
// Create two event objects
for (i = 0; i < 2; i++)
{
ghEvents[i] = CreateEvent(
NULL, // default security attributes
FALSE, // auto-reset event object
FALSE, // initial state is nonsignaled
NULL); // unnamed object
if (ghEvents[i] == NULL)
{
printf("CreateEvent error: %d\n", GetLastError() );
ExitProcess(0);
}
}
// Create a thread
hThread = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc,
NULL, // no thread function arguments
0, // default creation flags
&dwThreadID); // receive thread identifier
if( hThread == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
// Wait for the thread to signal one of the event objects
dwEvent = WaitForMultipleObjects(
2, // number of objects in array
ghEvents, // array of objects
FALSE, // wait for any object
5000); // five-second wait
// The return value indicates which event is signaled
switch (dwEvent)
{
// ghEvents[0] was signaled
case WAIT_OBJECT_0 + 0:
// TODO: Perform tasks required by this event
printf("First event was signaled.\n");
break;
// ghEvents[1] was signaled
case WAIT_OBJECT_0 + 1:
// TODO: Perform tasks required by this event
printf("Second event was signaled.\n");
break;
case WAIT_TIMEOUT:
// How can I get which object timed out?
printf("Wait timed out.\n");
break;
// Return value is invalid.
default:
printf("Wait error: %d\n", GetLastError());
ExitProcess(0);
}
// Close event handles
for (i = 0; i < 2; i++)
CloseHandle(ghEvents[i]);
return 0;
}
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
// lpParam not used in this example
UNREFERENCED_PARAMETER( lpParam);
// Set one event to the signaled state
if ( !SetEvent(ghEvents[0]) )
{
printf("SetEvent failed (%d)\n", GetLastError());
return 1;
}
return 0;
}
When the WaitForMultipleObjects(...) returns with the WAIT_TIMEOUT return code, it indicates that none of your you objects you waited for signaled within the given amount of time.
The function essentially sleeps for the time you specify as timeout and only returns earlier, if one of the waitable objects gets signaled before that time. That means that the WAIT_TIMEOUT return code is not associated with any of the objects you wait for.
Your second question is partialy answered by Eregriths comment. To check if other objects are also signaled, you could call WaitForMultipleObjects(...) again, and depending on your needs, set the timeout value to 0 (do not wait). When WaitForMultipleObjects(...) returns with WAIT_TIMEOUT you know that no other objects were in a signaled state at the time of your call, but you should keep in mind, that the object, that caused your first call to return could potentially be signaled again. So you could either exclude it from your array or simply check a single object for its state with the WaitForSingleObject(...) function.
If you want to make sure all objects are signaled, you can also play with the bWaitAll parameter. WaitForMultipleObjects(...) will then only return if all your objects are in a signaled state.,
Hope that helps a bit.

Preventing multiple instances of my application [duplicate]

This question already has answers here:
How to block running two instances of the same program?
(8 answers)
Closed 6 years ago.
ADDITIONAL INFORMATION
Again i am writing on the above issue (Preventing multiple instances of my application)
the code works for if i start two instances from programe menu/desktop shortcut. but in my envrironment,
one instance is running from Window Service.
another from Desktop shortcut with Same parameter.
Any help how to write the code ?
The most common method is to use a mutex, similar to the following:
int WINAPI WinMain(...)
{
const char szUniqueNamedMutex[] = "com_mycompany_apps_appname";
HANDLE hHandle = CreateMutex( NULL, TRUE, szUniqueNamedMutex );
if( ERROR_ALREADY_EXISTS == GetLastError() )
{
// Program already running somewhere
return(1); // Exit program
}
// Program runs...
// Upon app closing:
ReleaseMutex( hHandle ); // Explicitly release mutex
CloseHandle( hHandle ); // close handle before terminating
return( 1 );
}
You have to make sure that you close properly - a program crash that doesn't remove the mutex could possibly prevent the program from running again, though in theory the OS will clean up any dangling mutexes once the process ends.
Another method commonly used is to search window titles for the program title:
HWND hWnd=::FindWindow(LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
);
If it's null, then the window was not found, therefore the program is not running. You can use this to bring focus to the running app before closing this new instance, so the user isn't left wondering why the app didn't open.
if(hWnd != NULL)
{
ShowWindow(hWnd,SW_NORMAL);
// exit this instance
return(1);
}
Here is a simple solution that works most of the time:
CreateEvent(NULL, FALSE, FALSE, "MyEvent");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
Another way:
CreateSemaphore(NULL, TRUE, TRUE, "MySemaphore");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
And another way:
CreateMutex(NULL, TRUE, "MyMutex");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
As, the other answer mentioned, CreateMutex is the most common but it isnt perfect. If you want a really thorough solution and why the above ways are no good, check this link on Codeproject.
TLDR: The only safe and general way to prevent multiple instances of the same process is to use a mutex, since only this is guaranted to not give you a race condition.
Here you have a nice article about the subject. I used it when having to do something similar and the solution is working perfectly: AvoidingMultipleInstances.
You are looking for named mutex (named after argument, if it is what should disallow the app to run in multiple instances).
Also i've seen this solution, without GetLastError():
HANDLE hMutex = CreateMutexA(NULL, FALSE, "my mutex");
DWORD dwMutexWaitResult = WaitForSingleObject(hMutex, 0);
if (dwMutexWaitResult != WAIT_OBJECT_0)
{
MessageBox(HWND_DESKTOP, TEXT("This application is already running"), TEXT("Information"), MB_OK | MB_ICONINFORMATION);
CloseHandle(hMutex);
}