|
|
1.1 ! root 1: ! 2: /****************************************************************** ! 3: * This program demonstrates how convert an OS/2 program that uses * ! 4: * termination queues to wait for multiple child processses to * ! 5: * terminate. This is done under Win32 by waiting for the newly * ! 6: * created child process handles to be signalled. * ! 7: * * ! 8: * This program demonstrates the use of the following Win32 APIs: * ! 9: * CreateProcess, WaitForMultipleObjects, GetExitCodeProcess. * ! 10: ******************************************************************/ ! 11: ! 12: #include <windows.h> ! 13: #include <stdio.h> ! 14: #include <stdlib.h> ! 15: ! 16: #define PERR(api) printf("%s: Error %d from %s on line %d\n", \ ! 17: __FILE__, GetLastError(), api, __LINE__); ! 18: ! 19: #define PROCESS_COUNT 3 ! 20: ! 21: int main() ! 22: { ! 23: /***************************************************************** ! 24: * The following are the OS/2 types used in the OS/2 version: * ! 25: * * ! 26: * USHORT usErr; * ! 27: * HQUEUE hQueue; * ! 28: * STARTDATA stdata; * ! 29: * QUEUERESULT qresc; * ! 30: * USHORT cbElement, i, idSession; * ! 31: * PUSHORT pusQelemBuf; * ! 32: * BYTE bElemPrty; * ! 33: * USHORT pid; * ! 34: *****************************************************************/ ! 35: ! 36: STARTUPINFO stdata; /* info for CreateProcess */ ! 37: BOOL fSuccess; /* Win32 API return code */ ! 38: PROCESS_INFORMATION ppi; /* info for CreateProcess */ ! 39: DWORD adwProcessId[PROCESS_COUNT]; /* array of process ID's */ ! 40: HANDLE ahProcess[PROCESS_COUNT]; /* array of process handles */ ! 41: DWORD dwResult; /* API result */ ! 42: DWORD dwExitCode; /* exit code from the new processes */ ! 43: int i, j; ! 44: ! 45: /******************************************************************* ! 46: * usErr = DosCreateQueue(&hQueue, QUE_FIFO, szTermQName); * ! 47: * assert(!usErr); * ! 48: * * ! 49: * Rather than use a queue mechanism to both signal us that the * ! 50: * child process has ended and to return an exit code with, under * ! 51: * Win32 we need to wait for the process object to be signalled, * ! 52: * then call GetExitCodeProcess to get the exit code. * ! 53: *******************************************************************/ ! 54: ! 55: /****************************************************************** ! 56: * In the original OS/2 version, the variable stdata is of type * ! 57: * STARTDATA. In this version, it is of type STARTUPINFO. In the * ! 58: * comment boxes I will show the OS/2 settings for the STARTDATA * ! 59: * structure. Following the comment will be the Win32 equivalent * ! 60: * setting, if any. * ! 61: * * ! 62: * stdata.Related = TRUE; * ! 63: * * ! 64: * Under Win32 there is no formal parent/child process * ! 65: * relationship between processes and no equivalent parameter to * ! 66: * set. * ! 67: * * ! 68: * stdata.TraceOpt = 0; * ! 69: * * ! 70: * If the new process was to be debugged under Win32, you would * ! 71: * set the DEBUG_PROCESS flag for the fdwCreate parameter for * ! 72: * CreateProcess. * ! 73: * * ! 74: * stdata.PgmTitle = "OS/2 Command Processor"; * ! 75: ******************************************************************/ ! 76: ! 77: stdata.lpTitle = "Win32 Command Processor"; ! 78: ! 79: /******************************************************************* ! 80: * stdata.PgmName = "c:\\os2\\cmd.exe"; * ! 81: * stdata.PgmInputs = NULL; * ! 82: * * ! 83: * The equivalent Win32 parameters are passed directly into * ! 84: * CreateProcess as the lpszImageName and lpszCommandLine * ! 85: * parameters. * ! 86: * * ! 87: * stdata.TermQ = szTermQName; * ! 88: * * ! 89: * Wait for the object process to be signalled in Win32 instead * ! 90: * of using queues under OS/2. * ! 91: * * ! 92: * stdata.Environment = NULL; * ! 93: * * ! 94: * In Win32, this is passed as a parameter to CreateProcess as * ! 95: * the lpvEnvironment parameter. * ! 96: * * ! 97: * stdata.InheritOpt = 0; * ! 98: * * ! 99: * Though there is no formal parent/child relationship between * ! 100: * two processes in Win32, process can have the new process * ! 101: * inherit open object handles by specifying TRUE for the * ! 102: * fInheritHandles flag for CreateProcess. * ! 103: * * ! 104: * stdata.SessionType = 2; * ! 105: * * ! 106: * In Win32, the sessiontype does not need to be specified. It * ! 107: * will be automatically determined. * ! 108: * * ! 109: * stdata.IconFile = NULL; * ! 110: * stdata.PgmHandle = 0; * ! 111: * * ! 112: * In Win32, no similar options exist. * ! 113: * * ! 114: * stdata.PgmControl = 32768; * ! 115: * stdata.InitXPos = 50; * ! 116: * stdata.InitYPos = 250; * ! 117: * stdata.InitXSize = 200; * ! 118: * stdata.InitYSize = 100; * ! 119: * * ! 120: * For console apps under Win32, you can specify the console size * ! 121: * in terms of characters instead of pixel positions. * ! 122: *******************************************************************/ ! 123: ! 124: stdata.dwX = 50; /* X starting position (pixels) */ ! 125: stdata.dwY = 50; /* X starting position (pixels) */ ! 126: stdata.dwXSize = 40; ! 127: stdata.dwYSize = 25; ! 128: ! 129: /* set additional parameters for Win32 CreateProcess call */ ! 130: stdata.cb = sizeof(stdata); ! 131: stdata.lpReserved = NULL; ! 132: stdata.lpDesktop = NULL; ! 133: stdata.dwFlags = 0; /* attributes for starting process */ ! 134: stdata.wShowWindow = 0; ! 135: stdata.cbReserved2 = 0; ! 136: stdata.lpReserved2 = NULL; ! 137: ! 138: /* start PROCESS_COUNT number of child sessions */ ! 139: for (i = 0; i < PROCESS_COUNT; i++) ! 140: { ! 141: /************************************************** ! 142: * DosStartSession(&stdata, &idSession, &pid); * ! 143: * * ! 144: * Replace this with the Win32 CreateProcess call. * ! 145: **************************************************/ ! 146: ! 147: fSuccess = CreateProcess(NULL, /* image name */ ! 148: "cmd.exe", /* program to run and command line */ ! 149: NULL, /* security attributes for new process */ ! 150: NULL, /* security attributes for new thread */ ! 151: FALSE, /* don't inherit open object handles */ ! 152: NORMAL_PRIORITY_CLASS | /* creation flags */ ! 153: CREATE_NEW_CONSOLE, /* creation flags - new console for process */ ! 154: NULL, /* use environment of this process for new process */ ! 155: NULL, /* use current directory for startup directory */ ! 156: &stdata, /* startup data structure */ ! 157: &ppi); /* process info from the call */ ! 158: if (!fSuccess) ! 159: PERR("CreateProcess"); ! 160: CloseHandle(ppi.hThread); /* we don't need this handle */ ! 161: ! 162: /******************************************************** ! 163: * printf("session id = %d started\n", idSession); * ! 164: * * ! 165: * In Win32 the session ID is contained in the * ! 166: * PROCESS_INFORMATION structure (variable ppi in this * ! 167: * example). * ! 168: ********************************************************/ ! 169: ! 170: printf("session id = %d started\n", ppi.dwProcessId); ! 171: ahProcess[i] = ppi.hProcess; /* save the process handles */ ! 172: adwProcessId[i] = ppi.dwProcessId; /* save process IDs */ ! 173: stdata.dwX += 50; /* shift next window to cascade */ ! 174: stdata.dwY += 50; ! 175: } ! 176: ! 177: /****************************************************************** ! 178: * for (i = 0; i < PROCESS_COUNT; i++) * ! 179: * { * ! 180: * usErr = DosReadQueue(hQueue, &qresc, &cbElement, * ! 181: * (PVOID FAR *) &pusQelemBuf, 0, DCWW_WAIT, &bElemPrty, 0); * ! 182: * assert(!usErr); * ! 183: * printf("queue return: session id = %d, resultcode = %d\n", * ! 184: * pusQelemBuf[0], pusQelemBuf[1]); * ! 185: * usErr = DosFreeSeg(SELECTOROF(pusQelemBuf)); * ! 186: * assert(!usErr); * ! 187: * } * ! 188: * * ! 189: * Rather than read from the termination queue, under Win32 we * ! 190: * wait for any of the returned process handles to be signalled. * ! 191: * We must also use GetExitCodeProcess to get the exit codes * ! 192: * rather than getting them from the queue packet. * ! 193: ******************************************************************/ ! 194: ! 195: for (i = 0; i < PROCESS_COUNT; i++) ! 196: { ! 197: dwResult = WaitForMultipleObjects( ! 198: PROCESS_COUNT - i, /* number of objects to wait on */ ! 199: ahProcess, /* array of object handles to wait on */ ! 200: FALSE, /* wait on any handle to signal, rather than all */ ! 201: (DWORD) -1); /* timeout (wait forever) */ ! 202: if (dwResult == -1) ! 203: PERR("WaitForMultipleObjects"); ! 204: dwResult -= WAIT_OBJECT_0; /* adjust to zero-based range */ ! 205: fSuccess = GetExitCodeProcess( ! 206: ahProcess[dwResult], /* process handle */ ! 207: &dwExitCode); /* returned exit code */ ! 208: if (!fSuccess) ! 209: PERR("GetExitCodeProcess"); ! 210: CloseHandle(ahProcess[dwResult]); ! 211: printf("process return: session id = %d, result code = %d\n", ! 212: adwProcessId[dwResult], dwExitCode); ! 213: /* now we need to compact the handle/process ID arrays to remove */ ! 214: /* closed handle slots */ ! 215: for (j = dwResult; j <= PROCESS_COUNT - i - 2; j++) ! 216: { ! 217: /* shift remaining process handles down one slot */ ! 218: ahProcess[j] = ahProcess[j + 1]; ! 219: /* shift remaining process IDs down one slot */ ! 220: adwProcessId[j] = adwProcessId[j + 1]; ! 221: } ! 222: } ! 223: return(0); ! 224: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.