Creating Processes using win32

The CreateProcess() function is a real beast of a function as it takes no less than 10 parameters. Let’s tackle this function by first taking a look at some of the parameters, which are complicated in and of themselves.

The STARTUPINFO structure contains information which is used to control how the process behaves and appears on startup. The STARTUPINFO structure has no less than 18 fields.

The GetStartupInfo() function is used to fetch the contents of the STARTUPINFO structure that was specified when the process was created. It’s only parameter is a pointer to a STARTUPINFO structure.The GetStartupInfo() function does not return a value.

#include <Windows.h>
#include <stdio.h> 

int _tmain(int argc, _TCHAR* argv[])
{
	STARTUPINFO structSInfo;
	structSInfo.cb = sizeof(STARTUPINFO);

	GetStartupInfo(&structSInfo);

	_tprintf(_T("Desktop: %s\n"), structSInfo.lpDesktop);
	_tprintf(_T("Console: %s\n"), structSInfo.lpTitle);

	return 0;
}

The creation flags field dwFlags of the STARTUPINFO structure can take a number of values.

The STARTF_USECOUNTCHARS value specifies that the dwXCountChars and dwYCountChars members contain additional information. These screen buffer width and height values are used to determine the size of the console window.

The STARTF_USEFILLATTRIBUTE value specifies that the dwFillAttribute member contains additional information. The dwFillAttribute member is used to set the console fill attributes.

The STARTF_USEPOSITION value indicates that the dwX and dwY members hold additional information. The dwX and dwY members set the window position.

The STARTF_USESTDHANDLES value causes the process handles to be set to the values specified in the hStdInput, hStdOutput, and hStdError members.

#include <Windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
	//use the value of the STARTUPINFO wShowWindow member
	printf("STARTF_USESHOWWINDOW = %d\n", STARTF_USESHOWWINDOW);
	//use the dwX and dwY STARTUPINFO members
	printf("STARTF_USEPOSITION = %d\n", STARTF_USEPOSITION);
	//use the dwFillAttribute member of STARTUPINFO
	printf("STARTF_USEFILLATTRIBUTE = %d\n", STARTF_USEFILLATTRIBUTE);
	//use the hStdInput, hStdOutput, and hStdError members of STARTUPINFO
	printf("STARTF_USESTDHANDLES = %d\n", STARTF_USESTDHANDLES);

	return 0;
}

The CreateProcess() function itself has a dwFlags parameter,  dwCreationFlags, which should not be confused with the dwFlags field of the STARTUPINFO structure The dwFlags parameter is the sixth parameter of the CreateProcess() function. It is used to specify flags which control the creation of the process, and its priority.

The CREATE_DEFAULT_ERROR_MODE process creation flag indicates that the new process does not inherit the error mode of the calling process. Instead, the new process gets the default error mode.

The CREATE_NEW_CONSOLE process creation flag indicates that the new process has a new console, instead of inheriting the parent’s console, which is the default.

The CREATE_NEW_PROCESS_GROUP process creation flag indicates that the new process is the root process of a new process group. The process group is made up of all processes that are descendants of this process.

The CREATE_SUSPENDED process creation flag indicates that the new process is created in a suspended state, and will not run until the ResumeThread() function is called.

The DETACHED_PROCESS process creation flag indicates that the new process does not inherit its parent’s console, as per the default. Note that this flag cannot be used with the CREATE_NEW_CONSOLE flag.

#include <Windows.h>
#include <stdio.h>

int main(void){
	
	//creates a new console for the process
	printf("CREATE_NEW_CONSOLE %d\n", CREATE_NEW_CONSOLE);
	
	//make the process the root of a new process group
	printf("CREATE_NEW_PROCESS_GROUP %d\n", CREATE_NEW_PROCESS_GROUP);

	//primary thread of new process is created in a suspended state
	printf("CREATE_SUSPENDED %d\n", CREATE_SUSPENDED);

	//prevents the new process from accessing the console
	//belonging to the parent process
	printf("DETACHED_PROCESS %d\n", DETACHED_PROCESS);

	return 0;

}

The dwCreationFlags parameter can also hold priority flags. The four main priority flags are REALTIME_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, and IDLE_PRIORITY_CLASS.

We can find out the process priority for the current process using the GetPriorityClass() function, which takes a single parameter, the HANDLE to the current process. We can acquire a HANDLE to the current process using the GetProcessHandle() function.

#include <Windows.h>
#include <stdio.h>

int main(void){
	
	DWORD dwProcessPriority;

	//GetPriorityClass() 
	//returns 0 if it fails
	dwProcessPriority = GetPriorityClass(GetCurrentProcess());

	if(dwProcessPriority > 0){
		if(dwProcessPriority & REALTIME_PRIORITY_CLASS){
			printf("Highest priority process.\n");
		}
		if(dwProcessPriority & HIGH_PRIORITY_CLASS){
			printf("High priority process.\n");
		}
		if(dwProcessPriority & NORMAL_PRIORITY_CLASS){
			printf("Normal priority process.\n");
		}
		if(dwProcessPriority & IDLE_PRIORITY_CLASS){
			printf("Background process.\n");
		}
	}

	return 0;

}

We can change the priority for a process using the SetPriorityClass() function. The SetPriorityClass() function takes two parameters, the first being a HANDLE to the process, and the second being a DWORD value indicating the desired priority.

#include <windows.h>
#include <stdio.h>

int main(void){
	
	HANDLE hCurrentProc = GetCurrentProcess();

	if(SetPriorityClass(hCurrentProc, REALTIME_PRIORITY_CLASS)){
		printf("Process set to realtime priority.\n");
	} else {
		printf("Process not set to realtime priority.\n");
	}

	if(SetPriorityClass(hCurrentProc, HIGH_PRIORITY_CLASS)){
		printf("Process set to high priority.\n");
 	} else {
		printf("Process not set to high priority.\n");
	}

	return 0;

}

The win32 PROCESS_INFORMATION structure contains information about a newly created process and its primary thread. It has four members. The first member is a HANDLE to the newly created process. The second member is a HANDLE to the primary thread of the newly created process. Both of these handles need to be closed when we are through with them.

We will pass the PROCESS_INFORMATION structure to the CreateProcess() function by reference, which is to say via pointer.

#include <windows.h>
#include <stdio.h>

int main(void){
	
	STARTUPINFO structSI;
	PROCESS_INFORMATION structPI;
	BOOL bRetVal;

	//get startup info for current process
	GetStartupInfo(&structSI);

	//create child process
	bRetVal = CreateProcess(
		0, //executable module name
		"notepad.exe", //command line
		0, //process security attributes
		0, //thread security attributes
		FALSE, //inheritance flag
		CREATE_NEW_CONSOLE, //creation flags
		NULL, //pointer to environment block
		NULL, //current directory name
		&structSI, //pointer to startup info struct
		&structPI //pointer to process info struct
		);

	if(bRetVal==FALSE){
		printf("Error creating new process.\n");
		exit(EXIT_FAILURE);
	} else {
		printf("Process created.\n");
	}

	//close handles to new process
	CloseHandle(structPI.hProcess);
	CloseHandle(structPI.hThread);


	return 0;

}

Leave a comment