|< 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

 

 

My Training Period:          hours

 

Note:

Program examples compiled using Win32 console mode application of the Visual C++ .Net (Visual studio .Net 2003).  It is low-level programming and the .Net used is Unmanaged (/clr is not set: Project menu → your_project_name Properties… sub menu → Configuration Properties folder → General subfolder → Used Managed Extension setting set to No).  This also applied to other program examples in other Modules of tenouk.com Tutorial that mentioned “compiled using Visual C++ .Net”.  Other settings are default.  Machine’s OS is standalone Win Xp SP2.  Program examples have been tested for Non Destructive Test :o).  All information recomposed for Win 2000 (NT5.0) above.

 

WARNING

 

Wrongly modified and run the program examples presented here might collapse your Windows machine or disturb its integrity.  So for your Windows machine safety, make sure you fulfill the following conditions:

 

  1. Already read, understood and agreed to tenouk.com small disclaimer.
  2. Must be familiar with Windows OSes mainly NT5 (Windows 2000 above).
  3. Must be fluent in the following C topics: Function, Array, Pointer, String and Structure.
  4. Then, the basic knowledge of the Microsoft C Run-Time (CRT) and Win32 Programming using C.
  5. Do not mess up your system (Get a test machine! And run the program examples on the test machine).
  6. Must understand what you are going to do with the Windows APIs.
  7. Functions and structure used in the program examples were dumped at Functions & structure.
  8. Other related and required information (if any) not available in no. 7 can be found at MSDN Online.

 

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.

 

Index

 

  1. Creating Processes.
  2. Creating Threads.
  3. Enumerating All Processes.

 

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;

}

 

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;

}

 

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:

 

          The security attributes for the handle to the new thread. These security attributes include an inheritance flag that determines whether the handle can be inherited by child processes. The security attributes also include a security descriptor, which the system uses to perform access checks on all subsequent uses of the thread's handle before access is granted.

          The initial stack size of the new thread. The thread's stack is allocated automatically in the memory space of the process; the system increases the stack as needed and frees it when the thread terminates.

          A creation flag that enables you to create the thread in a suspended state. When suspended, the thread does not run until the ResumeThread() function is called.

 

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;

}

 

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.

 

 

 

Next...More examples...

www.tenouk.com

 

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 |