This is beginner post related to using Job objects in windows. If you’re a core native programmer, you might have a chance to deal with Job objects. One of the best realworld application managing with job objects are Visual Studio itself. The IDE compiles and links your source code by using “CL.exe” compiler and “Link.exe”.The IDE has sole control over the behavior and life time of the processes it deals with. How we can do that? To help with such scenarios, Windows supports Jobs objects. It allows grouping the application and restricting its behavior in various conditions. Read more about Job objects from MSDN. Another best example is Google Chrome Browser which manages its tabs as process. If you check with Process Explorer, you can see the chrome tabs as process and from its properties; you will get the information about the job.
What are the basic steps for dealing with Job objects?
- You’ve to create the Job object using CreateJobObject API.
- Define the behavior of the job
- Create or open the process you need to group.
- Assign the process to job, using “Job Objects”
- Manage the notifications of from the assigned processes or jobs
Creating Job Object
You can create a new job object as follows.
[sourcecode language='cpp']
m_hJob = CreateJobObject( NULL, _T(“NotepadJobs”)); // Create Job object
if ( !m_hJob)
{
MessageBox( _T(“Failed to create Job Object”),_T(“Job Error”),MB_OK|MB_ICONERROR);
return;
}
JOBOBJECT_BASIC_LIMIT_INFORMATION bli = { 0 };
bli.PriorityClass = HIGH_PRIORITY_CLASS;
bli.PerJobUserTimeLimit.QuadPart = 1000;
SetInformationJobObject( m_hJob, JobObjectBasicLimitInformation, &bli, sizeof(bli));
[/sourcecode]
The next you can provide as many supported restrictions to your job. Get a complete list of the restrictions and its usage from MSDN.
Create new process and assign to job object
You can simply using create process to create the new process and get it’s handle to attach with the job object.
[sourcecode language='cpp']
STARTUPINFO st = { sizeof(st) };
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
TCHAR buff[] = _T(“C:\\Windows\\Notepad.exe”);
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
buff, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent’s environment block
NULL, // Use parent’s starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
return;
}
[/sourcecode]
The above code creates a notepad application. You can create your own application to attach with job object. The next thing you need to do is, assign the process to job object. Using AssignProcessToJobObject
[sourcecode language='cpp']
// Close process and thread handles.
AssignProcessToJobObject( m_hJob, pi.hProcess );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
[/sourcecode]
Now your process will be appeared on the screen. Now you want to track the main activities like, adding a new process, exiting new process etc.. of your job object.
Add thread to monitor the notifications from the Jobs
After initializing simply create a thread to monitor the activities of your job object.
First you have to create a new thread for monitoring purpose using CreateThread API as follows.
CreateThread( 0, 0, ThreadFxn,m_hJob,0,0);
To implement the Job notifications, first we’ve to create an IO completion port for detecting changes. Since IO completion port not coming in the scope of this article, I’m planning it for some other time.
You can use CreateIoCompletionPort API to implement an IO completion port
[sourcecode language='cpp']
HANDLE hiocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,1,0 );
[/sourcecode]
Set the newly created IO completion port to the job object
[sourcecode language='cpp']
// Set the IO completion port handle to the job for notifications
JOBOBJECT_ASSOCIATE_COMPLETION_PORT
iop;
iop.CompletionKey = (PVOID)1;
iop.CompletionPort = hiocp;
SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation,
&iop,sizeof(iop));
[/sourcecode]
Wait for IO completion Port
[sourcecode language='cpp']
while( WAIT_OBJECT_0 == WaitForSingleObject(hiocp,INFINITE))
[/sourcecode]
Once the IOCP signaled, then get the status using GetQueuedCompletionStatus API
[sourcecode language='cpp']
if(GetQueuedCompletionStatus( hiocp,&dwBytes,&completionkey,&ove,INFINITE))
[/sourcecode]
Check which was the message of interest
[sourcecode language='cpp']
if (dwBytes == JOB_OBJECT_MSG_NEW_PROCESS)
AfxMessageBox( _T( “New process”));
else if( dwBytes == JOB_OBJECT_MSG_EXIT_PROCESS)
AfxMessageBox( _T( “Exit process”));
else if(dwBytes == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
AfxMessageBox(_T( “No further processes”));
[/sourcecode]
You can get the complete list of options from MSDN. The LPOVERLAPPED parameter will be holding data according to the message got signaled.
The entire monitor thread function may appear as follows
[sourcecode language='cpp']
DWORD WINAPI ThreadFxn(LPVOID lpVoid)
{
// Get the pointer to job object
HANDLE hJob = (HANDLE)lpVoid;
// Create IO completion port (no files are attached)
HANDLE hiocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,1,0 );
// Set the IO completion port handle to the job for notifications
JOBOBJECT_ASSOCIATE_COMPLETION_PORT iop;
iop.CompletionKey = (PVOID)1;
iop.CompletionPort = hiocp;
SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation,
&iop,sizeof(iop));
// Wait for events
while( WAIT_OBJECT_0 == WaitForSingleObject(hiocp,INFINITE))
{
DWORD dwBytes;
ULONG_PTR completionkey;
LPOVERLAPPED ove;
if(GetQueuedCompletionStatus( hiocp,&dwBytes,&completionkey,&ove,INFINITE))
{
if (dwBytes == JOB_OBJECT_MSG_NEW_PROCESS) // Check *ove for additional information with the notification
{
AfxMessageBox( _T( “New process”));
}
else if( dwBytes == JOB_OBJECT_MSG_EXIT_PROCESS)
{
AfxMessageBox( _T( “Exit process”));
}
else if(dwBytes == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
{
AfxMessageBox(_T( “No further processes”));
}
}
else
{
AfxMessageBox( _T(“Failed”));
}
}
return 0;
}
[/sourcecode]
This is the simple way to manage the Job objects with notification. If you want to give further inputs, give feedback through comments.

