|< Windows Process & Threads Programming 5 | Main | Windows Process & Threads Programming 7 >| Site Index | Download |


 

 

 

 

MODULE U

PROCESSES AND THREADS: Win32/WINDOWS APIs

Part 6: Program Examples

 

 

 

 

 

 

 

 

 

 

 

 

What do we have in this session?

 

  1. Creating Processes Example.

  2. Creating Threads Example.

  3. Enumerating All Processes Example

 

My Training Period: yy hours. Before you begin, read some instruction here.

 

The expected abilities:

  • Able to understand and use various processes and threads functions (Windows APIs/Win32).

  • Able to build and run your own simple processes and threads programs.

  • Able to understand, build and run your own simple multithreading programs.

  • Able to extract, understand and use functions information from MSDN documentation.

Note: For Multithreaded program examples, you have to set your project to Multithread project type.

 

Creating Processes

 

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 fragment demonstrates how to create a process.

 

// For WinXp

#define _WIN32_WINNT 0x0501

#include <windows.h>

#include <stdio.h>

 

int main()

{

    STARTUPINFO si;

    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));

    si.cb = sizeof(si);

    ZeroMemory(&pi, sizeof(pi));

    // Start the child process. If not OK...

    if(!CreateProcess("C:\\WINDOWS\\system32\\cmd.exe", // module name.

        NULL,    // 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.

    )

 

       // Then, give some prompt...

       printf("\nSorry! CreateProcess() failed.\n\n");

   //else, give some prompt...

   else

   {

       printf("\nWell, CreateProcess() looks OK.\n");

       printf("exit after 5000 ms...\n\n");

   }

    // Wait until child process exits after 5000 ms.

    WaitForSingleObject(pi.hProcess, 5000);

    printf("\n");

    // Close process and thread handles.

    CloseHandle(pi.hProcess);

    CloseHandle(pi.hThread);

    return 0;

}

 

A sample output:

Using CreateProcess() to create a process: program example output

 

Verify through Windows Task Manager.

 

Verifying process creation through Windows Task Manager

 

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.

 

Creating Threads

 

The CreateThread() function creates a new thread for a process. The creating thread must specify the starting address of the code that the new thread is to execute. Typically, the starting address is the name of a function defined in the program code. This function takes a single parameter and returns a DWORD value. A process can have multiple threads simultaneously executing the same function. The following example demonstrates how to create a new thread that executes the locally defined function, MyThreadFunction().

 

// For WinXp

#define _WIN32_WINNT 0x0501

#include <windows.h>

#include <stdio.h>

#include <conio.h>

 

DWORD WINAPI MyThreadFunction(LPVOID lpParam)

{

       printf("The parameter: %d.\n", *(DWORD*)lpParam);

    return 0;

}

 

int main(void)

{

    DWORD dwThreadId, dwThrdParam = 1;

    HANDLE hThread;

       // Let try a loop...

       for(int x = 1; x <= 5; x++)

       {

         hThread = CreateThread(

        NULL,                         // default security attributes

        0,                                // use default stack size 

        MyThreadFunction,  // thread function

        &dwThrdParam,       // argument to thread function

        0,                                // use default creation flags

        &dwThreadId);          // returns the thread identifier

   // Check the return value for success. If something wrong...

   if (hThread == NULL)

         printf("CreateThread() failed, error: %d.\n", GetLastError());

   //else, gives some prompt...

   else

   {

          printf("It seems the CreateThread() is OK lol!\n");

          printf("The thread ID: %d.\n", dwThreadId);

   }

 

   if (CloseHandle(hThread) != 0)

          printf("Handle to thread closed successfully.\n");

       }

  return 0;

}

 

A sample output:

 

Creating a thread

 

What a mess! Running the program for second time producing different output :o). Whatever, we just want to see some action here about creating threads.

 

Process/thread creation verification through Windows Task Manager

 

For simplicity, this example passes a pointer to a value as an argument to the thread function. This could be a pointer to any type of data or structure, or it could be omitted altogether by passing a NULL pointer and deleting the references to the parameter in MyThreadFunction(). It is risky to pass the address of a local variable if the creating thread exits before the new thread, because the pointer becomes invalid. Instead, either pass a pointer to dynamically allocated memory or make the creating thread wait for the new thread to terminate. Data can also be passed from the creating thread to the new thread using global variables. With global variables, it is usually necessary to synchronize access by multiple threads.

