source: trunk/src/helpers/apps.c@ 131

Last change on this file since 131 was 131, checked in by umoeller, 24 years ago

Coupla fixes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 52.9 KB
Line 
1
2/*
3 *@@sourcefile apps.c:
4 * contains program helpers (environments, application start).
5 *
6 * This file is new with V0.9.12 and contains functions
7 * previously in winh.c and dosh2.c.
8 *
9 * Note: Version numbering in this file relates to XWorkplace version
10 * numbering.
11 *
12 *@@header "helpers\apps.h"
13 *@@added V0.9.12 (2001-05-26) [umoeller]
14 */
15
16/*
17 * Copyright (C) 1997-2001 Ulrich M”ller.
18 * This file is part of the "XWorkplace helpers" source package.
19 * This is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published
21 * by the Free Software Foundation, in version 2 as it comes in the
22 * "COPYING" file of the XWorkplace main distribution.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 */
28
29#define OS2EMX_PLAIN_CHAR
30 // this is needed for "os2emx.h"; if this is defined,
31 // emx will define PSZ as _signed_ char, otherwise
32 // as unsigned char
33
34#define INCL_DOSPROCESS
35#define INCL_DOSMODULEMGR
36#define INCL_DOSSESMGR
37#define INCL_DOSERRORS
38
39#define INCL_WINPROGRAMLIST // needed for PROGDETAILS, wppgm.h
40#define INCL_WINERRORS
41#define INCL_SHLERRORS
42#include <os2.h>
43
44#include <stdio.h>
45
46#include "setup.h" // code generation and debugging options
47
48#include "helpers\apps.h"
49#include "helpers\dosh.h"
50#include "helpers\prfh.h"
51#include "helpers\stringh.h"
52#include "helpers\winh.h"
53#include "helpers\xstring.h"
54
55/*
56 *@@category: Helpers\PM helpers\Application helpers
57 */
58
59/* ******************************************************************
60 *
61 * Environment helpers
62 *
63 ********************************************************************/
64
65/*
66 *@@ appQueryEnvironmentLen:
67 * returns the total length of the passed in environment
68 * string buffer, including the terminating two null bytes.
69 *
70 *@@added V0.9.16 (2002-01-09) [umoeller]
71 */
72
73ULONG appQueryEnvironmentLen(PCSZ pcszEnvironment)
74{
75 ULONG cbEnvironment = 0;
76 if (pcszEnvironment)
77 {
78 PCSZ pVarThis = pcszEnvironment;
79 // go thru the environment strings; last one has two null bytes
80 while (*pVarThis)
81 {
82 ULONG ulLenThis = strlen(pVarThis) + 1;
83 cbEnvironment += ulLenThis;
84 pVarThis += ulLenThis;
85 }
86
87 cbEnvironment++; // last null byte
88 }
89
90 return (cbEnvironment);
91}
92
93/*
94 *@@ appParseEnvironment:
95 * this takes one of those ugly environment strings
96 * as used by DosStartSession and WinStartApp (with
97 * lots of zero-terminated strings one after another
98 * and a duplicate zero byte as a terminator) as
99 * input and splits it into an array of separate
100 * strings in pEnv.
101 *
102 * The newly allocated strings are stored in in
103 * pEnv->papszVars. The array count is stored in
104 * pEnv->cVars.
105 *
106 * Each environment variable will be copied into
107 * one newly allocated string in the array. Use
108 * appFreeEnvironment to free the memory allocated
109 * by this function.
110 *
111 * Use the following code to browse thru the array:
112 +
113 + DOSENVIRONMENT Env = {0};
114 + if (appParseEnvironment(pszEnv,
115 + &Env)
116 + == NO_ERROR)
117 + {
118 + if (Env.papszVars)
119 + {
120 + PSZ *ppszThis = Env.papszVars;
121 + for (ul = 0;
122 + ul < Env.cVars;
123 + ul++)
124 + {
125 + PSZ pszThis = *ppszThis;
126 + // pszThis now has something like PATH=C:\TEMP
127 + // ...
128 + // next environment string
129 + ppszThis++;
130 + }
131 + }
132 + appFreeEnvironment(&Env);
133 + }
134 *
135 *@@added V0.9.4 (2000-08-02) [umoeller]
136 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
137 */
138
139APIRET appParseEnvironment(const char *pcszEnv,
140 PDOSENVIRONMENT pEnv) // out: new environment
141{
142 APIRET arc = NO_ERROR;
143 if (!pcszEnv)
144 arc = ERROR_INVALID_PARAMETER;
145 else
146 {
147 PSZ pszVarThis = (PSZ)pcszEnv;
148 ULONG cVars = 0;
149 // count strings
150 while (*pszVarThis)
151 {
152 cVars++;
153 pszVarThis += strlen(pszVarThis) + 1;
154 }
155
156 pEnv->cVars = 0;
157 pEnv->papszVars = 0;
158
159 if (cVars)
160 {
161 ULONG cbArray = sizeof(PSZ) * cVars;
162 PSZ *papsz;
163 if (!(papsz = (PSZ*)malloc(cbArray)))
164 arc = ERROR_NOT_ENOUGH_MEMORY;
165 else
166 {
167 PSZ *ppszTarget = papsz;
168 memset(papsz, 0, cbArray);
169 pszVarThis = (PSZ)pcszEnv;
170 while (*pszVarThis)
171 {
172 ULONG ulThisLen;
173 if (!(*ppszTarget = strhdup(pszVarThis, &ulThisLen)))
174 {
175 arc = ERROR_NOT_ENOUGH_MEMORY;
176 break;
177 }
178 (pEnv->cVars)++;
179 ppszTarget++;
180 pszVarThis += ulThisLen + 1;
181 }
182
183 pEnv->papszVars = papsz;
184 }
185 }
186 }
187
188 return (arc);
189}
190
191/*
192 *@@ appGetEnvironment:
193 * calls appParseEnvironment for the current
194 * process environment, which is retrieved from
195 * the info blocks.
196 *
197 * Returns:
198 *
199 * -- NO_ERROR:
200 *
201 * -- ERROR_INVALID_PARAMETER
202 *
203 * -- ERROR_BAD_ENVIRONMENT: no environment found in
204 * info blocks.
205 *
206 *@@added V0.9.4 (2000-07-19) [umoeller]
207 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
208 */
209
210APIRET appGetEnvironment(PDOSENVIRONMENT pEnv)
211{
212 APIRET arc = NO_ERROR;
213 if (!pEnv)
214 arc = ERROR_INVALID_PARAMETER;
215 else
216 {
217 PTIB ptib = 0;
218 PPIB ppib = 0;
219 arc = DosGetInfoBlocks(&ptib, &ppib);
220 if (arc == NO_ERROR)
221 {
222 PSZ pszEnv;
223 if (pszEnv = ppib->pib_pchenv)
224 arc = appParseEnvironment(pszEnv, pEnv);
225 else
226 arc = ERROR_BAD_ENVIRONMENT;
227 }
228 }
229
230 return (arc);
231}
232
233/*
234 *@@ appFindEnvironmentVar:
235 * returns the PSZ* in the pEnv->papszVars array
236 * which specifies the environment variable in pszVarName.
237 *
238 * With pszVarName, you can either specify the variable
239 * name only ("VARNAME") or a full environment string
240 * ("VARNAME=BLAH"). In any case, only the variable name
241 * is compared.
242 *
243 * Returns NULL if no such variable name was found in
244 * the array.
245 *
246 *@@added V0.9.4 (2000-07-19) [umoeller]
247 *@@changed V0.9.12 (2001-05-21) [umoeller]: fixed memory leak
248 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
249 *@@changed V0.9.16 (2002-01-01) [umoeller]: removed extra heap allocation
250 */
251
252PSZ* appFindEnvironmentVar(PDOSENVIRONMENT pEnv,
253 PSZ pszVarName)
254{
255 PSZ *ppszRet = 0;
256
257 if ( (pEnv)
258 && (pEnv->papszVars)
259 && (pszVarName)
260 )
261 {
262 ULONG ul = 0;
263 ULONG ulVarNameLen = 0;
264
265 PSZ pFirstEqual;
266 // rewrote all the following for speed V0.9.16 (2002-01-01) [umoeller]
267 if (pFirstEqual = strchr(pszVarName, '='))
268 // VAR=VALUE
269 // ^ pFirstEqual
270 ulVarNameLen = pFirstEqual - pszVarName;
271 else
272 ulVarNameLen = strlen(pszVarName);
273
274 for (ul = 0;
275 ul < pEnv->cVars;
276 ul++)
277 {
278 PSZ pszThis = pEnv->papszVars[ul];
279 if (pFirstEqual = strchr(pszThis, '='))
280 {
281 ULONG ulLenThis = pFirstEqual - pszThis;
282 if ( (ulLenThis == ulVarNameLen)
283 && (!memicmp(pszThis,
284 pszVarName,
285 ulVarNameLen))
286 )
287 {
288 ppszRet = &pEnv->papszVars[ul];
289 break;
290 }
291 }
292 }
293 }
294
295 return (ppszRet);
296}
297
298/*
299 *@@ appSetEnvironmentVar:
300 * sets an environment variable in the specified
301 * environment, which must have been initialized
302 * using appGetEnvironment first.
303 *
304 * pszNewEnv must be a full environment string
305 * in the form "VARNAME=VALUE".
306 *
307 * If "VARNAME" has already been set to something
308 * in the string array in pEnv, that array item
309 * is replaced.
310 *
311 * OTOH, if "VARNAME" has not been set yet, a new
312 * item is added to the array, and pEnv->cVars is
313 * raised by one. In that case, fAddFirst determines
314 * whether the new array item is added to the front
315 * or the tail of the environment list.
316 *
317 *@@added V0.9.4 (2000-07-19) [umoeller]
318 *@@changed V0.9.7 (2000-12-17) [umoeller]: added fAddFirst
319 *@@changed V0.9.12 (2001-05-21) [umoeller]: fixed memory leak
320 *@@changed V0.9.12 (2001-05-26) [umoeller]: fixed crash if !fAddFirst
321 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
322 */
323
324APIRET appSetEnvironmentVar(PDOSENVIRONMENT pEnv,
325 PSZ pszNewEnv,
326 BOOL fAddFirst)
327{
328 APIRET arc = NO_ERROR;
329 if ((!pEnv) || (!pszNewEnv))
330 arc = ERROR_INVALID_PARAMETER;
331 else
332 {
333 if (!pEnv->papszVars)
334 {
335 // no variables set yet:
336 pEnv->papszVars = (PSZ*)malloc(sizeof(PSZ));
337 pEnv->cVars = 1;
338
339 *(pEnv->papszVars) = strdup(pszNewEnv);
340 }
341 else
342 {
343 PSZ *ppszEnvLine;
344 if (ppszEnvLine = appFindEnvironmentVar(pEnv, pszNewEnv))
345 // was set already: replace
346 arc = strhStore(ppszEnvLine,
347 pszNewEnv,
348 NULL);
349 else
350 {
351 // not set already:
352 PSZ *ppszNew = NULL;
353
354 // allocate new array, with one new entry
355 // fixed V0.9.12 (2001-05-26) [umoeller], this crashed
356 PSZ *papszNew;
357
358 if (!(papszNew = (PSZ*)malloc(sizeof(PSZ) * (pEnv->cVars + 1))))
359 arc = ERROR_NOT_ENOUGH_MEMORY;
360 else
361 {
362 if (fAddFirst)
363 {
364 // add as first entry:
365 // overwrite first entry
366 ppszNew = papszNew;
367 // copy old entries
368 memcpy(papszNew + 1, // second new entry
369 pEnv->papszVars, // first old entry
370 sizeof(PSZ) * pEnv->cVars);
371 }
372 else
373 {
374 // append at the tail:
375 // overwrite last entry
376 ppszNew = papszNew + pEnv->cVars;
377 // copy old entries
378 memcpy(papszNew, // first new entry
379 pEnv->papszVars, // first old entry
380 sizeof(PSZ) * pEnv->cVars);
381 }
382
383 free(pEnv->papszVars); // was missing V0.9.12 (2001-05-21) [umoeller]
384 pEnv->papszVars = papszNew;
385 pEnv->cVars++;
386 *ppszNew = strdup(pszNewEnv);
387 }
388 }
389 }
390 }
391
392 return (arc);
393}
394
395/*
396 *@@ appConvertEnvironment:
397 * converts an environment initialized by appGetEnvironment
398 * to the string format required by WinStartApp and DosExecPgm,
399 * that is, one memory block is allocated in *ppszEnv and all
400 * strings in pEnv->papszVars are copied to that block. Each
401 * string is terminated with a null character; the last string
402 * is terminated with two null characters.
403 *
404 * Use free() to free the memory block allocated by this
405 * function in *ppszEnv.
406 *
407 *@@added V0.9.4 (2000-07-19) [umoeller]
408 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
409 */
410
411APIRET appConvertEnvironment(PDOSENVIRONMENT pEnv,
412 PSZ *ppszEnv, // out: environment string
413 PULONG pulSize) // out: size of block allocated in *ppszEnv; ptr can be NULL
414{
415 APIRET arc = NO_ERROR;
416 if ( (!pEnv)
417 || (!pEnv->papszVars)
418 )
419 arc = ERROR_INVALID_PARAMETER;
420 else
421 {
422 // count memory needed for all strings
423 ULONG cbNeeded = 0,
424 ul = 0;
425 PSZ *ppszThis = pEnv->papszVars;
426
427 for (ul = 0;
428 ul < pEnv->cVars;
429 ul++)
430 {
431 cbNeeded += strlen(*ppszThis) + 1; // length of string plus null terminator
432
433 // next environment string
434 ppszThis++;
435 }
436
437 cbNeeded++; // for another null terminator
438
439 if (!(*ppszEnv = (PSZ)malloc(cbNeeded)))
440 arc = ERROR_NOT_ENOUGH_MEMORY;
441 else
442 {
443 PSZ pTarget = *ppszEnv;
444 if (pulSize)
445 *pulSize = cbNeeded;
446 ppszThis = pEnv->papszVars;
447
448 // now copy each string
449 for (ul = 0;
450 ul < pEnv->cVars;
451 ul++)
452 {
453 PSZ pSource = *ppszThis;
454
455 while ((*pTarget++ = *pSource++))
456 ;
457
458 // *pTarget++ = 0; // append null terminator per string
459
460 // next environment string
461 ppszThis++;
462 }
463
464 *pTarget++ = 0; // append second null terminator
465 }
466 }
467
468 return (arc);
469}
470
471/*
472 *@@ appFreeEnvironment:
473 * frees memory allocated by appGetEnvironment.
474 *
475 *@@added V0.9.4 (2000-07-19) [umoeller]
476 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
477 */
478
479APIRET appFreeEnvironment(PDOSENVIRONMENT pEnv)
480{
481 APIRET arc = NO_ERROR;
482 if ( (!pEnv)
483 || (!pEnv->papszVars)
484 )
485 arc = ERROR_INVALID_PARAMETER;
486 else
487 {
488 PSZ *ppszThis = pEnv->papszVars;
489 PSZ pszThis;
490 ULONG ul = 0;
491
492 for (ul = 0;
493 ul < pEnv->cVars;
494 ul++)
495 {
496 pszThis = *ppszThis;
497 free(pszThis);
498 // *ppszThis = NULL;
499 // next environment string
500 ppszThis++;
501 }
502
503 free(pEnv->papszVars);
504 pEnv->cVars = 0;
505 }
506
507 return (arc);
508}
509
510/* ******************************************************************
511 *
512 * Application information
513 *
514 ********************************************************************/
515
516/*
517 *@@ appQueryAppType:
518 * returns the Control Program (Dos) and
519 * Win* PROG_* application types for the
520 * specified executable. Essentially, this
521 * is a wrapper around DosQueryAppType.
522 *
523 * pcszExecutable must be fully qualified.
524 * You can use doshFindExecutable to qualify
525 * it.
526 *
527 * This returns the APIRET of DosQueryAppType.
528 * If this is NO_ERROR; *pulDosAppType receives
529 * the app type of DosQueryAppType. In addition,
530 * *pulWinAppType is set to one of the following:
531 *
532 * -- PROG_FULLSCREEN
533 *
534 * -- PROG_PDD
535 *
536 * -- PROG_VDD
537 *
538 * -- PROG_DLL
539 *
540 * -- PROG_WINDOWEDVDM
541 *
542 * -- PROG_PM
543 *
544 * -- PROG_31_ENHSEAMLESSCOMMON
545 *
546 * -- PROG_WINDOWABLEVIO
547 *
548 * -- PROG_DEFAULT
549 *
550 *@@added V0.9.9 (2001-03-07) [umoeller]
551 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
552 *@@changed V0.9.14 (2001-08-07) [pr]: use FAPPTYP_* constants
553 *@@changed V0.9.16 (2001-12-08) [umoeller]: added checks for batch files, other optimizations
554 */
555
556APIRET appQueryAppType(const char *pcszExecutable,
557 PULONG pulDosAppType,
558 PULONG pulWinAppType)
559{
560 APIRET arc;
561
562/*
563 #define FAPPTYP_NOTSPEC 0x0000
564 #define FAPPTYP_NOTWINDOWCOMPAT 0x0001
565 #define FAPPTYP_WINDOWCOMPAT 0x0002
566 #define FAPPTYP_WINDOWAPI 0x0003
567 #define FAPPTYP_BOUND 0x0008
568 #define FAPPTYP_DLL 0x0010
569 #define FAPPTYP_DOS 0x0020
570 #define FAPPTYP_PHYSDRV 0x0040 // physical device driver
571 #define FAPPTYP_VIRTDRV 0x0080 // virtual device driver
572 #define FAPPTYP_PROTDLL 0x0100 // 'protected memory' dll
573 #define FAPPTYP_WINDOWSREAL 0x0200 // Windows real mode app
574 #define FAPPTYP_WINDOWSPROT 0x0400 // Windows protect mode app
575 #define FAPPTYP_WINDOWSPROT31 0x1000 // Windows 3.1 protect mode app
576 #define FAPPTYP_32BIT 0x4000
577*/
578
579 ULONG ulWinAppType = PROG_DEFAULT;
580
581 if (!(arc = DosQueryAppType((PSZ)pcszExecutable, pulDosAppType)))
582 {
583 // clear the 32-bit flag
584 // V0.9.16 (2001-12-08) [umoeller]
585 ULONG ulDosAppType = (*pulDosAppType) & ~FAPPTYP_32BIT,
586 ulLoAppType = ulDosAppType & 0xFFFF;
587
588 if (ulDosAppType & FAPPTYP_PHYSDRV) // 0x40
589 ulWinAppType = PROG_PDD;
590 else if (ulDosAppType & FAPPTYP_VIRTDRV) // 0x80
591 ulWinAppType = PROG_VDD;
592 else if ((ulDosAppType & 0xF0) == FAPPTYP_DLL) // 0x10
593 // DLL bit set
594 ulWinAppType = PROG_DLL;
595 else if (ulDosAppType & FAPPTYP_DOS) // 0x20
596 // DOS bit set?
597 ulWinAppType = PROG_WINDOWEDVDM;
598 else if ((ulDosAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) // 0x0003)
599 // "Window-API" == PM
600 ulWinAppType = PROG_PM;
601 else if (ulLoAppType == FAPPTYP_WINDOWSREAL)
602 ulWinAppType = PROG_31_ENHSEAMLESSCOMMON; // @@todo really?
603 else if ( (ulLoAppType == FAPPTYP_WINDOWSPROT31) // 0x1000) // windows program (?!?)
604 || (ulLoAppType == FAPPTYP_WINDOWSPROT) // ) // windows program (?!?)
605 )
606 ulWinAppType = PROG_31_ENHSEAMLESSCOMMON; // PROG_31_ENH;
607 else if ((ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_WINDOWCOMPAT) // 0x02)
608 ulWinAppType = PROG_WINDOWABLEVIO;
609 else if ((ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_NOTWINDOWCOMPAT) // 0x01)
610 ulWinAppType = PROG_FULLSCREEN;
611 }
612
613 if (ulWinAppType == PROG_DEFAULT)
614 {
615 // added checks for batch files V0.9.16 (2001-12-08) [umoeller]
616 PCSZ pcszExt;
617 if (pcszExt = doshGetExtension(pcszExecutable))
618 {
619 if (!stricmp(pcszExt, "BAT"))
620 {
621 ulWinAppType = PROG_WINDOWEDVDM;
622 arc = NO_ERROR;
623 }
624 else if (!stricmp(pcszExt, "CMD"))
625 {
626 ulWinAppType = PROG_WINDOWABLEVIO;
627 arc = NO_ERROR;
628 }
629 }
630 }
631
632 *pulWinAppType = ulWinAppType;
633
634 return (arc);
635}
636
637/*
638 *@@ appDescribeAppType:
639 * returns a "PROG_*" string for the given
640 * program type. Useful for WPProgram setup
641 * strings and such.
642 *
643 *@@added V0.9.16 (2001-10-06)
644 */
645
646PCSZ appDescribeAppType(PROGCATEGORY progc) // in: from PROGDETAILS.progc
647{
648 switch (progc)
649 {
650 case PROG_DEFAULT: return "PROG_DEFAULT";
651 case PROG_FULLSCREEN: return "PROG_FULLSCREEN";
652 case PROG_WINDOWABLEVIO: return "PROG_WINDOWABLEVIO";
653 case PROG_PM: return "PROG_PM";
654 case PROG_GROUP: return "PROG_GROUP";
655 case PROG_VDM: return "PROG_VDM";
656 // same as case PROG_REAL: return "PROG_REAL";
657 case PROG_WINDOWEDVDM: return "PROG_WINDOWEDVDM";
658 case PROG_DLL: return "PROG_DLL";
659 case PROG_PDD: return "PROG_PDD";
660 case PROG_VDD: return "PROG_VDD";
661 case PROG_WINDOW_REAL: return "PROG_WINDOW_REAL";
662 case PROG_30_STD: return "PROG_30_STD";
663 // same as case PROG_WINDOW_PROT: return "PROG_WINDOW_PROT";
664 case PROG_WINDOW_AUTO: return "PROG_WINDOW_AUTO";
665 case PROG_30_STDSEAMLESSVDM: return "PROG_30_STDSEAMLESSVDM";
666 // same as case PROG_SEAMLESSVDM: return "PROG_SEAMLESSVDM";
667 case PROG_30_STDSEAMLESSCOMMON: return "PROG_30_STDSEAMLESSCOMMON";
668 // same as case PROG_SEAMLESSCOMMON: return "PROG_SEAMLESSCOMMON";
669 case PROG_31_STDSEAMLESSVDM: return "PROG_31_STDSEAMLESSVDM";
670 case PROG_31_STDSEAMLESSCOMMON: return "PROG_31_STDSEAMLESSCOMMON";
671 case PROG_31_ENHSEAMLESSVDM: return "PROG_31_ENHSEAMLESSVDM";
672 case PROG_31_ENHSEAMLESSCOMMON: return "PROG_31_ENHSEAMLESSCOMMON";
673 case PROG_31_ENH: return "PROG_31_ENH";
674 case PROG_31_STD: return "PROG_31_STD";
675
676// Warp 4 toolkit defines, whatever these were designed for...
677#ifndef PROG_DOS_GAME
678 #define PROG_DOS_GAME (PROGCATEGORY)21
679#endif
680#ifndef PROG_WIN_GAME
681 #define PROG_WIN_GAME (PROGCATEGORY)22
682#endif
683#ifndef PROG_DOS_MODE
684 #define PROG_DOS_MODE (PROGCATEGORY)23
685#endif
686
687 case PROG_DOS_GAME: return "PROG_DOS_GAME";
688 case PROG_WIN_GAME: return "PROG_WIN_GAME";
689 case PROG_DOS_MODE: return "PROG_DOS_MODE";
690
691 // added this V0.9.16 (2001-12-08) [umoeller]
692 case PROG_WIN32: return "PROG_WIN32";
693 }
694
695 return NULL;
696}
697
698/*
699 *@@ appIsWindowsApp:
700 * checks the specified program category
701 * (PROGDETAILS.progt.progc) for whether
702 * it represents a Win-OS/2 application.
703 *
704 * Returns:
705 *
706 * -- 0: no windows app (it's VIO, OS/2
707 * or DOS fullscreen, or PM).
708 *
709 * -- 1: Win-OS/2 standard app.
710 *
711 * -- 2: Win-OS/2 enhanced-mode app.
712 *
713 *@@added V0.9.12 (2001-05-26) [umoeller]
714 */
715
716ULONG appIsWindowsApp(ULONG ulProgCategory)
717{
718 switch (ulProgCategory)
719 {
720 case PROG_31_ENHSEAMLESSVDM: // 17
721 case PROG_31_ENHSEAMLESSCOMMON: // 18
722 case PROG_31_ENH: // 19
723 return (2);
724
725#ifndef PROG_30_STD
726 #define PROG_30_STD (PROGCATEGORY)11
727#endif
728
729#ifndef PROG_30_STDSEAMLESSVDM
730 #define PROG_30_STDSEAMLESSVDM (PROGCATEGORY)13
731#endif
732
733 case PROG_WINDOW_REAL: // 10
734 case PROG_30_STD: // 11
735 case PROG_WINDOW_AUTO: // 12
736 case PROG_30_STDSEAMLESSVDM: // 13
737 case PROG_30_STDSEAMLESSCOMMON: // 14
738 case PROG_31_STDSEAMLESSVDM: // 15
739 case PROG_31_STDSEAMLESSCOMMON: // 16
740 case PROG_31_STD: // 20
741 return (1);
742 }
743
744 return (0);
745}
746
747/* ******************************************************************
748 *
749 * Application start
750 *
751 ********************************************************************/
752
753/*
754 *@@ CallBatchCorrectly:
755 * fixes the specified PROGDETAILS for
756 * command files in the executable part
757 * by inserting /C XXX into the parameters
758 * and setting the executable according
759 * to an environment variable.
760 *
761 *@@added V0.9.6 (2000-10-16) [umoeller]
762 *@@changed V0.9.7 (2001-01-15) [umoeller]: now using XSTRING
763 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
764 */
765
766VOID CallBatchCorrectly(PPROGDETAILS pProgDetails,
767 PXSTRING pstrParams, // in/out: modified parameters (reallocated)
768 const char *pcszEnvVar, // in: env var spec'g command proc
769 // (e.g. "OS2_SHELL"); can be NULL
770 const char *pcszDefProc) // in: def't command proc (e.g. "CMD.EXE")
771{
772 // XXX.CMD file as executable:
773 // fix args to /C XXX.CMD
774
775 PSZ pszOldParams = NULL;
776 ULONG ulOldParamsLength = pstrParams->ulLength;
777 if (ulOldParamsLength)
778 // we have parameters already:
779 // make a backup... we'll append that later
780 pszOldParams = strdup(pstrParams->psz);
781
782 // set new params to "/C filename.cmd"
783 xstrcpy(pstrParams, "/C ", 0);
784 xstrcat(pstrParams,
785 pProgDetails->pszExecutable,
786 0);
787
788 if (pszOldParams)
789 {
790 // .cmd had params:
791 // append space and old params
792 xstrcatc(pstrParams, ' ');
793 xstrcat(pstrParams,
794 pszOldParams,
795 ulOldParamsLength);
796 free(pszOldParams);
797 }
798
799 // set executable to $(OS2_SHELL)
800 pProgDetails->pszExecutable = NULL;
801 if (pcszEnvVar)
802 pProgDetails->pszExecutable = getenv(pcszEnvVar);
803 if (!pProgDetails->pszExecutable)
804 pProgDetails->pszExecutable = (PSZ)pcszDefProc;
805 // should be on PATH
806}
807
808/*
809 *@@ appQueryDefaultWin31Environment:
810 * returns the default Win-OS/2 3.1 environment
811 * from OS2.INI, which you can then merge with
812 * your process environment to be able to
813 * start Win-OS/2 sessions properly with
814 * appStartApp.
815 *
816 * Caller must free() the return value.
817 *
818 *@@added V0.9.12 (2001-05-26) [umoeller]
819 */
820
821PSZ appQueryDefaultWin31Environment(VOID)
822{
823 PSZ pszReturn = NULL;
824 ULONG ulSize = 0;
825 // get default environment (from Win-OS/2 settings object)
826 // from OS2.INI
827 PSZ pszDefEnv = prfhQueryProfileData(HINI_USER,
828 "WINOS2",
829 "PM_GlobalWindows31Settings",
830 &ulSize);
831 if (pszDefEnv)
832 {
833 if (pszReturn = (PSZ)malloc(ulSize + 2))
834 {
835 PSZ p;
836 memset(pszReturn, 0, ulSize + 2);
837 memcpy(pszReturn, pszDefEnv, ulSize);
838
839 for (p = pszReturn;
840 p < pszReturn + ulSize;
841 p++)
842 if (*p == ';')
843 *p = 0;
844
845 // okay.... now we got an OS/2-style environment
846 // with 0, 0, 00 strings
847 }
848
849 free(pszDefEnv);
850 }
851
852 return (pszReturn);
853}
854
855/*
856 *@@ appStartApp:
857 * wrapper around WinStartApp which fixes the
858 * specified PROGDETAILS to (hopefully) work
859 * work with all executable types.
860 *
861 * This fixes the executable info to support:
862 *
863 * -- starting "*" executables (command prompts
864 * for OS/2, DOS, Win-OS/2);
865 *
866 * -- starting ".CMD" and ".BAT" files as
867 * PROGDETAILS.pszExecutable;
868 *
869 * -- starting apps which are not fully qualified
870 * and therefore assumed to be on the PATH.
871 *
872 * Unless it is "*", PROGDETAILS.pszExecutable must
873 * be a proper file name. The full path may be omitted
874 * if it is on the PATH, but the extension (.EXE etc.)
875 * must be given. You can use doshFindExecutable to
876 * find executables if you don't know the extension.
877 *
878 * This also handles and merges special and default
879 * environments for the app to be started. The
880 * following should be respected:
881 *
882 * -- As with WinStartApp, if PROGDETAILS.pszEnvironment
883 * is NULL, the new app inherits a default environment
884 * from the shell.
885 *
886 * -- However, if you specify an environment, you _must_
887 * specify a complete environment. This function
888 * will not merge environments. Use
889 * appSetEnvironmentVar to change environment
890 * variables in a complete environment set.
891 *
892 * -- If PROGDETAILS specifies a Win-OS/2 session
893 * and PROGDETAILS.pszEnvironment is empty,
894 * this uses the default Win-OS/2 environment.
895 * See appQueryDefaultWin31Environment.
896 *
897 * Even though this isn't clearly said in PMREF,
898 * PROGDETAILS.swpInitial is important:
899 *
900 * -- To start a session minimized, set SWP_MINIMIZE.
901 *
902 * -- To start a VIO session with auto-close disabled,
903 * set the half-documented SWP_NOAUTOCLOSE flag (0x8000)
904 * This flag is now in the newer toolkit headers.
905 *
906 * In addition, this supports the following session
907 * flags with ulFlags if PROG_DEFAULT is specified:
908 *
909 * -- APP_RUN_FULLSCREEN
910 *
911 * -- APP_RUN_ENHANCED
912 *
913 * -- APP_RUN_STANDARD
914 *
915 * -- APP_RUN_SEPARATE
916 *
917 * Since this calls WinStartApp in turn, this
918 * requires a message queue on the calling thread.
919 *
920 * Note that this also does minimal checking on
921 * the specified parameters so it can return something
922 * more meaningful than FALSE like WinStartApp.
923 * As a result, you get a DOS error code now (V0.9.16).
924 *
925 * Most importantly:
926 *
927 * -- ERROR_INVALID_THREADID: not running on thread 1.
928 * Since this uses WinStartApp internally and
929 * WinStartApp completely hangs the session manager
930 * if a Win-OS/2 full-screen session is started from
931 * a thread that is NOT thread 1, this will now fail
932 * with this error for safety (V0.9.16).
933 *
934 * -- ERROR_INVALID_PARAMETER: pcProgDetails or
935 * phapp is NULL; or PROGDETAILS.pszExecutable is NULL.
936 *
937 * -- ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND:
938 * PROGDETAILS.pszExecutable and/or PROGDETAILS.pszStartupDir
939 * are invalid.
940 * A NULL PROGDETAILS.pszStartupDir is supported though.
941 *
942 * -- ERROR_NOT_ENOUGH_MEMORY
943 *
944 *@@added V0.9.6 (2000-10-16) [umoeller]
945 *@@changed V0.9.7 (2000-12-10) [umoeller]: PROGDETAILS.swpInitial no longer zeroed... this broke VIOs
946 *@@changed V0.9.7 (2000-12-17) [umoeller]: PROGDETAILS.pszEnvironment no longer zeroed
947 *@@changed V0.9.9 (2001-01-27) [umoeller]: crashed if PROGDETAILS.pszExecutable was NULL
948 *@@changed V0.9.12 (2001-05-26) [umoeller]: fixed PROG_DEFAULT
949 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
950 *@@changed V0.9.14 (2001-08-07) [pr]: removed some env. strings for Win. apps.
951 *@@changed V0.9.14 (2001-08-23) [pr]: added session type options
952 *@@changed V0.9.16 (2001-10-19) [umoeller]: added prototype to return APIRET
953 *@@changed V0.9.16 (2001-10-19) [umoeller]: added thread-1 check
954 *@@changed V0.9.16 (2001-12-06) [umoeller]: now using doshSearchPath for finding pszExecutable if not qualified
955 *@@changed V0.9.16 (2002-01-04) [umoeller]: removed error report if startup directory was drive letter only
956 *@@changed V0.9.16 (2002-01-04) [umoeller]: added more detailed error reports and *FailingName params
957 */
958
959APIRET appStartApp(HWND hwndNotify, // in: notify window or NULLHANDLE
960 const PROGDETAILS *pcProgDetails, // in: program spec (req.)
961 ULONG ulFlags, // in: APP_RUN_* flags
962 HAPP *phapp, // out: application handle if NO_ERROR is returned
963 ULONG cbFailingName,
964 PSZ pszFailingName)
965{
966 APIRET arc = NO_ERROR;
967 PROGDETAILS ProgDetails;
968
969 if (pszFailingName)
970 *pszFailingName = '\0';
971
972 if (!pcProgDetails || !phapp)
973 return (ERROR_INVALID_PARAMETER);
974
975 memcpy(&ProgDetails, pcProgDetails, sizeof(PROGDETAILS));
976 // pointers still point into old prog details buffer
977 ProgDetails.Length = sizeof(PROGDETAILS);
978 ProgDetails.progt.fbVisible = SHE_VISIBLE;
979
980 // all this only makes sense if this contains something...
981 // besides, this crashed on string comparisons V0.9.9 (2001-01-27) [umoeller]
982 if ( (!ProgDetails.pszExecutable)
983 || (!(*(ProgDetails.pszExecutable)))
984 )
985 arc = ERROR_INVALID_PARAMETER;
986 else if (doshMyTID() != 1) // V0.9.16 (2001-10-19) [umoeller]
987 arc = ERROR_INVALID_THREADID;
988 else
989 {
990 ULONG ulIsWinApp;
991
992 CHAR szFQExecutable[CCHMAXPATH];
993
994 XSTRING strParamsPatched;
995 PSZ pszWinOS2Env = 0;
996
997 // memset(&ProgDetails.swpInitial, 0, sizeof(SWP));
998 // this wasn't a good idea... WPProgram stores stuff
999 // in here, such as the "minimize on startup" -> SWP_MINIMIZE
1000
1001 // duplicate parameters...
1002 // we need this for string manipulations below...
1003 if (ProgDetails.pszParameters)
1004 xstrInitCopy(&strParamsPatched,
1005 ProgDetails.pszParameters,
1006 100);
1007 else
1008 // no old params:
1009 xstrInit(&strParamsPatched, 100);
1010
1011 // _Pmpf((__FUNCTION__ ": old progc: 0x%lX", pcProgDetails->progt.progc));
1012 // _Pmpf((" pszTitle: %s", (ProgDetails.pszTitle) ? ProgDetails.pszTitle : NULL));
1013 // _Pmpf((" pszIcon: %s", (ProgDetails.pszIcon) ? ProgDetails.pszIcon : NULL));
1014
1015 // program type fixups
1016 switch (ProgDetails.progt.progc) // that's a ULONG
1017 {
1018 case ((ULONG)-1): // we get that sometimes...
1019 case PROG_DEFAULT:
1020 {
1021 // V0.9.12 (2001-05-26) [umoeller]
1022 ULONG ulDosAppType;
1023 appQueryAppType(ProgDetails.pszExecutable,
1024 &ulDosAppType,
1025 &ProgDetails.progt.progc);
1026 }
1027 break;
1028 }
1029
1030 // set session type from option flags
1031 if (ulFlags & APP_RUN_FULLSCREEN)
1032 {
1033 if (ProgDetails.progt.progc == PROG_WINDOWABLEVIO)
1034 ProgDetails.progt.progc = PROG_FULLSCREEN;
1035
1036 if (ProgDetails.progt.progc == PROG_WINDOWEDVDM)
1037 ProgDetails.progt.progc = PROG_VDM;
1038 }
1039
1040 if (ulIsWinApp = appIsWindowsApp(ProgDetails.progt.progc))
1041 {
1042 if (ulFlags & APP_RUN_FULLSCREEN)
1043 ProgDetails.progt.progc = (ulFlags & APP_RUN_ENHANCED)
1044 ? PROG_31_ENH
1045 : PROG_31_STD;
1046 else
1047 {
1048 if (ulFlags & APP_RUN_STANDARD)
1049 ProgDetails.progt.progc = (ulFlags & APP_RUN_SEPARATE)
1050 ? PROG_31_STDSEAMLESSVDM
1051 : PROG_31_STDSEAMLESSCOMMON;
1052
1053 if (ulFlags & APP_RUN_ENHANCED)
1054 ProgDetails.progt.progc = (ulFlags & APP_RUN_SEPARATE)
1055 ? PROG_31_ENHSEAMLESSVDM
1056 : PROG_31_ENHSEAMLESSCOMMON;
1057 }
1058
1059 // re-run V0.9.16 (2001-10-19) [umoeller]
1060 ulIsWinApp = appIsWindowsApp(ProgDetails.progt.progc);
1061 }
1062
1063 /*
1064 * command lines fixups:
1065 *
1066 */
1067
1068 if (!strcmp(ProgDetails.pszExecutable, "*"))
1069 {
1070 /*
1071 * "*" for command sessions:
1072 *
1073 */
1074
1075 if (ulIsWinApp == 2)
1076 {
1077 // enhanced Win-OS/2 session:
1078 PSZ psz = NULL;
1079 if (strParamsPatched.ulLength)
1080 // "/3 " + existing params
1081 psz = strdup(strParamsPatched.psz);
1082
1083 xstrcpy(&strParamsPatched, "/3 ", 0);
1084
1085 if (psz)
1086 {
1087 xstrcat(&strParamsPatched, psz, 0);
1088 free(psz);
1089 }
1090 }
1091
1092 if (ulIsWinApp)
1093 {
1094 // cheat: WinStartApp doesn't support NULL
1095 // for Win-OS2 sessions, so manually start winos2.com
1096 ProgDetails.pszExecutable = "WINOS2.COM";
1097 // this is a DOS app, so fix this to DOS fullscreen
1098 ProgDetails.progt.progc = PROG_VDM;
1099 }
1100 else
1101 // for all other executable types
1102 // (including OS/2 and DOS sessions),
1103 // set pszExecutable to NULL; this will
1104 // have WinStartApp start a cmd shell
1105 ProgDetails.pszExecutable = NULL;
1106
1107 } // end if (strcmp(pProgDetails->pszExecutable, "*") == 0)
1108 else
1109 {
1110 // check if the executable is fully qualified; if so,
1111 // check if the executable file exists
1112 if ( (ProgDetails.pszExecutable[1] == ':')
1113 && (strchr(ProgDetails.pszExecutable, '\\'))
1114 )
1115 {
1116 ULONG ulAttr;
1117 if (!(arc = doshQueryPathAttr(ProgDetails.pszExecutable,
1118 &ulAttr)))
1119 {
1120 // make sure startup dir is really a directory
1121 if (ProgDetails.pszStartupDir)
1122 {
1123 // it is valid to specify a startup dir of "C:"
1124 if ( (strlen(ProgDetails.pszStartupDir) > 2)
1125 && (!(arc = doshQueryPathAttr(ProgDetails.pszStartupDir,
1126 &ulAttr)))
1127 && (!(ulAttr & FILE_DIRECTORY))
1128 )
1129 arc = ERROR_PATH_NOT_FOUND;
1130 }
1131 }
1132 }
1133 else
1134 {
1135 // _not_ fully qualified: look it up on the PATH then
1136 // V0.9.16 (2001-12-06) [umoeller]
1137 if (!(arc = doshSearchPath("PATH",
1138 ProgDetails.pszExecutable,
1139 szFQExecutable,
1140 sizeof(szFQExecutable))))
1141 // alright, found it:
1142 ProgDetails.pszExecutable = szFQExecutable;
1143 }
1144
1145 if (!arc)
1146 {
1147 PSZ pszExtension;
1148 switch (ProgDetails.progt.progc)
1149 {
1150 /*
1151 * .CMD files fixups
1152 *
1153 */
1154
1155 case PROG_FULLSCREEN: // OS/2 fullscreen
1156 case PROG_WINDOWABLEVIO: // OS/2 window
1157 {
1158 if ( (pszExtension = doshGetExtension(ProgDetails.pszExecutable))
1159 && (!stricmp(pszExtension, "CMD"))
1160 )
1161 {
1162 CallBatchCorrectly(&ProgDetails,
1163 &strParamsPatched,
1164 "OS2_SHELL",
1165 "CMD.EXE");
1166 }
1167 break; }
1168
1169 case PROG_VDM: // DOS fullscreen
1170 case PROG_WINDOWEDVDM: // DOS window
1171 {
1172 if ( (pszExtension = doshGetExtension(ProgDetails.pszExecutable))
1173 && (!stricmp(pszExtension, "BAT"))
1174 )
1175 {
1176 CallBatchCorrectly(&ProgDetails,
1177 &strParamsPatched,
1178 NULL,
1179 "COMMAND.COM");
1180 }
1181 break; }
1182 } // end switch (ProgDetails.progt.progc)
1183 }
1184 }
1185
1186 if (!arc)
1187 {
1188 if ( (ulIsWinApp)
1189 && ( (ProgDetails.pszEnvironment == NULL)
1190 || (!strlen(ProgDetails.pszEnvironment))
1191 )
1192 )
1193 {
1194 // this is a windoze app, and caller didn't bother
1195 // to give us an environment:
1196 // we MUST set one then, or we'll get the strangest
1197 // errors, up to system hangs. V0.9.12 (2001-05-26) [umoeller]
1198
1199 DOSENVIRONMENT Env = {0};
1200
1201 // get standard WIN-OS/2 environment
1202 PSZ pszTemp = appQueryDefaultWin31Environment();
1203
1204 if (!(arc = appParseEnvironment(pszTemp,
1205 &Env)))
1206 {
1207 // now override KBD_CTRL_BYPASS=CTRL_ESC
1208 if ( (!(arc = appSetEnvironmentVar(&Env,
1209 "KBD_CTRL_BYPASS=CTRL_ESC",
1210 FALSE))) // add last
1211 && (!(arc = appConvertEnvironment(&Env,
1212 &pszWinOS2Env, // freed at bottom
1213 NULL)))
1214 )
1215 ProgDetails.pszEnvironment = pszWinOS2Env;
1216
1217 appFreeEnvironment(&Env);
1218 }
1219
1220 free(pszTemp);
1221 }
1222
1223 if (!arc)
1224 {
1225 if (!ProgDetails.pszTitle)
1226 ProgDetails.pszTitle = ProgDetails.pszExecutable;
1227
1228 ProgDetails.pszParameters = strParamsPatched.psz;
1229
1230 _Pmpf((__FUNCTION__ ": progt.progc: %d", ProgDetails.progt.progc));
1231 _Pmpf((" progt.fbVisible: 0x%lX", ProgDetails.progt.fbVisible));
1232 _Pmpf((" progt.pszTitle: \"%s\"", (ProgDetails.pszTitle) ? ProgDetails.pszTitle : "NULL"));
1233 _Pmpf((" exec: \"%s\"", (ProgDetails.pszExecutable) ? ProgDetails.pszExecutable : "NULL"));
1234 _Pmpf((" params: \"%s\"", (ProgDetails.pszParameters) ? ProgDetails.pszParameters : "NULL"));
1235 _Pmpf((" startup: \"%s\"", (ProgDetails.pszStartupDir) ? ProgDetails.pszStartupDir : "NULL"));
1236 _Pmpf((" pszIcon: \"%s\"", (ProgDetails.pszIcon) ? ProgDetails.pszIcon : "NULL"));
1237 /* _Pmpf((" environment: "));
1238 {
1239 PSZ pszThis = ProgDetails.pszEnvironment;
1240 while (pszThis && *pszThis)
1241 {
1242 _Pmpf((" \"%s\"", pszThis));
1243 pszThis += strlen(pszThis) + 1;
1244 }
1245 }
1246 */
1247
1248 _Pmpf((" swpInitial.fl = 0x%lX, x = %d, y = %d, cx = %d, cy = %d:",
1249 ProgDetails.swpInitial.fl,
1250 ProgDetails.swpInitial.x,
1251 ProgDetails.swpInitial.y,
1252 ProgDetails.swpInitial.cx,
1253 ProgDetails.swpInitial.cy));
1254 _Pmpf((" behind = %d, hwnd = %d, res1 = %d, res2 = %d",
1255 ProgDetails.swpInitial.hwndInsertBehind,
1256 ProgDetails.swpInitial.hwnd,
1257 ProgDetails.swpInitial.ulReserved1,
1258 ProgDetails.swpInitial.ulReserved2));
1259
1260 if (pszFailingName)
1261 strhncpy0(pszFailingName, ProgDetails.pszExecutable, cbFailingName);
1262
1263 /* if (WinMessageBox(HWND_DESKTOP,
1264 NULLHANDLE,
1265 (ProgDetails.pszExecutable) ? ProgDetails.pszExecutable : "NULL",
1266 "Start?",
1267 0,
1268 MB_YESNO | MB_MOVEABLE)
1269 != MBID_YES)
1270 arc = ERROR_INTERRUPT;
1271 else */
1272 {
1273 if (!(*phapp = WinStartApp(hwndNotify,
1274 // receives WM_APPTERMINATENOTIFY
1275 &ProgDetails,
1276 strParamsPatched.psz,
1277 NULL, // "reserved", PMREF says...
1278 SAF_INSTALLEDCMDLINE)))
1279 // we MUST use SAF_INSTALLEDCMDLINE
1280 // or no Win-OS/2 session will start...
1281 // whatever is going on here... Warp 4 FP11
1282
1283 // do not use SAF_STARTCHILDAPP, or the
1284 // app will be terminated automatically
1285 // when the WPS terminates!
1286 {
1287 // cannot start app:
1288 _Pmpf((__FUNCTION__ ": WinStartApp failed"));
1289 arc = ERROR_FILE_NOT_FOUND;
1290 // unfortunately WinStartApp doesn't
1291 // return meaningful codes like DosStartSession, so
1292 // try to see what happened
1293 /*
1294 switch (ERRORIDERROR(WinGetLastError(0)))
1295 {
1296 case PMERR_DOS_ERROR: // (0x1200)
1297 {
1298 arc = ERROR_FILE_NOT_FOUND;
1299
1300 // this is probably the case where the module
1301 // couldn't be loaded, so try DosStartSession
1302 // to get a meaningful return code... note that
1303 // this cannot handle hwndNotify then
1304 /* RESULTCODES result;
1305 arc = DosExecPgm(pszFailingName,
1306 cbFailingName,
1307 EXEC_ASYNC,
1308 NULL, // ProgDetails.pszParameters,
1309 NULL, // ProgDetails.pszEnvironment,
1310 &result,
1311 ProgDetails.pszExecutable);
1312 */
1313 /* ULONG sid, pid;
1314 STARTDATA SData;
1315 SData.Length = sizeof(STARTDATA);
1316 SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
1317 SData.FgBg = SSF_FGBG_FORE;
1318 SData.TraceOpt = SSF_TRACEOPT_NONE;
1319
1320 SData.PgmTitle = ProgDetails.pszTitle;
1321 SData.PgmName = ProgDetails.pszExecutable;
1322 SData.PgmInputs = ProgDetails.pszParameters;
1323
1324 SData.TermQ = NULL;
1325 SData.Environment = ProgDetails.pszEnvironment;
1326 SData.InheritOpt = SSF_INHERTOPT_PARENT; // ignored
1327 SData.SessionType = SSF_TYPE_DEFAULT;
1328 SData.IconFile = 0;
1329 SData.PgmHandle = 0;
1330
1331 SData.PgmControl = SSF_CONTROL_VISIBLE;
1332
1333 SData.InitXPos = 30;
1334 SData.InitYPos = 40;
1335 SData.InitXSize = 200;
1336 SData.InitYSize = 140;
1337 SData.Reserved = 0;
1338 SData.ObjectBuffer = pszFailingName;
1339 SData.ObjectBuffLen = cbFailingName;
1340
1341 arc = DosStartSession(&SData, &sid, &pid);
1342 }
1343 break;
1344
1345 case PMERR_INVALID_APPL: // (0x1530)
1346 // Attempted to start an application whose type is not
1347 // recognized by OS/2.
1348 arc = ERROR_INVALID_EXE_SIGNATURE;
1349 break;
1350
1351 case PMERR_INVALID_PARAMETERS: // (0x1208)
1352 // An application parameter value is invalid for
1353 // its converted PM type. For example: a 4-byte
1354 // value outside the range -32 768 to +32 767 cannot be
1355 // converted to a SHORT, and a negative number cannot
1356 // be converted to a ULONG or USHORT.
1357 arc = ERROR_INVALID_DATA;
1358 break;
1359
1360 case PMERR_STARTED_IN_BACKGROUND: // (0x1532)
1361 // The application started a new session in the
1362 // background.
1363 arc = ERROR_SMG_START_IN_BACKGROUND;
1364 break;
1365
1366 case PMERR_INVALID_WINDOW: // (0x1206)
1367 // The window specified with a Window List call
1368 // is not a valid frame window.
1369
1370 default:
1371 arc = ERROR_BAD_FORMAT;
1372 break;
1373 }
1374 */
1375 }
1376 }
1377 }
1378 }
1379
1380 xstrClear(&strParamsPatched);
1381 if (pszWinOS2Env)
1382 free(pszWinOS2Env);
1383 } // end if (ProgDetails.pszExecutable)
1384
1385 _Pmpf((__FUNCTION__ ": returning %d", arc));
1386
1387 return (arc);
1388}
1389
1390/*
1391 *@@ appWaitForApp:
1392 * waits for the specified application to terminate
1393 * and returns its exit code.
1394 *
1395 *@@added V0.9.9 (2001-03-07) [umoeller]
1396 */
1397
1398BOOL appWaitForApp(HWND hwndNotify, // in: notify window
1399 HAPP happ, // in: app to wait for
1400 PULONG pulExitCode) // out: exit code (ptr can be NULL)
1401{
1402 BOOL brc = FALSE;
1403
1404 if (happ)
1405 {
1406 // app started:
1407 // enter a modal message loop until we get the
1408 // WM_APPTERMINATENOTIFY for happ. Then we
1409 // know the app is done.
1410 HAB hab = WinQueryAnchorBlock(hwndNotify);
1411 QMSG qmsg;
1412 // ULONG ulXFixReturnCode = 0;
1413 while (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0))
1414 {
1415 if ( (qmsg.msg == WM_APPTERMINATENOTIFY)
1416 && (qmsg.hwnd == hwndNotify)
1417 && (qmsg.mp1 == (MPARAM)happ)
1418 )
1419 {
1420 // xfix has terminated:
1421 // get xfix return code from mp2... this is:
1422 // -- 0: everything's OK, continue.
1423 // -- 1: handle section was rewritten, restart Desktop
1424 // now.
1425 if (pulExitCode)
1426 *pulExitCode = (ULONG)qmsg.mp2;
1427 brc = TRUE;
1428 // do not dispatch this
1429 break;
1430 }
1431
1432 WinDispatchMsg(hab, &qmsg);
1433 }
1434 }
1435
1436 return (brc);
1437}
1438
1439/*
1440 *@@ appQuickStartApp:
1441 * shortcut for simply starting an app and
1442 * waiting until it's finished.
1443 *
1444 * On errors, NULLHANDLE is returned.
1445 *
1446 * If pulReturnCode != NULL, it receives the
1447 * return code of the app.
1448 *
1449 *@@added V0.9.16 (2001-10-19) [umoeller]
1450 */
1451
1452HAPP appQuickStartApp(const char *pcszFile,
1453 ULONG ulProgType, // e.g. PROG_PM
1454 const char *pcszArgs,
1455 PULONG pulExitCode)
1456{
1457 PROGDETAILS pd = {0};
1458 HAPP happ,
1459 happReturn = NULLHANDLE;
1460 CHAR szDir[CCHMAXPATH] = "";
1461 PCSZ p;
1462 HWND hwndObject;
1463
1464 pd.Length = sizeof(pd);
1465 pd.progt.progc = ulProgType;
1466 pd.progt.fbVisible = SHE_VISIBLE;
1467 pd.pszExecutable = (PSZ)pcszFile;
1468 pd.pszParameters = (PSZ)pcszArgs;
1469 if (p = strrchr(pcszFile, '\\'))
1470 {
1471 strhncpy0(szDir,
1472 pcszFile,
1473 p - pcszFile);
1474 pd.pszStartupDir = szDir;
1475 }
1476
1477 if ( (hwndObject = winhCreateObjectWindow(WC_STATIC, NULL))
1478 && (!appStartApp(hwndObject,
1479 &pd,
1480 0,
1481 &happ,
1482 0,
1483 NULL))
1484 )
1485 {
1486 if (appWaitForApp(hwndObject,
1487 happ,
1488 pulExitCode))
1489 happReturn = happ;
1490 }
1491
1492 return (happReturn);
1493}
Note: See TracBrowser for help on using the repository browser.