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