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

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

Lots of updates from the last week for conditional compiles and other stuff.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 39.0 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_DOSSESMGR
36#define INCL_DOSERRORS
37
38#define INCL_WINPROGRAMLIST // needed for PROGDETAILS, wppgm.h
39#include <os2.h>
40
41#include <stdio.h>
42
43#include "setup.h" // code generation and debugging options
44
45#include "helpers\apps.h"
46#include "helpers\dosh.h"
47#include "helpers\prfh.h"
48#include "helpers\stringh.h"
49#include "helpers\xstring.h"
50
51/*
52 *@@category: Helpers\PM helpers\Application helpers
53 */
54
55/* ******************************************************************
56 *
57 * Environment helpers
58 *
59 ********************************************************************/
60
61/*
62 *@@ appParseEnvironment:
63 * this takes one of those ugly environment strings
64 * as used by DosStartSession and WinStartApp (with
65 * lots of zero-terminated strings one after another
66 * and a duplicate zero byte as a terminator) as
67 * input and splits it into an array of separate
68 * strings in pEnv.
69 *
70 * The newly allocated strings are stored in in
71 * pEnv->papszVars. The array count is stored in
72 * pEnv->cVars.
73 *
74 * Each environment variable will be copied into
75 * one newly allocated string in the array. Use
76 * appFreeEnvironment to free the memory allocated
77 * by this function.
78 *
79 * Use the following code to browse thru the array:
80 +
81 + DOSENVIRONMENT Env = {0};
82 + if (appParseEnvironment(pszEnv,
83 + &Env)
84 + == NO_ERROR)
85 + {
86 + if (Env.papszVars)
87 + {
88 + PSZ *ppszThis = Env.papszVars;
89 + for (ul = 0;
90 + ul < Env.cVars;
91 + ul++)
92 + {
93 + PSZ pszThis = *ppszThis;
94 + // pszThis now has something like PATH=C:\TEMP
95 + // ...
96 + // next environment string
97 + ppszThis++;
98 + }
99 + }
100 + appFreeEnvironment(&Env);
101 + }
102 *
103 *@@added V0.9.4 (2000-08-02) [umoeller]
104 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
105 */
106
107APIRET appParseEnvironment(const char *pcszEnv,
108 PDOSENVIRONMENT pEnv)
109{
110 APIRET arc = NO_ERROR;
111 if (!pcszEnv)
112 arc = ERROR_INVALID_PARAMETER;
113 else
114 {
115 PSZ pszVarThis = (PSZ)pcszEnv;
116 ULONG cVars = 0;
117 // count strings
118 while (*pszVarThis)
119 {
120 cVars++;
121 pszVarThis += strlen(pszVarThis) + 1;
122 }
123
124 pEnv->cVars = cVars;
125 pEnv->papszVars = 0;
126
127 if (cVars)
128 {
129 PSZ *papsz = (PSZ*)malloc(sizeof(PSZ) * cVars);
130 if (!papsz)
131 arc = ERROR_NOT_ENOUGH_MEMORY;
132 else
133 {
134 PSZ *ppszTarget = papsz;
135 memset(papsz, 0, sizeof(PSZ) * cVars);
136 pszVarThis = (PSZ)pcszEnv;
137 while (*pszVarThis)
138 {
139 *ppszTarget = strdup(pszVarThis);
140 ppszTarget++;
141 pszVarThis += strlen(pszVarThis) + 1;
142 }
143
144 pEnv->papszVars = papsz;
145 }
146 }
147 }
148
149 return (arc);
150}
151
152/*
153 *@@ appGetEnvironment:
154 * calls appParseEnvironment for the current
155 * process environment, which is retrieved from
156 * the info blocks.
157 *
158 *@@added V0.9.4 (2000-07-19) [umoeller]
159 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
160 */
161
162APIRET appGetEnvironment(PDOSENVIRONMENT pEnv)
163{
164 APIRET arc = NO_ERROR;
165 if (!pEnv)
166 arc = ERROR_INVALID_PARAMETER;
167 else
168 {
169 PTIB ptib = 0;
170 PPIB ppib = 0;
171 arc = DosGetInfoBlocks(&ptib, &ppib);
172 if (arc == NO_ERROR)
173 {
174 PSZ pszEnv = ppib->pib_pchenv;
175 if (pszEnv)
176 arc = appParseEnvironment(pszEnv, pEnv);
177 else
178 arc = ERROR_BAD_ENVIRONMENT;
179 }
180 }
181
182 return (arc);
183}
184
185/*
186 *@@ appFindEnvironmentVar:
187 * returns the PSZ* in the pEnv->papszVars array
188 * which specifies the environment variable in pszVarName.
189 *
190 * With pszVarName, you can either specify the variable
191 * name only ("VARNAME") or a full environment string
192 * ("VARNAME=BLAH"). In any case, only the variable name
193 * is compared.
194 *
195 * Returns NULL if no such variable name was found in
196 * the array.
197 *
198 *@@added V0.9.4 (2000-07-19) [umoeller]
199 *@@changed V0.9.12 (2001-05-21) [umoeller]: fixed memory leak
200 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
201 */
202
203PSZ* appFindEnvironmentVar(PDOSENVIRONMENT pEnv,
204 PSZ pszVarName)
205{
206 PSZ *ppszRet = 0;
207 if (pEnv)
208 {
209 if ((pEnv->papszVars) && (pszVarName))
210 {
211 PSZ *ppszThis = pEnv->papszVars;
212 // PSZ pszThis;
213 ULONG ul = 0;
214 ULONG ulVarNameLen = 0;
215
216 PSZ pszSearch = NULL; // receives "VARNAME="
217 PSZ pFirstEqual = strchr(pszVarName, '=');
218 if (pFirstEqual)
219 pszSearch = strhSubstr(pszVarName, pFirstEqual + 1);
220 else
221 {
222 ulVarNameLen = strlen(pszVarName);
223 pszSearch = (PSZ)malloc(ulVarNameLen + 2);
224 memcpy(pszSearch, pszVarName, ulVarNameLen);
225 *(pszSearch + ulVarNameLen) = '=';
226 *(pszSearch + ulVarNameLen + 1) = 0;
227 }
228
229 ulVarNameLen = strlen(pszSearch);
230
231 for (ul = 0;
232 ul < pEnv->cVars;
233 ul++)
234 {
235 if (strnicmp(*ppszThis, pszSearch, ulVarNameLen) == 0)
236 {
237 ppszRet = ppszThis;
238 break;
239 }
240
241 // next environment string
242 ppszThis++;
243 }
244
245 free(pszSearch); // was missing V0.9.12 (2001-05-21) [umoeller]
246 }
247 }
248
249 return (ppszRet);
250}
251
252/*
253 *@@ appSetEnvironmentVar:
254 * sets an environment variable in the specified
255 * environment, which must have been initialized
256 * using appGetEnvironment first.
257 *
258 * pszNewEnv must be a full environment string
259 * in the form "VARNAME=VALUE".
260 *
261 * If "VARNAME" has already been set to something
262 * in the string array in pEnv, that array item
263 * is replaced.
264 *
265 * OTOH, if "VARNAME" has not been set yet, a new
266 * item is added to the array, and pEnv->cVars is
267 * raised by one. In that case, fAddFirst determines
268 * whether the new array item is added to the front
269 * or the tail of the environment list.
270 *
271 *@@added V0.9.4 (2000-07-19) [umoeller]
272 *@@changed V0.9.7 (2000-12-17) [umoeller]: added fAddFirst
273 *@@changed V0.9.12 (2001-05-21) [umoeller]: fixed memory leak
274 *@@changed V0.9.12 (2001-05-26) [umoeller]: fixed crash if !fAddFirst
275 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
276 */
277
278APIRET appSetEnvironmentVar(PDOSENVIRONMENT pEnv,
279 PSZ pszNewEnv,
280 BOOL fAddFirst)
281{
282 APIRET arc = NO_ERROR;
283 if ((!pEnv) || (!pszNewEnv))
284 arc = ERROR_INVALID_PARAMETER;
285 else
286 {
287 if (!pEnv->papszVars)
288 {
289 // no variables set yet:
290 pEnv->papszVars = (PSZ*)malloc(sizeof(PSZ));
291 pEnv->cVars = 1;
292
293 *(pEnv->papszVars) = strdup(pszNewEnv);
294 }
295 else
296 {
297 PSZ *ppszEnvLine = appFindEnvironmentVar(pEnv, pszNewEnv);
298 if (ppszEnvLine)
299 {
300 // was set already: replace
301 free(*ppszEnvLine);
302 *ppszEnvLine = strdup(pszNewEnv);
303 if (!(*ppszEnvLine))
304 arc = ERROR_NOT_ENOUGH_MEMORY;
305 }
306 else
307 {
308 // not set already:
309 PSZ *ppszNew = NULL;
310
311 // allocate new array, with one new entry
312 // fixed V0.9.12 (2001-05-26) [umoeller], this crashed
313 PSZ *papszNew = (PSZ*)malloc(sizeof(PSZ) * (pEnv->cVars + 1));
314
315 if (!papszNew)
316 arc = ERROR_NOT_ENOUGH_MEMORY;
317 else
318 {
319 if (fAddFirst)
320 {
321 // add as first entry:
322 // overwrite first entry
323 ppszNew = papszNew;
324 // copy old entries
325 memcpy(papszNew + 1, // second new entry
326 pEnv->papszVars, // first old entry
327 sizeof(PSZ) * pEnv->cVars);
328 }
329 else
330 {
331 // append at the tail:
332 // overwrite last entry
333 ppszNew = papszNew + pEnv->cVars;
334 // copy old entries
335 memcpy(papszNew, // first new entry
336 pEnv->papszVars, // first old entry
337 sizeof(PSZ) * pEnv->cVars);
338 }
339
340 if (pEnv->papszVars)
341 free(pEnv->papszVars); // was missing V0.9.12 (2001-05-21) [umoeller]
342
343 pEnv->papszVars = papszNew;
344 pEnv->cVars++;
345 *ppszNew = strdup(pszNewEnv);
346 }
347 }
348 }
349 }
350
351 return (arc);
352}
353
354/*
355 *@@ appConvertEnvironment:
356 * converts an environment initialized by appGetEnvironment
357 * to the string format required by WinStartApp and DosExecPgm,
358 * that is, one memory block is allocated in *ppszEnv and all
359 * strings in pEnv->papszVars are copied to that block. Each
360 * string is terminated with a null character; the last string
361 * is terminated with two null characters.
362 *
363 * Use free() to free the memory block allocated by this
364 * function in *ppszEnv.
365 *
366 *@@added V0.9.4 (2000-07-19) [umoeller]
367 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
368 */
369
370APIRET appConvertEnvironment(PDOSENVIRONMENT pEnv,
371 PSZ *ppszEnv, // out: environment string
372 PULONG pulSize) // out: size of block allocated in *ppszEnv; ptr can be NULL
373{
374 APIRET arc = NO_ERROR;
375 if (!pEnv)
376 arc = ERROR_INVALID_PARAMETER;
377 else
378 {
379 if (!pEnv->papszVars)
380 arc = ERROR_INVALID_PARAMETER;
381 else
382 {
383 // count memory needed for all strings
384 ULONG cbNeeded = 0,
385 ul = 0;
386 PSZ *ppszThis = pEnv->papszVars;
387
388 for (ul = 0;
389 ul < pEnv->cVars;
390 ul++)
391 {
392 cbNeeded += strlen(*ppszThis) + 1; // length of string plus null terminator
393
394 // next environment string
395 ppszThis++;
396 }
397
398 cbNeeded++; // for another null terminator
399
400 *ppszEnv = (PSZ)malloc(cbNeeded);
401 if (!(*ppszEnv))
402 arc = ERROR_NOT_ENOUGH_MEMORY;
403 else
404 {
405 PSZ pTarget = *ppszEnv;
406 if (pulSize)
407 *pulSize = cbNeeded;
408 ppszThis = pEnv->papszVars;
409
410 // now copy each string
411 for (ul = 0;
412 ul < pEnv->cVars;
413 ul++)
414 {
415 PSZ pSource = *ppszThis;
416
417 while ((*pTarget++ = *pSource++))
418 ;
419
420 // *pTarget++ = 0; // append null terminator per string
421
422 // next environment string
423 ppszThis++;
424 }
425
426 *pTarget++ = 0; // append second null terminator
427 }
428 }
429 }
430
431 return (arc);
432}
433
434/*
435 *@@ appFreeEnvironment:
436 * frees memory allocated by appGetEnvironment.
437 *
438 *@@added V0.9.4 (2000-07-19) [umoeller]
439 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
440 */
441
442APIRET appFreeEnvironment(PDOSENVIRONMENT pEnv)
443{
444 APIRET arc = NO_ERROR;
445 if (!pEnv)
446 arc = ERROR_INVALID_PARAMETER;
447 else
448 {
449 if (!pEnv->papszVars)
450 arc = ERROR_INVALID_PARAMETER;
451 else
452 {
453 PSZ *ppszThis = pEnv->papszVars;
454 PSZ pszThis;
455 ULONG ul = 0;
456
457 for (ul = 0;
458 ul < pEnv->cVars;
459 ul++)
460 {
461 pszThis = *ppszThis;
462 free(pszThis);
463 // *ppszThis = NULL;
464 // next environment string
465 ppszThis++;
466 }
467
468 free(pEnv->papszVars);
469 pEnv->cVars = 0;
470 }
471 }
472
473 return (arc);
474}
475
476/* ******************************************************************
477 *
478 * Application information
479 *
480 ********************************************************************/
481
482/*
483 *@@ appQueryAppType:
484 * returns the Control Program (Dos) and
485 * Win* PROG_* application types for the
486 * specified executable. Essentially, this
487 * is a wrapper around DosQueryAppType.
488 *
489 * pcszExecutable must be fully qualified.
490 * You can use doshFindExecutable to qualify
491 * it.
492 *
493 * This returns the APIRET of DosQueryAppType.
494 * If this is NO_ERROR; *pulDosAppType receives
495 * the app type of DosQueryAppType. In addition,
496 * *pulWinAppType is set to one of the following:
497 *
498 * -- PROG_FULLSCREEN
499 *
500 * -- PROG_PDD
501 *
502 * -- PROG_VDD
503 *
504 * -- PROG_DLL
505 *
506 * -- PROG_WINDOWEDVDM
507 *
508 * -- PROG_PM
509 *
510 * -- PROG_31_ENHSEAMLESSCOMMON
511 *
512 * -- PROG_WINDOWABLEVIO
513 *
514 *@@added V0.9.9 (2001-03-07) [umoeller]
515 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
516 *@@changed V0.9.14 (2001-08-07) [pr]: use FAPPTYP_* constants
517 */
518
519APIRET appQueryAppType(const char *pcszExecutable,
520 PULONG pulDosAppType,
521 PULONG pulWinAppType)
522{
523 APIRET arc = DosQueryAppType((PSZ)pcszExecutable, pulDosAppType);
524 if (arc == NO_ERROR)
525 {
526 ULONG _ulDosAppType = *pulDosAppType;
527
528 if (_ulDosAppType == 0)
529 *pulWinAppType = PROG_FULLSCREEN;
530 else if (_ulDosAppType & FAPPTYP_PHYSDRV) // 0x40
531 *pulWinAppType = PROG_PDD;
532 else if (_ulDosAppType & FAPPTYP_VIRTDRV) // 0x80)
533 *pulWinAppType = PROG_VDD;
534 else if ((_ulDosAppType & 0xF0) == FAPPTYP_DLL) // 0x10)
535 // DLL bit set
536 *pulWinAppType = PROG_DLL;
537 else if (_ulDosAppType & FAPPTYP_DOS) // 0x20)
538 // DOS bit set?
539 *pulWinAppType = PROG_WINDOWEDVDM;
540 else if ((_ulDosAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) // 0x0003) // "Window-API" == PM
541 *pulWinAppType = PROG_PM;
542 else if ( ((_ulDosAppType & 0xFFFF) == FAPPTYP_WINDOWSPROT31) // 0x1000) // windows program (?!?)
543 || ((_ulDosAppType & 0xFFFF) == FAPPTYP_WINDOWSPROT) // ) // windows program (?!?)
544 )
545 *pulWinAppType = PROG_31_ENHSEAMLESSCOMMON; // PROG_31_ENH;
546 // *pulWinAppType = PROG_31_ENHSEAMLESSVDM;
547 else if ((_ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_WINDOWCOMPAT) // 0x02)
548 *pulWinAppType = PROG_WINDOWABLEVIO;
549 else if ((_ulDosAppType & FAPPTYP_WINDOWAPI /* 0x03 */ ) == FAPPTYP_NOTWINDOWCOMPAT) // 0x01)
550 *pulWinAppType = PROG_FULLSCREEN;
551 }
552
553 return (arc);
554}
555
556/*
557 *@@ appDescribeAppType:
558 * returns a "PROG_*" string for the given
559 * program type. Useful for WPProgram setup
560 * strings and such.
561 *
562 *@@added V0.9.16 (2001-10-06)
563 */
564
565PCSZ appDescribeAppType(PROGCATEGORY progc) // in: from PROGDETAILS.progc
566{
567 switch (progc)
568 {
569 case PROG_DEFAULT: return "PROG_DEFAULT";
570 case PROG_FULLSCREEN: return "PROG_FULLSCREEN";
571 case PROG_WINDOWABLEVIO: return "PROG_WINDOWABLEVIO";
572 case PROG_PM: return "PROG_PM";
573 case PROG_GROUP: return "PROG_GROUP";
574 case PROG_VDM: return "PROG_VDM";
575 // same as case PROG_REAL: return "PROG_REAL";
576 case PROG_WINDOWEDVDM: return "PROG_WINDOWEDVDM";
577 case PROG_DLL: return "PROG_DLL";
578 case PROG_PDD: return "PROG_PDD";
579 case PROG_VDD: return "PROG_VDD";
580 case PROG_WINDOW_REAL: return "PROG_WINDOW_REAL";
581 case PROG_30_STD: return "PROG_30_STD";
582 // same as case PROG_WINDOW_PROT: return "PROG_WINDOW_PROT";
583 case PROG_WINDOW_AUTO: return "PROG_WINDOW_AUTO";
584 case PROG_30_STDSEAMLESSVDM: return "PROG_30_STDSEAMLESSVDM";
585 // same as case PROG_SEAMLESSVDM: return "PROG_SEAMLESSVDM";
586 case PROG_30_STDSEAMLESSCOMMON: return "PROG_30_STDSEAMLESSCOMMON";
587 // same as case PROG_SEAMLESSCOMMON: return "PROG_SEAMLESSCOMMON";
588 case PROG_31_STDSEAMLESSVDM: return "PROG_31_STDSEAMLESSVDM";
589 case PROG_31_STDSEAMLESSCOMMON: return "PROG_31_STDSEAMLESSCOMMON";
590 case PROG_31_ENHSEAMLESSVDM: return "PROG_31_ENHSEAMLESSVDM";
591 case PROG_31_ENHSEAMLESSCOMMON: return "PROG_31_ENHSEAMLESSCOMMON";
592 case PROG_31_ENH: return "PROG_31_ENH";
593 case PROG_31_STD: return "PROG_31_STD";
594
595// Warp 4 toolkit defines, whatever these were designed for...
596#ifndef PROG_DOS_GAME
597 #define PROG_DOS_GAME (PROGCATEGORY)21
598#endif
599#ifndef PROG_WIN_GAME
600 #define PROG_WIN_GAME (PROGCATEGORY)22
601#endif
602#ifndef PROG_DOS_MODE
603 #define PROG_DOS_MODE (PROGCATEGORY)23
604#endif
605
606 case PROG_DOS_GAME: return "PROG_DOS_GAME";
607 case PROG_WIN_GAME: return "PROG_WIN_GAME";
608 case PROG_DOS_MODE: return "PROG_DOS_MODE";
609 }
610
611 return NULL;
612}
613
614/*
615 *@@ appIsWindowsApp:
616 * checks the specified program category
617 * (PROGDETAILS.progt.progc) for whether
618 * it represents a Win-OS/2 application.
619 *
620 * Returns:
621 *
622 * -- 0: no windows app (it's VIO, OS/2
623 * or DOS fullscreen, or PM).
624 *
625 * -- 1: Win-OS/2 standard app.
626 *
627 * -- 2: Win-OS/2 enhanced-mode app.
628 *
629 *@@added V0.9.12 (2001-05-26) [umoeller]
630 */
631
632ULONG appIsWindowsApp(ULONG ulProgCategory)
633{
634 switch (ulProgCategory)
635 {
636 case PROG_31_ENHSEAMLESSVDM: // 17
637 case PROG_31_ENHSEAMLESSCOMMON: // 18
638 case PROG_31_ENH: // 19
639 return (2);
640
641#ifndef PROG_30_STD
642 #define PROG_30_STD (PROGCATEGORY)11
643#endif
644
645#ifndef PROG_30_STDSEAMLESSVDM
646 #define PROG_30_STDSEAMLESSVDM (PROGCATEGORY)13
647#endif
648
649 case PROG_WINDOW_REAL: // 10
650 case PROG_30_STD: // 11
651 case PROG_WINDOW_AUTO: // 12
652 case PROG_30_STDSEAMLESSVDM: // 13
653 case PROG_30_STDSEAMLESSCOMMON: // 14
654 case PROG_31_STDSEAMLESSVDM: // 15
655 case PROG_31_STDSEAMLESSCOMMON: // 16
656 case PROG_31_STD: // 20
657 return (1);
658 }
659
660 return (0);
661}
662
663/* ******************************************************************
664 *
665 * Application start
666 *
667 ********************************************************************/
668
669/*
670 *@@ CallBatchCorrectly:
671 * fixes the specified PROGDETAILS for
672 * command files in the executable part
673 * by inserting /C XXX into the parameters
674 * and setting the executable according
675 * to an environment variable.
676 *
677 *@@added V0.9.6 (2000-10-16) [umoeller]
678 *@@changed V0.9.7 (2001-01-15) [umoeller]: now using XSTRING
679 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
680 */
681
682VOID CallBatchCorrectly(PPROGDETAILS pProgDetails,
683 PXSTRING pstrParams, // in/out: modified parameters (reallocated)
684 const char *pcszEnvVar, // in: env var spec'g command proc
685 // (e.g. "OS2_SHELL"); can be NULL
686 const char *pcszDefProc) // in: def't command proc (e.g. "CMD.EXE")
687{
688 // XXX.CMD file as executable:
689 // fix args to /C XXX.CMD
690
691 PSZ pszOldParams = NULL;
692 ULONG ulOldParamsLength = pstrParams->ulLength;
693 if (ulOldParamsLength)
694 // we have parameters already:
695 // make a backup... we'll append that later
696 pszOldParams = strdup(pstrParams->psz);
697
698 // set new params to "/C filename.cmd"
699 xstrcpy(pstrParams, "/C ", 0);
700 xstrcat(pstrParams,
701 pProgDetails->pszExecutable,
702 0);
703
704 if (pszOldParams)
705 {
706 // .cmd had params:
707 // append space and old params
708 xstrcatc(pstrParams, ' ');
709 xstrcat(pstrParams,
710 pszOldParams,
711 ulOldParamsLength);
712 free(pszOldParams);
713 }
714
715 // set executable to $(OS2_SHELL)
716 pProgDetails->pszExecutable = NULL;
717 if (pcszEnvVar)
718 pProgDetails->pszExecutable = getenv(pcszEnvVar);
719 if (!pProgDetails->pszExecutable)
720 pProgDetails->pszExecutable = (PSZ)pcszDefProc;
721 // should be on PATH
722}
723
724/*
725 *@@ appQueryDefaultWin31Environment:
726 * returns the default Win-OS/2 3.1 environment
727 * from OS2.INI, which you can then merge with
728 * your process environment to be able to
729 * start Win-OS/2 sessions properly with
730 * appStartApp.
731 *
732 * Caller must free() the return value.
733 *
734 *@@added V0.9.12 (2001-05-26) [umoeller]
735 */
736
737PSZ appQueryDefaultWin31Environment(VOID)
738{
739 PSZ pszReturn = NULL;
740 ULONG ulSize = 0;
741 // get default environment (from Win-OS/2 settings object)
742 // from OS2.INI
743 PSZ pszDefEnv = prfhQueryProfileData(HINI_USER,
744 "WINOS2",
745 "PM_GlobalWindows31Settings",
746 &ulSize);
747 if (pszDefEnv)
748 {
749 if (pszReturn = (PSZ)malloc(ulSize + 2))
750 {
751 PSZ p;
752 memset(pszReturn, 0, ulSize + 2);
753 memcpy(pszReturn, pszDefEnv, ulSize);
754
755 for (p = pszReturn;
756 p < pszReturn + ulSize;
757 p++)
758 if (*p == ';')
759 *p = 0;
760
761 // okay.... now we got an OS/2-style environment
762 // with 0, 0, 00 strings
763 }
764
765 free(pszDefEnv);
766 }
767
768 return (pszReturn);
769}
770
771/*
772 *@@ appStartApp:
773 * wrapper around WinStartApp which fixes the
774 * specified PROGDETAILS to (hopefully) work
775 * work with all executable types.
776 *
777 * This fixes the executable info to support:
778 *
779 * -- starting "*" executables (command prompts
780 * for OS/2, DOS, Win-OS/2);
781 *
782 * -- starting ".CMD" and ".BAT" files as
783 * PROGDETAILS.pszExecutable.
784 *
785 * Unless it is "*", PROGDETAILS.pszExecutable must
786 * be a proper file name. The full path may be omitted
787 * if it is on the PATH, but the extension (.EXE etc.)
788 * must be given. You can use doshFindExecutable to
789 * find executables if you don't know the extension.
790 *
791 * This also handles and merges special and default
792 * environments for the app to be started. The
793 * following should be respected:
794 *
795 * -- As with WinStartApp, if PROGDETAILS.pszEnvironment
796 * is NULL, the new app inherits a default environment
797 * from the shell.
798 *
799 + -- However, if you specify an environment, you _must_
800 * specify a complemete environment. This function
801 * will not merge environments. Use
802 * appSetEnvironmentVar to change environment
803 * variables in a complete environment set.
804 *
805 * -- If PROGDETAILS specifies a Win-OS/2 session
806 * and PROGDETAILS.pszEnvironment is empty,
807 * this uses the default Win-OS/2 environment.
808 * See appQueryDefaultWin31Environment.
809 *
810 * -- WARNING: Since this uses WinStartApp internally,
811 * and WinStartApp completely hangs PM if a Win-OS/2
812 * full-screen session is started from a thread that
813 * is NOT thread1, THIS SHOULD ONLY BE CALLED ON
814 * THREAD 1 of your application.
815 *
816 * Even though this isn't clearly said in PMREF,
817 * PROGDETAILS.swpInitial is important:
818 *
819 * -- To start a session minimized, set SWP_MINIMIZE.
820 *
821 * -- To start a VIO session auto-close disabled, set
822 * the half-documented SWP_NOAUTOCLOSE flag (0x8000)
823 * This flag is now in the newer toolkit headers.
824 *
825 * Since this calls WinStartApp in turn, this
826 * requires a message queue on the calling thread.
827 *
828 *@@added V0.9.6 (2000-10-16) [umoeller]
829 *@@changed V0.9.7 (2000-12-10) [umoeller]: PROGDETAILS.swpInitial no longer zeroed... this broke VIOs
830 *@@changed V0.9.7 (2000-12-17) [umoeller]: PROGDETAILS.pszEnvironment no longer zeroed
831 *@@changed V0.9.9 (2001-01-27) [umoeller]: crashed if PROGDETAILS.pszExecutable was NULL
832 *@@changed V0.9.12 (2001-05-26) [umoeller]: fixed PROG_DEFAULT
833 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
834 *@@changed V0.9.14 (2001-08-07) [pr]: removed some env. strings for Win. apps.
835 *@@changed V0.9.14 (2001-08-23) [pr]: added session type options
836 */
837
838HAPP appStartApp(HWND hwndNotify, // in: notify window (as with WinStartApp)
839 const PROGDETAILS *pcProgDetails, // in: program data
840 ULONG ulFlags) // in: session type options
841{
842 HAPP happ = NULLHANDLE;
843 XSTRING strParamsPatched;
844 PROGDETAILS ProgDetails;
845
846 PSZ pszWinOS2Env = 0;
847
848 memcpy(&ProgDetails, pcProgDetails, sizeof(PROGDETAILS));
849 // pointers still point into old prog details buffer
850 ProgDetails.Length = sizeof(PROGDETAILS);
851 ProgDetails.progt.fbVisible = SHE_VISIBLE;
852 // ProgDetails.pszEnvironment = 0;
853
854 // all this only makes sense if this contains something...
855 // besides, this crashed on string comparisons V0.9.9 (2001-01-27) [umoeller]
856 if (ProgDetails.pszExecutable)
857 {
858 ULONG ulIsWinApp;
859
860 // memset(&ProgDetails.swpInitial, 0, sizeof(SWP));
861 // this wasn't a good idea... WPProgram stores stuff
862 // in here, such as the "minimize on startup" -> SWP_MINIMIZE
863
864 // duplicate parameters...
865 // we need this for string manipulations below...
866 if (ProgDetails.pszParameters)
867 xstrInitCopy(&strParamsPatched,
868 ProgDetails.pszParameters,
869 100);
870 else
871 // no old params:
872 xstrInit(&strParamsPatched, 100);
873
874 // _Pmpf((__FUNCTION__ ": old progc: 0x%lX", pcProgDetails->progt.progc));
875 // _Pmpf((" pszTitle: %s", (ProgDetails.pszTitle) ? ProgDetails.pszTitle : NULL));
876 // _Pmpf((" pszIcon: %s", (ProgDetails.pszIcon) ? ProgDetails.pszIcon : NULL));
877
878 // program type fixups
879 switch (ProgDetails.progt.progc) // that's a ULONG
880 {
881 case ((ULONG)-1): // we get that sometimes...
882 case PROG_DEFAULT:
883 {
884 // V0.9.12 (2001-05-26) [umoeller]
885 ULONG ulDosAppType;
886 appQueryAppType(ProgDetails.pszExecutable,
887 &ulDosAppType,
888 &ProgDetails.progt.progc);
889 }
890 break;
891 }
892
893 // Set session type from option flags
894 if (ulFlags & APP_RUN_FULLSCREEN)
895 {
896 if (ProgDetails.progt.progc == PROG_WINDOWABLEVIO)
897 ProgDetails.progt.progc = PROG_FULLSCREEN;
898
899 if (ProgDetails.progt.progc == PROG_WINDOWEDVDM)
900 ProgDetails.progt.progc = PROG_VDM;
901 }
902
903 if (ulIsWinApp = appIsWindowsApp(ProgDetails.progt.progc))
904 {
905 if (ulFlags & APP_RUN_FULLSCREEN)
906 ProgDetails.progt.progc = (ulFlags & APP_RUN_ENHANCED)
907 ? PROG_31_ENH
908 : PROG_31_STD;
909 else
910 {
911 if (ulFlags & APP_RUN_STANDARD)
912 ProgDetails.progt.progc = (ulFlags & APP_RUN_SEPARATE)
913 ? PROG_31_STDSEAMLESSVDM
914 : PROG_31_STDSEAMLESSCOMMON;
915
916 if (ulFlags & APP_RUN_ENHANCED)
917 ProgDetails.progt.progc = (ulFlags & APP_RUN_SEPARATE)
918 ? PROG_31_ENHSEAMLESSVDM
919 : PROG_31_ENHSEAMLESSCOMMON;
920 }
921 }
922
923 /*
924 * command lines fixups:
925 *
926 */
927
928 if (!strcmp(ProgDetails.pszExecutable, "*"))
929 {
930 /*
931 * "*" for command sessions:
932 *
933 */
934
935 if (ulIsWinApp == 2)
936 {
937 // enhanced Win-OS/2 session:
938 PSZ psz = NULL;
939 if (strParamsPatched.ulLength)
940 // "/3 " + existing params
941 psz = strdup(strParamsPatched.psz);
942
943 xstrcpy(&strParamsPatched, "/3 ", 0);
944
945 if (psz)
946 {
947 xstrcat(&strParamsPatched, psz, 0);
948 free(psz);
949 }
950 }
951
952 if (ulIsWinApp)
953 {
954 // cheat: WinStartApp doesn't support NULL
955 // for Win-OS2 sessions, so manually start winos2.com
956 ProgDetails.pszExecutable = "WINOS2.COM";
957 // this is a DOS app, so fix this to DOS fullscreen
958 ProgDetails.progt.progc = PROG_VDM;
959 }
960 else
961 // for all other executable types
962 // (including OS/2 and DOS sessions),
963 // set pszExecutable to NULL; this will
964 // have WinStartApp start a cmd shell
965 ProgDetails.pszExecutable = NULL;
966
967 } // end if (strcmp(pProgDetails->pszExecutable, "*") == 0)
968 else
969 {
970 PSZ pszExtension;
971 switch (ProgDetails.progt.progc)
972 {
973 /*
974 * .CMD files fixups
975 *
976 */
977
978 case PROG_FULLSCREEN: // OS/2 fullscreen
979 case PROG_WINDOWABLEVIO: // OS/2 window
980 {
981 if ( (pszExtension = doshGetExtension(ProgDetails.pszExecutable))
982 && (!stricmp(pszExtension, "CMD"))
983 )
984 {
985 CallBatchCorrectly(&ProgDetails,
986 &strParamsPatched,
987 "OS2_SHELL",
988 "CMD.EXE");
989 }
990 break; }
991
992 case PROG_VDM: // DOS fullscreen
993 case PROG_WINDOWEDVDM: // DOS window
994 {
995 if ( (pszExtension = doshGetExtension(ProgDetails.pszExecutable))
996 && (!stricmp(pszExtension, "BAT"))
997 )
998 {
999 CallBatchCorrectly(&ProgDetails,
1000 &strParamsPatched,
1001 NULL,
1002 "COMMAND.COM");
1003 }
1004 break; }
1005 } // end switch (ProgDetails.progt.progc)
1006 }
1007
1008 if ( (ulIsWinApp)
1009 && ( (ProgDetails.pszEnvironment == NULL)
1010 || (!strlen(ProgDetails.pszEnvironment))
1011 )
1012 )
1013 {
1014 // this is a windoze app, and caller didn't bother
1015 // to give us an environment:
1016 // we MUST set one then, or we'll get the strangest
1017 // errors, up to system hangs. V0.9.12 (2001-05-26) [umoeller]
1018
1019 DOSENVIRONMENT Env = {0};
1020
1021 // get standard WIN-OS/2 environment
1022 PSZ pszTemp = appQueryDefaultWin31Environment();
1023
1024 if (!appParseEnvironment(pszTemp,
1025 &Env))
1026 {
1027 // now override KBD_CTRL_BYPASS=CTRL_ESC
1028 appSetEnvironmentVar(&Env,
1029 "KBD_CTRL_BYPASS=CTRL_ESC",
1030 FALSE); // add last
1031 /*
1032 * These should be set by the default environment. It is
1033 * not our business to override them really. V0.9.14
1034 *
1035 appSetEnvironmentVar(&Env,
1036 "KBD_ALTHOME_BYPASS=1",
1037 FALSE); // add last
1038 appSetEnvironmentVar(&Env,
1039 "INT_DURING_IO=1",
1040 FALSE); // add last
1041 appSetEnvironmentVar(&Env,
1042 "HW_TIMER=1",
1043 FALSE); // add last
1044 appSetEnvironmentVar(&Env,
1045 "MOUSE_EXCLUSIVE_ACCESS=0",
1046 FALSE); // add last
1047 appSetEnvironmentVar(&Env,
1048 "VIDEO_RETRACE_EMULATION=1",
1049 FALSE); // add last
1050 appSetEnvironmentVar(&Env,
1051 "VIDEO_SWITCH_NOTIFICATION=1",
1052 FALSE); // add last
1053 appSetEnvironmentVar(&Env,
1054 "VIDEO_8514A_XGA_IOTRAP=0",
1055 FALSE); // add last
1056 */
1057
1058 if (!appConvertEnvironment(&Env,
1059 &pszWinOS2Env, // freed at bottom
1060 NULL))
1061 ProgDetails.pszEnvironment = pszWinOS2Env;
1062
1063 appFreeEnvironment(&Env);
1064 }
1065
1066 free(pszTemp);
1067 }
1068
1069 if (!ProgDetails.pszTitle)
1070 ProgDetails.pszTitle = ProgDetails.pszExecutable;
1071
1072 ProgDetails.pszParameters = strParamsPatched.psz;
1073
1074 /* _Pmpf(("progt.progc: %d", ProgDetails.progt.progc));
1075 _Pmpf(("progt.fbVisible: 0x%lX", ProgDetails.progt.fbVisible));
1076 _Pmpf(("progt.pszTitle: \"%s\"", (ProgDetails.pszTitle) ? ProgDetails.pszTitle : "NULL"));
1077 _Pmpf(("exec: \"%s\"", (ProgDetails.pszExecutable) ? ProgDetails.pszExecutable : "NULL"));
1078 _Pmpf(("params: \"%s\"", (ProgDetails.pszParameters) ? ProgDetails.pszParameters : "NULL"));
1079 _Pmpf(("startup: \"%s\"", (ProgDetails.pszStartupDir) ? ProgDetails.pszStartupDir : "NULL"));
1080 _Pmpf(("pszIcon: \"%s\"", (ProgDetails.pszIcon) ? ProgDetails.pszIcon : "NULL"));
1081 _Pmpf(("environment: "));
1082 {
1083 PSZ pszThis = ProgDetails.pszEnvironment;
1084 while (pszThis && *pszThis)
1085 {
1086 _Pmpf((" \"%s\"", pszThis));
1087 pszThis += strlen(pszThis) + 1;
1088 }
1089 }
1090
1091 _Pmpf(("swpInitial.fl = 0x%lX, x = %d, y = %d, cx = %d, cy = %d:",
1092 ProgDetails.swpInitial.fl,
1093 ProgDetails.swpInitial.x,
1094 ProgDetails.swpInitial.y,
1095 ProgDetails.swpInitial.cx,
1096 ProgDetails.swpInitial.cy));
1097 _Pmpf((" behind = %d, hwnd = %d, res1 = %d, res2 = %d",
1098 ProgDetails.swpInitial.hwndInsertBehind,
1099 ProgDetails.swpInitial.hwnd,
1100 ProgDetails.swpInitial.ulReserved1,
1101 ProgDetails.swpInitial.ulReserved2));
1102 */
1103
1104 /* if (WinMessageBox(HWND_DESKTOP,
1105 NULLHANDLE,
1106 (ProgDetails.pszExecutable) ? ProgDetails.pszExecutable : "NULL",
1107 "Start?",
1108 0,
1109 MB_YESNO | MB_MOVEABLE)
1110 == MBID_YES) */
1111 happ = WinStartApp(hwndNotify,
1112 // receives WM_APPTERMINATENOTIFY
1113 &ProgDetails,
1114 strParamsPatched.psz,
1115 NULL, // "reserved", PMREF says...
1116 SAF_INSTALLEDCMDLINE);
1117 // we MUST use SAF_INSTALLEDCMDLINE
1118 // or no Win-OS/2 session will start...
1119 // whatever is going on here... Warp 4 FP11
1120
1121 // do not use SAF_STARTCHILDAPP, or the
1122 // app will be terminated automatically
1123 // when the WPS terminates!
1124
1125 // _Pmpf((__FUNCTION__ ": got happ 0x%lX", happ));
1126
1127 xstrClear(&strParamsPatched);
1128 if (pszWinOS2Env)
1129 free(pszWinOS2Env);
1130 } // end if (ProgDetails.pszExecutable)
1131
1132 return (happ);
1133}
1134
1135
Note: See TracBrowser for help on using the repository browser.