Process creation and monitoring

Hi,

In the code below I have created a process and want to monitor that process whether the created process get closed or not.

If I have a single document type application(for example MS notepad.exe) then in that case a new application get created every time when I create a new process and I do get the notification at the instance it get closed.

But If I have a multiple document based application then in that case if I create a process for the first time then a single application is present and when i close the application then in that case I get the notification.
But suppose if the application is already open with some tab then when i create and open a file using this program the WaitForSingleObject function return immediately just after it creation,though the application with the created tab is still open and active.

How can I handle this case?
It will be nice and useful if someone let me know how a process is maintained in second case(Multiple document based).

Thanks


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <windows.h>

int main(int argc, char *argv[])
{
	STARTUPINFO				si					= {0};
	PROCESS_INFORMATION		piProcessB;
	PROCESS_INFORMATION		piProcessC;
	SECURITY_ATTRIBUTES		saProcess;
	SECURITY_ATTRIBUTES		saThread;
	TCHAR					szPath[MAX_PATH]	= {0};

	/** 
	* At minimum initialize all member of startupinfo structure to zero and cb 
	* to the size of this structure.
	**/
	si.cb = sizeof(si);

	/**
	* The Handle identifying the new process object should not be inheritable.
	**/
	saProcess.nLength				= sizeof(saProcess);
	saProcess.lpSecurityDescriptor	= NULL;
	saProcess.bInheritHandle		= TRUE;

	/**
	* The handle identifying the new thread object shoul not be inheritable. 
	**/
	saThread.nLength				= sizeof(saThread);
	saThread.lpSecurityDescriptor	= NULL;
	saThread.bInheritHandle			= FALSE;

	lstrcpy(szPath, TEXT("\"C:\\Program Files\\Notepad++\\notepad++.exe\""));
	lstrcat(szPath, TEXT("\"C:\\Documents and Settings\\vivek.kumar\\Desktop\\CP1.txt\""));
	BOOL result = CreateProcess(NULL, szPath, &saProcess, &saThread, FALSE, 0, NULL, NULL, &si, &piProcessC);
	
	/* Displaying CreateProcess() function result. */
	std::cout << "Result    : " << result				  << std::endl;
	std::cout << "processID : " << piProcessC.dwProcessId << std::endl;
	std::cout << "ThreadID  : " << piProcessC.dwThreadId  << std::endl;

	/**
	* Wiat for the created process to terminalte
	**/
	WaitForSingleObject(piProcessC.hProcess, INFINITE);
	std::cout << "\n\nProcces Exited\n\n";

	getchar();
	return 0;
}
closed account (DSLq5Di1)
Likely, the process you create via CreateProcess() detects an already open instance, passes the command line arguments to that instance and brings it to the foreground, then terminates.

If the process is already running, use the handle from OpenProcess(). http://msdn.microsoft.com/en-us/library/windows/desktop/ms684320
Thanks sloppy9 for your explanation how the process passes argument to opened application!

I have modified the code, but still not getting any effect. I mean that the wait is not functioning as expected.

1
2
3
4
5
6
7
8
        BOOL result = CreateProcess(NULL, szPath, &saProcess, &saThread, FALSE, 0, NULL, NULL, &si, &piProcessC);
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, piProcessC.dwThreadId);
	/**
	* Wiat for the created process to terminalte
	**/
	WaitForSingleObject(hProcess, INFINITE);
	std::cout << "\n\nProcces Exited\n\n";


closed account (DSLq5Di1)
Well, now you are opening another handle to the process you've created, though events will still play out the same way.. with that process activating an already existing instance and terminating itself.

The easiest approach,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HWND hWindow = FindWindow(TEXT("Notepad++"), NULL);

if (hWindow != NULL) // Notepad++ is already running
{
    DWORD ProcessId, ThreadId;
    ThreadId = GetWindowThreadProcessId(hWindow, &ProcessId);

    HANDLE hProcess = OpenProcess(SYNCHRONIZE, TRUE, ProcessId);
    // ...

    WaitForSingleObject(hProcess, INFINITE);
}
else
{
    /* CreateProcess */
}

Alternatively, see these examples for process enumeration:-
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686701
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682623
Thanks again!

This will let me get the handle to open application(notepad++.exe) if it's already opened, but I need to open a new file in it and to see when this new file opened by the application gets closed.
In-fact I need to know when this application is closing this file?
closed account (DSLq5Di1)
In-fact I need to know when this application is closing this file?

That complicates things a great deal! You could enumerate child windows and poll them (ugly solution), but I recommend you look into windows hooking, see:-
http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990

I've created a naive example using SetWinEventHook() you can play around with,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <windows.h>
#include <process.h>

#include <oleacc.h>
#pragma comment (lib, "oleacc.lib")

#include <cstdio>

void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
	IAccessible* pAcc = NULL;
	VARIANT varChild;

	HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &varChild);  

	if ((hr == S_OK) && (pAcc != NULL))
	{
		VARIANT varResult = {};
		pAcc->get_accRole(varChild, &varResult);

		if (varResult.lVal == ROLE_SYSTEM_PAGETAB || varResult.lVal == NULL)
		{
			BSTR bstrName;
			pAcc->get_accName(varChild, &bstrName);

			if (event == EVENT_OBJECT_CREATE) 
			{
				printf("Create: ");
			}
			else if (event == EVENT_OBJECT_DESTROY)
			{
				printf("Destroy:   ");
			}
			printf("%S\n", bstrName);
			SysFreeString(bstrName);
		}
		pAcc->Release();
	}
}

unsigned __stdcall hook(void* args)
{
	HWND hWindow = FindWindow(TEXT("Notepad++"), NULL);

	if (hWindow != NULL)
	{
		DWORD ProcessId, ThreadId;
		ThreadId = GetWindowThreadProcessId(hWindow, &ProcessId);

		CoInitialize(NULL);
		HWINEVENTHOOK hHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, NULL, HandleWinEvent, ProcessId, ThreadId, WINEVENT_OUTOFCONTEXT);

		MSG msg;
		while (GetMessage(&msg, NULL, 0, 0) > 0);
		
		UnhookWinEvent(hHook);
		CoUninitialize();
	}
	return 0;
}

int main()
{
	unsigned ThreadId;
	HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, hook, NULL, 0, &ThreadId);

	for (;; Sleep(100))
	{
		if (GetAsyncKeyState(VK_END) & 0x8000) // Press End to exit
		{
			PostThreadMessage(ThreadId, WM_QUIT, 0, 0);
			WaitForSingleObject(hThread, 3000);
			break;
		}
	}
	CloseHandle(hThread);
	return 0;
}

Run Notepad++ first, then the program above, create some new tabs in Notepad++ and you'll see the tab names output to the console.

Note: The destroy event is less reliable, properties (name, role, etc) are NULL, you may want to create a map of child ids and their names from EVENT_OBJECT_CREATE, then whenever you receive a destroy event, check the map for the id and handle appropriately.
Last edited on
Thanks a ton!

I have build this code and understood a bit about the logic.
Topic archived. No new replies allowed.