Gaining a Sense of One s Own Identity

[Previous] [Next]

As threads execute, they frequently want to call Windows functions that change their execution environment. For example, a thread might want to alter its priority or its process's priority. (Priorities are discussed in Chapter 7.) Since it is common for a thread to alter its (or its process's) environment, Windows offers functions that make it easy for a thread to refer to its process kernel object or to its own thread kernel object:

 HANDLE GetCurrentProcess(); HANDLE GetCurrentThread(); 

Both of these functions return a pseudo-handle to the calling thread's process or thread kernel object. These functions do not create new handles in the calling process's handle table. Also, calling these functions has no effect on the usage count of the process or thread kernel object. If you call CloseHandle, passing a pseudo-handle as the parameter, CloseHandle simply ignores the call and returns FALSE.

When you call a Windows function that requires a handle to a process or thread, you can pass a pseudo-handle, which causes the function to perform its action on the calling process or thread. For example, a thread can query its process's time usage by calling GetProcessTimes as follows:

 FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime; GetProcessTimes(GetCurrentProcess(), &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime); 

Likewise, a thread can query its own thread times by calling GetThreadTimes:

 FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime; GetThreadTimes(GetCurrentThread(), &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime); 

A few Windows functions allow you to identify a specific process or thread by its unique system-wide ID. The following functions allow a thread to query its process's unique ID or its own unique ID:

 DWORD GetCurrentProcessId(); DWORD GetCurrentThreadId(); 

These functions are generally not as useful as the functions that return pseudo-handles, but occasionally they come in handy.

Converting a Pseudo-Handle to a Real Handle

Sometimes you might need to acquire a real handle to a thread instead of a pseudo-handle. By "real," I mean a handle that unambiguously identifies a unique thread. Examine the following code:

 DWORD WINAPI ParentThread(PVOID pvParam) { HANDLE hThreadParent = GetCurrentThread(); CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, NULL); // Function continues... } DWORD WINAPI ChildThread(PVOID pvParam) {    HANDLE hThreadParent = (HANDLE) pvParam;    FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime;    GetThreadTimes(hThreadParent,       &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);    // Function continues... } 

Can you see the problem with this code fragment? The idea is to have the parent thread pass to the child thread a thread handle that identifies the parent thread. However, the parent thread passes a pseudo-handle, not a real handle. When the child thread begins executing, it passes the pseudo-handle to the GetThreadTimes function, which causes the child thread to get its own CPU times, not the parent thread's CPU times. This happens because a thread pseudo-handle is a handle to the current thread— that is, a handle to whichever thread is making the function call.

To fix this code, we must turn the pseudo-handle into a real handle. The DuplicateHandle function (discussed in Chapter 3) can do this transformation:

 BOOL DuplicateHandle(    HANDLE hSourceProcess,     HANDLE hSource,    HANDLE hTargetProcess,     PHANDLE phTarget,    DWORD fdwAccess,     BOOL bInheritHandle,     DWORD fdwOptions); 

Usually you use this function to create a new process-relative handle from a kernel object handle that is relative to another process. However, we can use it in an unusual way to correct the code fragment discussed earlier. The corrected code fragment is as follows:

 DWORD WINAPI ParentThread(PVOID pvParam) {    HANDLE hThreadParent;    DuplicateHandle(       GetCurrentProcess(),     // Handle of process that thread                                 // pseudo-handle is relative to       GetCurrentThread(),      // Parent thread's pseudo-handle       GetCurrentProcess(),     // Handle of process that the new, real,                                // thread handle is relative to       &hThreadParent,          // Will receive the new, real, handle                                // identifying the parent thread       0,                       // Ignored due to DUPLICATE_SAME_ACCESS       FALSE,                   // New thread handle is not inheritable       DUPLICATE_SAME_ACCESS);  // New thread handle has same                                 // access as pseudo-handle    CreateThread(NULL, 0, ChildThread, (PVOID) hThreadParent, 0, NULL);    // Function continues... } DWORD WINAPI ChildThread(PVOID pvParam) {    HANDLE hThreadParent = (HANDLE) pvParam;    FILETIME ftCreationTime, ftExitTime, ftKernelTime, ftUserTime;    GetThreadTimes(hThreadParent,       &ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);    CloseHandle(hThreadParent);    // Function continues... } 

Now when the parent thread executes, it converts the ambiguous pseudo-handle identifying the parent thread to a new, real handle that unambiguously identifies the parent thread, and it passes this real handle to CreateThread. When the child thread starts executing, its pvParam parameter contains the real thread handle. Any calls to functions passing this handle will affect the parent thread, not the child thread.

Because DuplicateHandle increments the usage count of the specified kernel object, it is important to decrement the object's usage count by passing the target handle to CloseHandle when you finish using the duplicated object handle. This is shown in the code fragment above. Immediately after the call to GetThreadTimes, the child thread calls CloseHandle to decrement the parent thread object's usage count. In this code fragment, I assumed that the child thread would not call any other functions using this handle. If other functions are to be called passing the parent thread's handle, the call to CloseHandle should not be made until the child thread no longer requires the handle.

I should also point out that the DuplicateHandle function can be used to convert a pseudo-handle for a process to a real process handle as follows:

 HANDLE hProcess; DuplicateHandle(    GetCurrentProcess(),    // Handle of process that the process                             // pseudo-handle is relative to    GetCurrentProcess(),    // Process's pseudo-handle    GetCurrentProcess(),    // Handle of process that the new, real,                            // process handle is relative to    &hProcess,              // Will receive the new, real                             // handle identifying the process    0,                      // Ignored because of DUPLICATE_SAME_ACCESS    FALSE,                  // New thread handle is not inheritable    DUPLICATE_SAME_ACCESS); // New process handle has same                             // access as pseudo-handle 



Programming Applications for Microsoft Windows
Programming Applications for Microsoft Windows (Microsoft Programming Series)
ISBN: 1572319968
EAN: 2147483647
Year: 1999
Pages: 193

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net