The Windows Processes and Threads 10

 

 

 

 

 

Creating Processes (With Code Example)

 

The CreateProcess() function creates a new process, which runs independently of the creating process. However, for simplicity, the relationship is referred to as a parent-child relationship. The following code example demonstrates how to create a process.

Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.

Then, add the source file and give it a suitable name.

Next, add the following source code.

 

#include <windows.h>

#include <stdio.h>

#include <strsafe.h>

#include <wchar.h>

 

// Prototype

void ErrorHandler(LPTSTR lpszFunction);

 

// This wmain() is the main or parent process

int wmain(int argc, WCHAR *argv[])

{

    STARTUPINFO si;

    PROCESS_INFORMATION pi;

    DWORD Ret = 0, dwPID = 0, dwTID = 0, dwPver = 0;

 

    ZeroMemory(&si, sizeof(si));

    si.cb = sizeof(si);

    ZeroMemory(&pi, sizeof(pi));

 

    // Validate the argument

    if(argc != 2)

    {

        wprintf(L"Usage: %s [cmdline]\n", argv[0]);

        return 1;

    }

 

      // Get parent process and...

      dwPID = GetCurrentProcessId();

      wprintf(L"wmain() process ID is %u\n", dwPID);

      // What about the current thread?

      dwTID = GetCurrentThreadId();

      wprintf(L"wmain() thread ID is %u\n", dwTID);

      // More info...

      wprintf(L"Command line: %s\n", GetCommandLine());

      // Other info

      dwPver = GetProcessVersion(dwPID);

      // or dwPver = GetProcessVersion(0);

      wprintf(L"Process version: %u\n", dwPver);

 

    // Start the child process

    wprintf(L"Starting another process i.e. child process...\n");

    if(!CreateProcess(NULL,   // No module name (so use command line - [cmdline])

        argv[1],        // 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

    )

    {

        ErrorHandler(L"CreateProcess()");

        return 1;

    }

      else

      {

            wprintf(L"CreateProcess() - child process was created successfully!\n");

            wprintf(L"Process ID is %u or %u\n", pi.dwProcessId, GetProcessId(pi.hProcess));

            wprintf(L"Thread ID is %u\n", pi.dwThreadId);

            // Minimum is Vista, Windows 2003 for the following code

            // wprintf(L" Thread ID is %u\n", GetThreadId(pi.hThread));

      }

 

    // Wait until child process exits.

    wprintf(L"Waiting the child process exits...\n");

    // The time-out interval, in milliseconds. If a nonzero value is specified,

    // the function waits until the object is signaled or the interval elapses.

    // If dwMilliseconds is zero, the function does not enter a wait state if

    // the object is not signaled; it always returns immediately. If dwMilliseconds is INFINITE,

    // the function will return only when the object is signaled.

    Ret = WaitForSingleObject( pi.hProcess, INFINITE );

    // WAIT_ABANDONED - 0x00000080L, WAIT_OBJECT_0 - 0x00000000L,

    // WAIT_TIMEOUT - 0x00000102L, WAIT_FAILED - (DWORD)0xFFFFFFFF

    wprintf(L"The WaitForSingleObject() return value is 0X%.8X\n", Ret);

 

    // Close process and thread handles

    wprintf(L"Closing the process and thread handles...\n");

    if(CloseHandle(pi.hProcess) != 0)

            wprintf(L"pi.hProcess handle was closed successfully!\n");

      else

            ErrorHandler(L"CloseHandle(pi.hProcess)");

    if(CloseHandle(pi.hThread) != 0)

            wprintf(L"pi.hThread handle was closed successfully!\n");

      else

            ErrorHandler(L"CloseHandle(pi.hThread)");

 

      return 0;

}

 

// This just redundant, you can use the GetLastError() instead

void ErrorHandler(LPTSTR lpszFunction)

{

    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;

    LPVOID lpDisplayBuf;

    DWORD dw = GetLastError();

 

    FormatMessage(

        FORMAT_MESSAGE_ALLOCATE_BUFFER |

        FORMAT_MESSAGE_FROM_SYSTEM |

        FORMAT_MESSAGE_IGNORE_INSERTS,

        NULL,

        dw,

        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

        (LPTSTR) &lpMsgBuf,

        0, NULL );

 

    // Display the error message

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(WCHAR));

    StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(WCHAR), L"%s failed with error %u: %s", lpszFunction, dw, lpMsgBuf);

    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, L"Error", MB_OK);

 

    // Free error-handling buffer allocations

    if(LocalFree(lpMsgBuf) == NULL)

            wprintf(L"lpMsgBuf buffer freed!\n");

      else

            wprintf(L"Failed to free lpMsgBuf buffer, error %u\n", GetLastError());

 

    if(LocalFree(lpDisplayBuf) == NULL)

            wprintf(L"lpDisplayBuf buffer freed!\n");

      else

            wprintf(L"Failed to free lpDisplayBuf buffer, error %u\n", GetLastError());

}

 

Build and run the project. The following screenshot is a sample output when we use the calc (calculator) as the argument. The Windows calculator program should be launched.

 

Creating processes code example: A sample console program output in action

 

The following is the Windows calculator.

 

A sample console program output in action: launching or spawning the calc.exe process

 

When we see through Windows Task Manager, we can see both processes and their threads respectively.

 

A sample thread and process in action seen from Windows Task Manager

 

When we close the calc program, the following screenshot shows the complete output.

 

Creating processes code example: Spawning new process (thread)

 

If CreateProcess() succeeds, it returns a PROCESS_INFORMATION structure containing handles and identifiers for the new process and its primary thread. The thread and process handles are created with full access rights, although access can be restricted if you specify security descriptors. When you no longer need these handles, close them by using the CloseHandle() function. You can also create a process using the CreateProcessAsUser() or CreateProcessWithLogonW() function. This allows you to specify the security context of the user account in which the process will execute.

 

 

 

< Processes & Threads 9 | Win32 Process & Thread Programming | Win32 Programming | Processes & Threads 11 >