| My Training Period: yy hours. Before you begin, read someinstruction here.
The expected abilities are:
Note: For Multithreaded program examples, you have to set your project toMultithread project type.
Using The Thread Local Storage
Thread local storage (TLS) enables multiple threads of the same process to use an index allocated by the TlsAlloc() function to store and retrieve a value that is local to the thread. In this example, an index is allocated when the process starts. When each thread starts, it allocates a block of dynamic memory and stores a pointer to this memory in the TLS slot using the TlsSetValue() function. The MyCommonFunction() function uses the TlsGetValue() function to access the data associated with the index that is local to the calling thread. Before each thread terminates, it releases its dynamic memory. Before the process terminates, it callsTlsFree() to release the index.
// ForWinXp #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h> #define THREADCOUNT 5
DWORD dwTlsIndex;
// Function declarations and definitions... VOID ErrorExit(LPTSTR lpszMessage) { fprintf(stderr, "%s\n", lpszMessage); ExitProcess(0); } |
void MyCommonFunction(void)
{
LPVOID lpvData;
// Retrieve a data pointer for the current thread...
lpvData = TlsGetValue(dwTlsIndex);
if ((lpvData == 0) && (GetLastError() != 0))
ErrorExit("TlsGetValue() error!\n");
else
printf("TlsGetValue() is OK.\n");
// Use the data stored for the current thread...
printf("Common: thread %d: lpvData = %lx\n\n", GetCurrentThreadId(), lpvData);
}
DWORD WINAPI MyThreadFunc(void)
{
LPVOID lpvData;
// Initialize the TLS index for this thread.
lpvData = (LPVOID) LocalAlloc(LPTR, 256);
if (!TlsSetValue(dwTlsIndex, lpvData))
ErrorExit("TlsSetValue() error!\n");
else
printf("TlsSetValue() is OK.\n");
printf("Thread %d: lpvData = %lx\n", GetCurrentThreadId(), lpvData);
MyCommonFunction();
// Release the dynamic memory before the thread returns...
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != 0)
LocalFree((HLOCAL) lpvData);
return 0;
}
DWORD main(void)
{
DWORD IDThread;
HANDLE hThread[THREADCOUNT];
int i;
printf("Thread count is: %d\n", THREADCOUNT);
// Allocate a TLS index...
if ((dwTlsIndex = TlsAlloc()) == -1)
ErrorExit("TlsAlloc() failed");
else
printf("\nTlsAlloc() is OK.\n\n");
// Create multiple threads...
for (i = 0; i < THREADCOUNT; i++)
{
hThread[i] = CreateThread(NULL, // no security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE) MyThreadFunc, // thread function
NULL, // no thread function argument
0, // use default creation flags
&IDThread); // returns thread identifier
// Check the return value for success...
if (hThread[i] == NULL)
ErrorExit("CreateThread() error.\n");
else
printf("hThread[%d] is OK.\n", i);
}
for (i = 0; i < THREADCOUNT; i++)
WaitForSingleObject(hThread[i], INFINITE);
if (TlsFree(dwTlsIndex) == 0)
printf("TlsFree() failed!\n");
else
printf("TlsFree() is OK!\n");
return 0;
}
A sample output:
Thread count is: 5
TlsAlloc() is OK.
hThread[0] is OK.
hThread[1] is OK.
hThread[2] is OK.
hThread[3] is OK.
hThread[4] is OK.
TlsSetValue() is OK.
Thread 572: lpvData = 1430d8
TlsGetValue() is OK.
Common: thread 572: lpvData = 1430d8
TlsSetValue() is OK.
Thread 956: lpvData = 1430d8
TlsGetValue() is OK.
Common: thread 956: lpvData = 1430d8
TlsSetValue() is OK.
Thread 1636: lpvData = 1430d8
TlsGetValue() is OK.
Common: thread 1636: lpvData = 1430d8
TlsSetValue() is OK.
Thread 1740: lpvData = 1430d8
TlsGetValue() is OK.
Common: thread 1740: lpvData = 1430d8
TlsSetValue() is OK.
Thread 1696: lpvData = 1430d8
TlsGetValue() is OK.
Common: thread 1696: lpvData = 1430d8
TlsFree() is OK!
Press any key to continue
Creating a Child Process with Redirected Input and Output
The example in this topic demonstrates how to create a child process using the CreateProcess() function from a console process. It also demonstrates a technique for using anonymous pipes to redirect the child process's standard input and output handles. Note that named pipes can also be used to redirect process I/O.The CreatePipe() function uses theSECURITY_ATTRIBUTES structure to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the standard output for the child process. These pipe handles are specified in the STARTUPINFO structure, which makes them the standard handles inherited by the child process.
The parent process uses the other ends of the pipes to write to the child process's input and read the child process's output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process must use DuplicateHandle() to create a duplicate of the application-defined hChildStdinWr global variable that cannot be inherited. It then usesCloseHandle() to close the inheritable handle. The following is the code for the parent process. It takes a single command-line argument: the name of a text file. Furthermore, you also need to read a story about pipe.
// ForWinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 4096
// Declaring handles...
HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, hInputFile, hStdout;
// Prototypes...
BOOL CreateChildProcess(VOID);
VOID WriteToPipe(VOID);
VOID ReadFromPipe(VOID);
VOID MyErrorExit(LPTSTR);
VOID ErrMsg(LPTSTR, BOOL);
// This program takes a single command-line argument, the name of a text file
DWORD main(int argc, char *argv[])
{
SECURITY_ATTRIBUTES saAttr;
BOOL fSuccess;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Get the handle to the current STDOUT.
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
MyErrorExit("CreatePipe(), a pipe for the child process's STDOUT creation failed\n");
else
printf("CreatePipe(), a pipe for the child process's STDOUT creation is OK.\n");
// Create noninheritable read handle and close the inheritable read handle.
fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup , 0, FALSE, DUPLICATE_SAME_ACCESS);
if (!fSuccess)
{
MyErrorExit("DuplicateHandle() for noninheritable read handle failed");
CloseHandle(hChildStdoutRd);
}
else
printf("DuplicateHandle() for noninheritable read handle is OK.\n");
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
MyErrorExit("A pipe for the child process's STDIN creation failed\n");
else
printf("A pipe for the child process's STDIN creation is OK.\n");
// Duplicate the write handle to the pipe so it is not inherited.
fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0,
FALSE, // not inherited
DUPLICATE_SAME_ACCESS);
if (!fSuccess)
MyErrorExit("DuplicateHandle() for the write handle to the pipe failed");
else
printf("DuplicateHandle() for the write handle to the pipe is OK.\n");
CloseHandle(hChildStdinWr);
// Now create the child process.
fSuccess = CreateChildProcess();
if (! fSuccess)
MyErrorExit("CreateChildProcess(), a child process failed");
else
printf("CreateChildProcess(), a child process is OK.\n");
// Get a handle to the parent's input file.
printf("Getting a handle to the parent's input file.\n");
if (argc == 1)
MyErrorExit("Please specify an input file!");
else
printf("An input file is %s\n.", argv[1]);
hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (hInputFile == INVALID_HANDLE_VALUE)
MyErrorExit("CreateFile(), open existing failed\n");
else
printf("CreateFile(), open existing %s is OK.\n", argv[1]);
// Write to pipe that is the standard input for a child process.
printf("Try writing to pipe...\n");
WriteToPipe();
// Read from pipe that is the standard output for child process.
printf("Try reading from pipe...\n");
ReadFromPipe();
return 0;
}
//================================================ BOOL CreateChildProcess() { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; BOOL bFuncRetn = FALSE; // Set up members of the PROCESS_INFORMATION structure. ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); // Set up members of the STARTUPINFO structure. ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdError = hChildStdoutWr; siStartInfo.hStdOutput = hChildStdoutWr; siStartInfo.hStdInput = hChildStdinRd; |
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bFuncRetn = CreateProcess(NULL, // Use the following command line
"c:\\Windows\\system32\\systeminfo.exe", // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (bFuncRetn == 0)
MyErrorExit("CreateProcess() for child failed.");
else
{
printf("CreateProcess for child is OK.\n");
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
//================================================================
VOID WriteToPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
// Read from a file and write its contents to a pipe.
printf("In WriteToPipe(), try to read from a file and write its contents to a pipe.\n");
for (;;)// More read control should be implemented here such as EOF etc...
{
if (!(ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0))
printf("ReadFile() failed.\n");
break;
if (!WriteFile(hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL))
printf("WriteFile() failed.\n");
break;
}
// Close the pipe handle so the child process stops reading.
if (!CloseHandle(hChildStdinWrDup))
MyErrorExit("Close pipe failed");
}
//================================================================
VOID ReadFromPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
// Close the write end of the pipe before reading from the read end of the pipe.
if (!CloseHandle(hChildStdoutWr))
MyErrorExit("CloseHandle() failed");
else
printf("CloseHandle() is OK.\n");
// Read output from the child process, and write to parent's STDOUT.
printf("In ReadFromPipe(), try to read output from the child process, and write to parent's STDOUT.\n");
for (;;)// More read control should be implemented here such as EOF etc...
{
if (!ReadFile(hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0)
printf("ReadFile() failed.\n");
break;
if (!WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL))
printf("WriteFile() failed.\n");
break;
}
}
//================================================================
VOID MyErrorExit(LPTSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
// Exit peacefully...
ExitProcess(0);
}
A sample output:
F:\myproject\myprocess\Debug>myprocess c:\test.txt
CreatePipe(), a pipe for the child process's STDOUT creation is OK.
DuplicateHandle() for noninheritable read handle is OK.
A pipe for the child process's STDIN creation is OK.
DuplicateHandle() for the write handle to the pipe is OK.
CreateProcess for child is OK.
CreateChildProcess(), a child process is OK.
Getting a handle to the parent's input file.
An input file is c:\test.txt
.CreateFile(), open existing c:\test.txt is OK.
Try writing to pipe...
In WriteToPipe(), try to read from a file and write its contents to a pipe.
Try reading from pipe...
CloseHandle() is OK.
In ReadFromPipe(), try to read output from the child process, and write to parent's STDOUT.
F:\myproject\myprocess\Debug>
A verification through Windows Task Manager is shown below.