In processes where a thread might create multiple threads to execute the same code, it is inconvenient to use global variables. For example, a process that enables the user to open several files at the same time can create a new thread for each file, with each of the threads executing the same thread function. The creating thread can pass the unique information (such as the file name) required by each instance of the thread function as an argument. You cannot use a single global variable for this purpose, but you could use a dynamically allocated string buffer. The creating thread can use the arguments to CreateThread() to specify the following:

You can also create a thread by calling the CreateRemoteThread() function. This function is used by debugger processes to create a thread that runs in the address space of the process being debugged.

 

Enumerating All Processes

 

Task Manager is an example of a program that enumerates all running processes. It is implemented using data from the performance registry. The following sample code uses the EnumProcesses() function to enumerate the current processes in the system. This method is easier than using the performance registry.  Don’t forget to include the psapi.lib library in your project.  The steps are shown below.

Select and right click your project folder Select the Properties context menu.

Adding additional library to Visual C++ .Net project

 

Or you can access the project properties page through the Project menu your_project_name Properties... as shown below.

 

Adding additional library to Visual C++ .Net project

 

Select the Linker menu on the left pane On the Additional Dependencies setting, click the ...

 

Adding additional library to Visual C++ .Net project

 

Manually, type the library name and click the OK button.

 

 

Adding additional library to Visual C++ .Net project

 

// For WinXp

#define _WIN32_WINNT 0x0501

#include <windows.h>

#include <stdio.h>

#include <psapi.h>

 

void PrintProcessNameAndID(DWORD processID)

{

    // Initialize or default to "unknown"

    char szProcessName[MAX_PATH] = "<unknown>";

    // Get a handle to the process.

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);

    // Get the process name.

    if (hProcess != NULL)

    {

        HMODULE hMod;

        DWORD cbNeeded;

        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))

        {

            GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName));

        }

    }

    // Print the process name and identifier.

    printf("%-30s   %5u\n", szProcessName, processID);

    CloseHandle(hProcess);

}

 

int main()

{

    // Get the list of process identifiers.

    DWORD aProcesses[1024], cbNeeded, cProcesses;

    unsigned int i;

    // If fail...

    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))

        return 1; // or print some meaningful message...

    else

        printf("Enumprocesses() is OK.\n");

    // Calculate how many process identifiers were returned.

    cProcesses = cbNeeded / sizeof(DWORD);

    // Print the name and process identifier for each process.

    printf("Process Name                 Process ID\n");

    printf("============                 ==========\n");

    for (i = 0; i < cProcesses; i++)

        PrintProcessNameAndID(aProcesses[i]);

       return 0;

}

 

A sample output:

Enumprocesses() is OK.

Process Name                 Process ID

============                 ==========

<unknown>                            0

<unknown>                            4

smss.exe                           468

<unknown>                          528

winlogon.exe                       552

services.exe                       596

lsass.exe                          608

svchost.exe                        756

<unknown>                          812

svchost.exe                        848

<unknown>                          900

<unknown>                         1016

spoolsv.exe                       1116

inetinfo.exe                      1252

mdm.exe                           1268

slserv.exe                        1368

snmp.exe                          1396

svchost.exe                       1436

<unknown>                         1780

Explorer.EXE                       364

SOUNDMAN.EXE                       444

uGuru.exe                          460

AGRSMMSG.exe                       312

PDVDServ.exe                       496

OpwareSE2.exe                      504

ctfmon.exe                         524

msmsgs.exe                         520

wscntfy.exe                        612

acrotray.exe                       720

uGuru_Event_Receiver.exe           880

GammaTray.exe                      916

my015lit.exe                      1164

NaturalColorLoad.exe              1216

WINWORD.EXE                       2308

devenv.exe                        3468

mspaint.exe                       1088

vcspawn.exe                       3284

myprocess.exe                     3280

Press any key to continue

The main function obtains a list of processes by using the EnumProcesses() function. For each process, main calls the PrintProcessNameAndID() function, passing it the process identifier. PrintProcessNameAndID() in turn calls the OpenProcess() function to obtain the process handle. If OpenProcess() fails, the output shows the process name as <unknown>. For example, OpenProcess() fails for the Idle and CSRSS processes because their access restrictions prevent user-level code from opening them. Next, PrintProcessNameAndID() calls the EnumProcessModules() function to obtain the module handles. Finally, PrintProcessNameAndID() calls the GetModuleBaseName() function to obtain the name of the executable file and displays the name along with the process identifier.

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

 

  1. Microsoft Visual C++, online MSDN.

  2. For Multibytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).

  3. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

  4. Check the best selling C / C++ and Windows books at Amazon.com.

 

 

 

 

 

 

 |< Windows Process & Threads Programming 5 | Main | Windows Process & Threads Programming 7 >| Site Index | Download |