|
|
Microsoft Windows NT Build 297 06-28-1992
/******************************************************************
* This program demonstrates how convert an OS/2 program that uses *
* termination queues to wait for multiple child processses to *
* terminate. This is done under Win32 by waiting for the newly *
* created child process handles to be signalled. *
* *
* This program demonstrates the use of the following Win32 APIs: *
* CreateProcess, WaitForMultipleObjects, GetExitCodeProcess. *
******************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#define PERR(api) printf("%s: Error %d from %s on line %d\n", \
__FILE__, GetLastError(), api, __LINE__);
#define PROCESS_COUNT 3
int main()
{
/*****************************************************************
* The following are the OS/2 types used in the OS/2 version: *
* *
* USHORT usErr; *
* HQUEUE hQueue; *
* STARTDATA stdata; *
* QUEUERESULT qresc; *
* USHORT cbElement, i, idSession; *
* PUSHORT pusQelemBuf; *
* BYTE bElemPrty; *
* USHORT pid; *
*****************************************************************/
STARTUPINFO stdata; /* info for CreateProcess */
BOOL fSuccess; /* Win32 API return code */
PROCESS_INFORMATION ppi; /* info for CreateProcess */
DWORD adwProcessId[PROCESS_COUNT]; /* array of process ID's */
HANDLE ahProcess[PROCESS_COUNT]; /* array of process handles */
DWORD dwResult; /* API result */
DWORD dwExitCode; /* exit code from the new processes */
int i, j;
/*******************************************************************
* usErr = DosCreateQueue(&hQueue, QUE_FIFO, szTermQName); *
* assert(!usErr); *
* *
* Rather than use a queue mechanism to both signal us that the *
* child process has ended and to return an exit code with, under *
* Win32 we need to wait for the process object to be signalled, *
* then call GetExitCodeProcess to get the exit code. *
*******************************************************************/
/******************************************************************
* In the original OS/2 version, the variable stdata is of type *
* STARTDATA. In this version, it is of type STARTUPINFO. In the *
* comment boxes I will show the OS/2 settings for the STARTDATA *
* structure. Following the comment will be the Win32 equivalent *
* setting, if any. *
* *
* stdata.Related = TRUE; *
* *
* Under Win32 there is no formal parent/child process *
* relationship between processes and no equivalent parameter to *
* set. *
* *
* stdata.TraceOpt = 0; *
* *
* If the new process was to be debugged under Win32, you would *
* set the DEBUG_PROCESS flag for the fdwCreate parameter for *
* CreateProcess. *
* *
* stdata.PgmTitle = "OS/2 Command Processor"; *
******************************************************************/
stdata.lpTitle = "Win32 Command Processor";
/*******************************************************************
* stdata.PgmName = "c:\\os2\\cmd.exe"; *
* stdata.PgmInputs = NULL; *
* *
* The equivalent Win32 parameters are passed directly into *
* CreateProcess as the lpszImageName and lpszCommandLine *
* parameters. *
* *
* stdata.TermQ = szTermQName; *
* *
* Wait for the object process to be signalled in Win32 instead *
* of using queues under OS/2. *
* *
* stdata.Environment = NULL; *
* *
* In Win32, this is passed as a parameter to CreateProcess as *
* the lpvEnvironment parameter. *
* *
* stdata.InheritOpt = 0; *
* *
* Though there is no formal parent/child relationship between *
* two processes in Win32, process can have the new process *
* inherit open object handles by specifying TRUE for the *
* fInheritHandles flag for CreateProcess. *
* *
* stdata.SessionType = 2; *
* *
* In Win32, the sessiontype does not need to be specified. It *
* will be automatically determined. *
* *
* stdata.IconFile = NULL; *
* stdata.PgmHandle = 0; *
* *
* In Win32, no similar options exist. *
* *
* stdata.PgmControl = 32768; *
* stdata.InitXPos = 50; *
* stdata.InitYPos = 250; *
* stdata.InitXSize = 200; *
* stdata.InitYSize = 100; *
* *
* For console apps under Win32, you can specify the console size *
* in terms of characters instead of pixel positions. *
*******************************************************************/
stdata.dwX = 50; /* X starting position (pixels) */
stdata.dwY = 50; /* X starting position (pixels) */
stdata.dwXSize = 40;
stdata.dwYSize = 25;
/* set additional parameters for Win32 CreateProcess call */
stdata.cb = sizeof(stdata);
stdata.lpReserved = NULL;
stdata.lpDesktop = NULL;
stdata.dwFlags = 0; /* attributes for starting process */
stdata.wShowWindow = 0;
stdata.cbReserved2 = 0;
stdata.lpReserved2 = NULL;
/* start PROCESS_COUNT number of child sessions */
for (i = 0; i < PROCESS_COUNT; i++)
{
/**************************************************
* DosStartSession(&stdata, &idSession, &pid); *
* *
* Replace this with the Win32 CreateProcess call. *
**************************************************/
fSuccess = CreateProcess(NULL, /* image name */
"cmd.exe", /* program to run and command line */
NULL, /* security attributes for new process */
NULL, /* security attributes for new thread */
FALSE, /* don't inherit open object handles */
NORMAL_PRIORITY_CLASS | /* creation flags */
CREATE_NEW_CONSOLE, /* creation flags - new console for process */
NULL, /* use environment of this process for new process */
NULL, /* use current directory for startup directory */
&stdata, /* startup data structure */
&ppi); /* process info from the call */
if (!fSuccess)
PERR("CreateProcess");
CloseHandle(ppi.hThread); /* we don't need this handle */
/********************************************************
* printf("session id = %d started\n", idSession); *
* *
* In Win32 the session ID is contained in the *
* PROCESS_INFORMATION structure (variable ppi in this *
* example). *
********************************************************/
printf("session id = %d started\n", ppi.dwProcessId);
ahProcess[i] = ppi.hProcess; /* save the process handles */
adwProcessId[i] = ppi.dwProcessId; /* save process IDs */
stdata.dwX += 50; /* shift next window to cascade */
stdata.dwY += 50;
}
/******************************************************************
* for (i = 0; i < PROCESS_COUNT; i++) *
* { *
* usErr = DosReadQueue(hQueue, &qresc, &cbElement, *
* (PVOID FAR *) &pusQelemBuf, 0, DCWW_WAIT, &bElemPrty, 0); *
* assert(!usErr); *
* printf("queue return: session id = %d, resultcode = %d\n", *
* pusQelemBuf[0], pusQelemBuf[1]); *
* usErr = DosFreeSeg(SELECTOROF(pusQelemBuf)); *
* assert(!usErr); *
* } *
* *
* Rather than read from the termination queue, under Win32 we *
* wait for any of the returned process handles to be signalled. *
* We must also use GetExitCodeProcess to get the exit codes *
* rather than getting them from the queue packet. *
******************************************************************/
for (i = 0; i < PROCESS_COUNT; i++)
{
dwResult = WaitForMultipleObjects(
PROCESS_COUNT - i, /* number of objects to wait on */
ahProcess, /* array of object handles to wait on */
FALSE, /* wait on any handle to signal, rather than all */
(DWORD) -1); /* timeout (wait forever) */
if (dwResult == -1)
PERR("WaitForMultipleObjects");
dwResult -= WAIT_OBJECT_0; /* adjust to zero-based range */
fSuccess = GetExitCodeProcess(
ahProcess[dwResult], /* process handle */
&dwExitCode); /* returned exit code */
if (!fSuccess)
PERR("GetExitCodeProcess");
CloseHandle(ahProcess[dwResult]);
printf("process return: session id = %d, result code = %d\n",
adwProcessId[dwResult], dwExitCode);
/* now we need to compact the handle/process ID arrays to remove */
/* closed handle slots */
for (j = dwResult; j <= PROCESS_COUNT - i - 2; j++)
{
/* shift remaining process handles down one slot */
ahProcess[j] = ahProcess[j + 1];
/* shift remaining process IDs down one slot */
adwProcessId[j] = adwProcessId[j + 1];
}
}
return(0);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.