The following is the code for the child process. It uses the inherited handles for STDIN and STDOUT to access the pipe created by the parent. The parent process reads from its input file and writes the information to a pipe. The child receives text through the pipe using STDIN and writes to the pipe using STDOUT. The parent reads from the read end of the pipe and displays the information to its STDOUT.
// ForWinXp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#define BUFSIZE 4096
int main(void)
{
CHAR chBuf[BUFSIZE];
DWORD dwRead, dwWritten;
HANDLE hStdin, hStdout;
BOOL fSuccess;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if ((hStdout == INVALID_HANDLE_VALUE) || (hStdin == INVALID_HANDLE_VALUE))
// Exit with error...
ExitProcess(1);
else
printf("GetStdHandle() for standard input and output is OK.\n");
for (;;)// May use other program control here to stop automatically :o)
{
// Read from standard input.
fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
if (!(fSuccess || dwRead == 0))
{
printf("ReadFile(), from standard input failed.\n");
break;
}
else
printf("ReadFile(), from standard input is OK.\n");
// Write to standard output...
fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
if (!fSuccess)
{
printf("WriteFile(), to standard output failed.\n");
break;
}
else
printf("WriteFile(), to standard output is OK.\n");
}
return 0;
}
A sample output:
F:\myproject\childprocess\Debug>childprocess
GetStdHandle() for standard input and output is OK.
Testing some text from standard input...
ReadFile(), from standard input is OK.
Testing some text from standard input...
WriteFile(), to standard output is OK.
Need to stop the program manually lol!
ReadFile(), from standard input is OK.
Need to stop the program manually lol!
WriteFile(), to standard output is OK.
^C
F:\myproject\childprocess\Debug>
Further reading and digging:
Microsoft C references, online MSDN.
Microsoft Visual C++, online MSDN.
ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.
Linux Access Control Lists (ACL) info can be found atAccess Control Lists.
For Multi bytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).
Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.
Check the best selling C / C++ and Windows books at Amazon.com.