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

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

Misc changes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 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 pszThis = *ppszThis;
236
237 if (strnicmp(*ppszThis, pszSearch, ulVarNameLen) == 0)
238 {
239 ppszRet = ppszThis;
240 break;
241 }
242
243 // next environment string
244 ppszThis++;
245 }
246
247 free(pszSearch); // was missing V0.9.12 (2001-05-21) [umoeller]
248 }
249 }
250
251 return (ppszRet);
252}
253
254/*
255 *@@ appSetEnvironmentVar:
256 * sets an environment variable in the specified
257 * environment, which must have been initialized
258 * using appGetEnvironment first.
259 *
260 * pszNewEnv must be a full environment string
261 * in the form "VARNAME=VALUE".
262 *
263 * If "VARNAME" has already been set to something
264 * in the string array in pEnv, that array item
265 * is replaced.
266 *
267 * OTOH, if "VARNAME" has not been set yet, a new
268 * item is added to the array, and pEnv->cVars is
269 * raised by one. In that case, fAddFirst determines
270 * whether the new array item is added to the front
271 * or the tail of the environment list.
272 *
273 *@@added V0.9.4 (2000-07-19) [umoeller]
274 *@@changed V0.9.7 (2000-12-17) [umoeller]: added fAddFirst
275 *@@changed V0.9.12 (2001-05-21) [umoeller]: fixed memory leak
276 *@@changed V0.9.12 (2001-05-26) [umoeller]: fixed crash if !fAddFirst
277 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
278 */
279
280APIRET appSetEnvironmentVar(PDOSENVIRONMENT pEnv,
281 PSZ pszNewEnv,
282 BOOL fAddFirst)
283{
284 APIRET arc = NO_ERROR;
285 if ((!pEnv) || (!pszNewEnv))
286 arc = ERROR_INVALID_PARAMETER;
287 else
288 {
289 if (!pEnv->papszVars)
290 {
291 // no variables set yet:
292 pEnv->papszVars = (PSZ*)malloc(sizeof(PSZ));
293 pEnv->cVars = 1;
294
295 *(pEnv->papszVars) = strdup(pszNewEnv);
296 }
297 else
298 {
299 PSZ *ppszEnvLine = appFindEnvironmentVar(pEnv, pszNewEnv);
300 if (ppszEnvLine)
301 {
302 // was set already: replace
303 free(*ppszEnvLine);
304 *ppszEnvLine = strdup(pszNewEnv);
305 if (!(*ppszEnvLine))
306 arc = ERROR_NOT_ENOUGH_MEMORY;
307 }
308 else
309 {
310 // not set already:
311 PSZ *ppszNew = NULL;
312
313 // allocate new array, with one new entry
314 // fixed V0.9.12 (2001-05-26) [umoeller], this crashed
315 PSZ *papszNew = (PSZ*)malloc(sizeof(PSZ) * (pEnv->cVars + 1));
316
317 if (!papszNew)
318 arc = ERROR_NOT_ENOUGH_MEMORY;
319 else
320 {
321 if (fAddFirst)
322 {
323 // add as first entry:
324 // overwrite first entry
325 ppszNew = papszNew;
326 // copy old entries
327 memcpy(papszNew + 1, // second new entry
328 pEnv->papszVars, // first old entry
329 sizeof(PSZ) * pEnv->cVars);
330 }
331 else
332 {
333 // append at the tail:
334 // overwrite last entry
335 ppszNew = papszNew + pEnv->cVars;
336 // copy old entries
337 memcpy(papszNew, // first new entry
338 pEnv->papszVars, // first old entry
339 sizeof(PSZ) * pEnv->cVars);
340 }
341
342 if (pEnv->papszVars)
343 free(pEnv->papszVars); // was missing V0.9.12 (2001-05-21) [umoeller]
344
345 pEnv->papszVars = papszNew;
346 pEnv->cVars++;
347 *ppszNew = strdup(pszNewEnv);
348 }
349 }
350 }
351 }
352
353 return (arc);
354}
355
356/*
357 *@@ appConvertEnvironment:
358 * converts an environment initialized by appGetEnvironment
359 * to the string format required by WinStartApp and DosExecPgm,
360 * that is, one memory block is allocated in *ppszEnv and all
361 * strings in pEnv->papszVars are copied to that block. Each
362 * string is terminated with a null character; the last string
363 * is terminated with two null characters.
364 *
365 * Use free() to free the memory block allocated by this
366 * function in *ppszEnv.
367 *
368 *@@added V0.9.4 (2000-07-19) [umoeller]
369 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
370 */
371
372APIRET appConvertEnvironment(PDOSENVIRONMENT pEnv,
373 PSZ *ppszEnv, // out: environment string
374 PULONG pulSize) // out: size of block allocated in *ppszEnv; ptr can be NULL
375{
376 APIRET arc = NO_ERROR;
377 if (!pEnv)
378 arc = ERROR_INVALID_PARAMETER;
379 else
380 {
381 if (!pEnv->papszVars)
382 arc = ERROR_INVALID_PARAMETER;
383 else
384 {
385 // count memory needed for all strings
386 ULONG cbNeeded = 0,
387 ul = 0;
388 PSZ *ppszThis = pEnv->papszVars;
389
390 for (ul = 0;
391 ul < pEnv->cVars;
392 ul++)
393 {
394 cbNeeded += strlen(*ppszThis) + 1; // length of string plus null terminator
395
396 // next environment string
397 ppszThis++;
398 }
399
400 cbNeeded++; // for another null terminator
401
402 *ppszEnv = (PSZ)malloc(cbNeeded);
403 if (!(*ppszEnv))
404 arc = ERROR_NOT_ENOUGH_MEMORY;
405 else
406 {
407 PSZ pTarget = *ppszEnv;
408 if (pulSize)
409 *pulSize = cbNeeded;
410 ppszThis = pEnv->papszVars;
411
412 // now copy each string
413 for (ul = 0;
414 ul < pEnv->cVars;
415 ul++)
416 {
417 PSZ pSource = *ppszThis;
418
419 while ((*pTarget++ = *pSource++))
420 ;
421
422 // *pTarget++ = 0; // append null terminator per string
423
424 // next environment string
425 ppszThis++;
426 }
427
428 *pTarget++ = 0; // append second null terminator
429 }
430 }
431 }
432
433 return (arc);
434}
435
436/*
437 *@@ appFreeEnvironment:
438 * frees memory allocated by appGetEnvironment.
439 *
440 *@@added V0.9.4 (2000-07-19) [umoeller]
441 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from dosh2.c to apps.c
442 */
443
444APIRET appFreeEnvironment(PDOSENVIRONMENT pEnv)
445{
446 APIRET arc = NO_ERROR;
447 if (!pEnv)
448 arc = ERROR_INVALID_PARAMETER;
449 else
450 {
451 if (!pEnv->papszVars)
452 arc = ERROR_INVALID_PARAMETER;
453 else
454 {
455 PSZ *ppszThis = pEnv->papszVars;
456 PSZ pszThis;
457 ULONG ul = 0;
458
459 for (ul = 0;
460 ul < pEnv->cVars;
461 ul++)
462 {
463 pszThis = *ppszThis;
464 free(pszThis);
465 // *ppszThis = NULL;
466 // next environment string
467 ppszThis++;
468 }
469
470 free(pEnv->papszVars);
471 pEnv->cVars = 0;
472 }
473 }
474
475 return (arc);
476}
477
478/* ******************************************************************
479 *
480 * Application start
481 *
482 ********************************************************************/
483
484/*
485 *@@ CallBatchCorrectly:
486 * fixes the specified PROGDETAILS for
487 * command files in the executable part
488 * by inserting /C XXX into the parameters
489 * and setting the executable according
490 * to an environment variable.
491 *
492 *@@added V0.9.6 (2000-10-16) [umoeller]
493 *@@changed V0.9.7 (2001-01-15) [umoeller]: now using XSTRING
494 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
495 */
496
497VOID CallBatchCorrectly(PPROGDETAILS pProgDetails,
498 PXSTRING pstrParams, // in/out: modified parameters (reallocated)
499 const char *pcszEnvVar, // in: env var spec'g command proc
500 // (e.g. "OS2_SHELL"); can be NULL
501 const char *pcszDefProc) // in: def't command proc (e.g. "CMD.EXE")
502{
503 // XXX.CMD file as executable:
504 // fix args to /C XXX.CMD
505
506 PSZ pszOldParams = NULL;
507 ULONG ulOldParamsLength = pstrParams->ulLength;
508 if (ulOldParamsLength)
509 // we have parameters already:
510 // make a backup... we'll append that later
511 pszOldParams = strdup(pstrParams->psz);
512
513 // set new params to "/C filename.cmd"
514 xstrcpy(pstrParams, "/C ", 0);
515 xstrcat(pstrParams,
516 pProgDetails->pszExecutable,
517 0);
518
519 if (pszOldParams)
520 {
521 // .cmd had params:
522 // append space and old params
523 xstrcatc(pstrParams, ' ');
524 xstrcat(pstrParams,
525 pszOldParams,
526 ulOldParamsLength);
527 free(pszOldParams);
528 }
529
530 // set executable to $(OS2_SHELL)
531 pProgDetails->pszExecutable = NULL;
532 if (pcszEnvVar)
533 pProgDetails->pszExecutable = getenv(pcszEnvVar);
534 if (!pProgDetails->pszExecutable)
535 pProgDetails->pszExecutable = (PSZ)pcszDefProc;
536 // should be on PATH
537}
538
539/*
540 *@@ appQueryAppType:
541 * returns the Control Program (Dos) and
542 * Win* PROG_* application types for the
543 * specified executable. Essentially, this
544 * is a wrapper around DosQueryAppType.
545 *
546 * pcszExecutable must be fully qualified.
547 * You can use doshFindExecutable to qualify
548 * it.
549 *
550 * This returns the APIRET of DosQueryAppType.
551 * If this is NO_ERROR; *pulDosAppType receives
552 * the app type of DosQueryAppType. In addition,
553 * *pulWinAppType is set to one of the following:
554 *
555 * -- PROG_FULLSCREEN
556 *
557 * -- PROG_PDD
558 *
559 * -- PROG_VDD
560 *
561 * -- PROG_XWP_DLL: new apptype defined in winh.h for
562 * dynamic link libraries.
563 *
564 * -- PROG_WINDOWEDVDM
565 *
566 * -- PROG_PM
567 *
568 * -- PROG_31_ENH
569 *
570 * -- PROG_WINDOWABLEVIO
571 *
572 *@@added V0.9.9 (2001-03-07) [umoeller]
573 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
574 */
575
576APIRET appQueryAppType(const char *pcszExecutable,
577 PULONG pulDosAppType,
578 PULONG pulWinAppType)
579{
580 APIRET arc = DosQueryAppType((PSZ)pcszExecutable, pulDosAppType);
581 if (arc == NO_ERROR)
582 {
583 ULONG _ulDosAppType = *pulDosAppType;
584
585 if (_ulDosAppType == 0)
586 *pulWinAppType = PROG_FULLSCREEN;
587 else if (_ulDosAppType & 0x40)
588 *pulWinAppType = PROG_PDD;
589 else if (_ulDosAppType & 0x80)
590 *pulWinAppType = PROG_VDD;
591 else if ((_ulDosAppType & 0xF0) == 0x10)
592 // DLL bit set
593 *pulWinAppType = PROG_XWP_DLL;
594 else if (_ulDosAppType & 0x20)
595 // DOS bit set?
596 *pulWinAppType = PROG_WINDOWEDVDM;
597 else if ((_ulDosAppType & 0x0003) == 0x0003) // "Window-API" == PM
598 *pulWinAppType = PROG_PM;
599 else if ( ((_ulDosAppType & 0xFFFF) == 0x1000) // windows program (?!?)
600 || ((_ulDosAppType & 0xFFFF) == 0x0400) // windows program (?!?)
601 )
602 *pulWinAppType = PROG_31_ENH;
603 // *pulWinAppType = PROG_31_ENHSEAMLESSVDM;
604 else if ((_ulDosAppType & 0x03) == 0x02)
605 *pulWinAppType = PROG_WINDOWABLEVIO;
606 else if ((_ulDosAppType & 0x03) == 0x01)
607 *pulWinAppType = PROG_FULLSCREEN;
608 }
609
610 return (arc);
611}
612
613/*
614 *@@ appIsWindowsApp:
615 * checks the specified program category
616 * (PROGDETAILS.progt.progc) for whether
617 * it represents a Win-OS/2 application.
618 *
619 * Returns:
620 *
621 * -- 0: no windows app (it's VIO, OS/2
622 * or DOS fullscreen, or PM).
623 *
624 * -- 1: Win-OS/2 standard app.
625 *
626 * -- 2: Win-OS/2 enhanced-mode app.
627 *
628 *@@added V0.9.12 (2001-05-26) [umoeller]
629 */
630
631ULONG appIsWindowsApp(ULONG ulProgCategory)
632{
633 switch (ulProgCategory)
634 {
635 case PROG_31_ENHSEAMLESSVDM: // 17
636 case PROG_31_ENHSEAMLESSCOMMON: // 18
637 case PROG_31_ENH: // 19
638 return (2);
639
640#ifndef PROG_30_STD
641 #define PROG_30_STD (PROGCATEGORY)11
642#endif
643
644#ifndef PROG_30_STDSEAMLESSVDM
645 #define PROG_30_STDSEAMLESSVDM (PROGCATEGORY)13
646#endif
647
648 case PROG_WINDOW_REAL: // 10
649 case PROG_30_STD: // 11
650 case PROG_WINDOW_AUTO: // 12
651 case PROG_30_STDSEAMLESSVDM: // 13
652 case PROG_30_STDSEAMLESSCOMMON: // 14
653 case PROG_31_STDSEAMLESSVDM: // 15
654 case PROG_31_STDSEAMLESSCOMMON: // 16
655 case PROG_31_STD: // 20
656 return (1);
657 }
658
659 return (0);
660}
661
662/*
663 *@@ appQueryDefaultWin31Environment:
664 * returns the default Win-OS/2 3.1 environment
665 * from OS2.INI, which you can then merge with
666 * your process environment to be able to
667 * start Win-OS/2 sessions properly with
668 * appStartApp.
669 *
670 * Caller must free() the return value.
671 *
672 *@@added V0.9.12 (2001-05-26) [umoeller]
673 */
674
675PSZ appQueryDefaultWin31Environment(VOID)
676{
677 PSZ pszReturn = NULL;
678 ULONG ulSize = 0;
679 // get default environment (from Win-OS/2 settings object)
680 // from OS2.INI
681 PSZ pszDefEnv = prfhQueryProfileData(HINI_USER,
682 "WINOS2",
683 "PM_GlobalWindows31Settings",
684 &ulSize);
685 if (pszDefEnv)
686 {
687 if (pszReturn = (PSZ)malloc(ulSize + 2))
688 {
689 PSZ p;
690 memset(pszReturn, 0, ulSize + 2);
691 memcpy(pszReturn, pszDefEnv, ulSize);
692
693 for (p = pszReturn;
694 p < pszReturn + ulSize;
695 p++)
696 if (*p == ';')
697 *p = 0;
698
699 // okay.... now we got an OS/2-style environment
700 // with 0, 0, 00 strings
701 }
702
703 free(pszDefEnv);
704 }
705
706 return (pszReturn);
707}
708
709/*
710 *@@ appStartApp:
711 * wrapper around WinStartApp which fixes the
712 * specified PROGDETAILS to (hopefully) work
713 * work with all executable types.
714 *
715 * This fixes the executable info to support:
716 *
717 * -- starting "*" executables (command prompts
718 * for OS/2, DOS, Win-OS/2);
719 *
720 * -- starting ".CMD" and ".BAT" files as
721 * PROGDETAILS.pszExecutable.
722 *
723 * Unless it is "*", PROGDETAILS.pszExecutable must
724 * be a proper file name. The full path may be omitted
725 * if it is on the PATH, but the extension (.EXE etc.)
726 * must be given. You can use doshFindExecutable to
727 * find executables if you don't know the extension.
728 *
729 * This also handles and merges special and default
730 * environments for the app to be started. The
731 * following should be respected:
732 *
733 * -- As with WinStartApp, if PROGDETAILS.pszEnvironment
734 * is NULL, the new app inherits a default environment
735 * from the shell.
736 *
737 + -- However, if you specify an environment, you _must_
738 * specify a complemete environment. This function
739 * will not merge environments. Use
740 * appSetEnvironmentVar to change environment
741 * variables in a complete environment set.
742 *
743 * -- If PROGDETAILS specifies a Win-OS/2 session
744 * and PROGDETAILS.pszEnvironment is empty,
745 * this uses the default Win-OS/2 environment.
746 * See appQueryDefaultWin31Environment.
747 *
748 * Even though this isn't clearly said in PMREF,
749 * PROGDETAILS.swpInitial is important:
750 *
751 * -- To start a session minimized, set SWP_MINIMIZE.
752 *
753 * -- To start a VIO session auto-close disabled, set
754 * the half-documented SWP_NOAUTOCLOSE flag (0x8000)
755 * This flag is now in the newer toolkit headers.
756 *
757 * Since this calls WinStartApp in turn, this
758 * requires a message queue on the calling thread.
759 *
760 *@@added V0.9.6 (2000-10-16) [umoeller]
761 *@@changed V0.9.7 (2000-12-10) [umoeller]: PROGDETAILS.swpInitial no longer zeroed... this broke VIOs
762 *@@changed V0.9.7 (2000-12-17) [umoeller]: PROGDETAILS.pszEnvironment no longer zeroed
763 *@@changed V0.9.9 (2001-01-27) [umoeller]: crashed if PROGDETAILS.pszExecutable was NULL
764 *@@changed V0.9.12 (2001-05-26) [umoeller]: fixed PROG_DEFAULT
765 *@@changed V0.9.12 (2001-05-27) [umoeller]: moved from winh.c to apps.c
766 */
767
768HAPP appStartApp(HWND hwndNotify, // in: notify window (as with WinStartApp)
769 const PROGDETAILS *pcProgDetails) // in: program data
770{
771 HAPP happ = NULLHANDLE;
772 XSTRING strParamsPatched;
773 PROGDETAILS ProgDetails;
774
775 PSZ pszWinOS2Env = 0;
776
777 memcpy(&ProgDetails, pcProgDetails, sizeof(PROGDETAILS));
778 // pointers still point into old prog details buffer
779 ProgDetails.Length = sizeof(PROGDETAILS);
780 ProgDetails.progt.fbVisible = SHE_VISIBLE;
781 // ProgDetails.pszEnvironment = 0;
782
783 // all this only makes sense if this contains something...
784 // besides, this crashed on string comparisons V0.9.9 (2001-01-27) [umoeller]
785 if (ProgDetails.pszExecutable)
786 {
787 ULONG ulIsWinApp;
788
789 // memset(&ProgDetails.swpInitial, 0, sizeof(SWP));
790 // this wasn't a good idea... WPProgram stores stuff
791 // in here, such as the "minimize on startup" -> SWP_MINIMIZE
792
793 // duplicate parameters...
794 // we need this for string manipulations below...
795 if (ProgDetails.pszParameters)
796 xstrInitCopy(&strParamsPatched,
797 ProgDetails.pszParameters,
798 100);
799 else
800 // no old params:
801 xstrInit(&strParamsPatched, 100);
802
803 // _Pmpf((__FUNCTION__ ": old progc: 0x%lX", pcProgDetails->progt.progc));
804 // _Pmpf((" pszTitle: %s", (ProgDetails.pszTitle) ? ProgDetails.pszTitle : NULL));
805 // _Pmpf((" pszIcon: %s", (ProgDetails.pszIcon) ? ProgDetails.pszIcon : NULL));
806
807 // program type fixups
808 switch (ProgDetails.progt.progc) // that's a ULONG
809 {
810 case ((ULONG)-1): // we get that sometimes...
811 case PROG_DEFAULT:
812 {
813 // V0.9.12 (2001-05-26) [umoeller]
814 ULONG ulDosAppType;
815 appQueryAppType(ProgDetails.pszExecutable,
816 &ulDosAppType,
817 &ProgDetails.progt.progc);
818 }
819 break;
820 }
821
822 ulIsWinApp = appIsWindowsApp(ProgDetails.progt.progc);
823
824 // now try again...
825
826 /*
827 * command lines fixups:
828 *
829 */
830
831 if (strcmp(ProgDetails.pszExecutable, "*") == 0)
832 {
833 /*
834 * "*" for command sessions:
835 *
836 */
837
838 if (ulIsWinApp == 2)
839 {
840 // enhanced Win-OS/2 session:
841 PSZ psz = NULL;
842 if (strParamsPatched.ulLength)
843 // "/3 " + existing params
844 psz = strdup(strParamsPatched.psz);
845
846 xstrcpy(&strParamsPatched, "/3 ", 0);
847
848 if (psz)
849 {
850 xstrcat(&strParamsPatched, psz, 0);
851 free(psz);
852 }
853 }
854
855 if (ulIsWinApp)
856 {
857 // cheat: WinStartApp doesn't support NULL
858 // for Win-OS2 sessions, so manually start winos2.com
859 ProgDetails.pszExecutable = "WINOS2.COM";
860 // this is a DOS app, so fix this to DOS fullscreen
861 ProgDetails.progt.progc = PROG_VDM;
862 }
863 else
864 // for all other executable types
865 // (including OS/2 and DOS sessions),
866 // set pszExecutable to NULL; this will
867 // have WinStartApp start a cmd shell
868 ProgDetails.pszExecutable = NULL;
869
870 } // end if (strcmp(pProgDetails->pszExecutable, "*") == 0)
871 else
872 switch (ProgDetails.progt.progc)
873 {
874 /*
875 * .CMD files fixups
876 *
877 */
878
879 case PROG_FULLSCREEN: // OS/2 fullscreen
880 case PROG_WINDOWABLEVIO: // OS/2 window
881 {
882 PSZ pszExtension = doshGetExtension(ProgDetails.pszExecutable);
883 if (pszExtension)
884 {
885 if (stricmp(pszExtension, "CMD") == 0)
886 {
887 CallBatchCorrectly(&ProgDetails,
888 &strParamsPatched,
889 "OS2_SHELL",
890 "CMD.EXE");
891 }
892 }
893 break; }
894
895 case PROG_VDM: // DOS fullscreen
896 case PROG_WINDOWEDVDM: // DOS window
897 {
898 PSZ pszExtension = doshGetExtension(ProgDetails.pszExecutable);
899 if (pszExtension)
900 {
901 if (stricmp(pszExtension, "BAT") == 0)
902 {
903 CallBatchCorrectly(&ProgDetails,
904 &strParamsPatched,
905 NULL,
906 "COMMAND.COM");
907 }
908 }
909 break; }
910 } // end switch (ProgDetails.progt.progc)
911
912 if ( (ulIsWinApp)
913 && ( (ProgDetails.pszEnvironment == NULL)
914 || (!strlen(ProgDetails.pszEnvironment))
915 )
916 )
917 {
918 // this is a windoze app, and caller didn't bother
919 // to give us an environment:
920 // we MUST set one then, or we'll get the strangest
921 // errors, up to system hangs. V0.9.12 (2001-05-26) [umoeller]
922
923 DOSENVIRONMENT Env = {0};
924
925 // get standard WIN-OS/2 environment
926 PSZ pszTemp = appQueryDefaultWin31Environment();
927
928 if (!appParseEnvironment(pszTemp,
929 &Env))
930 {
931 // now override KBD_CTRL_BYPASS=CTRL_ESC
932 appSetEnvironmentVar(&Env,
933 "KBD_CTRL_BYPASS=CTRL_ESC",
934 FALSE); // add last
935 appSetEnvironmentVar(&Env,
936 "KBD_ALTHOME_BYPASS=1",
937 FALSE); // add last
938 appSetEnvironmentVar(&Env,
939 "INT_DURING_IO=1",
940 FALSE); // add last
941 appSetEnvironmentVar(&Env,
942 "HW_TIMER=1",
943 FALSE); // add last
944 appSetEnvironmentVar(&Env,
945 "MOUSE_EXCLUSIVE_ACCESS=0",
946 FALSE); // add last
947 appSetEnvironmentVar(&Env,
948 "VIDEO_RETRACE_EMULATION=1",
949 FALSE); // add last
950 appSetEnvironmentVar(&Env,
951 "VIDEO_SWITCH_NOTIFICATION=1",
952 FALSE); // add last
953 appSetEnvironmentVar(&Env,
954 "VIDEO_8514A_XGA_IOTRAP=0",
955 FALSE); // add last
956
957 if (!appConvertEnvironment(&Env,
958 &pszWinOS2Env, // freed at bottom
959 NULL))
960 ProgDetails.pszEnvironment = pszWinOS2Env;
961
962 appFreeEnvironment(&Env);
963 }
964
965 free(pszTemp);
966 }
967
968 if (!ProgDetails.pszTitle)
969 ProgDetails.pszTitle = ProgDetails.pszExecutable;
970
971 ProgDetails.pszParameters = strParamsPatched.psz;
972
973 _Pmpf(("progt.progc: %d", ProgDetails.progt.progc));
974 _Pmpf(("progt.fbVisible: 0x%lX", ProgDetails.progt.fbVisible));
975 _Pmpf(("progt.pszTitle: \"%s\"", (ProgDetails.pszTitle) ? ProgDetails.pszTitle : "NULL"));
976 _Pmpf(("exec: \"%s\"", (ProgDetails.pszExecutable) ? ProgDetails.pszExecutable : "NULL"));
977 _Pmpf(("params: \"%s\"", (ProgDetails.pszParameters) ? ProgDetails.pszParameters : "NULL"));
978 _Pmpf(("startup: \"%s\"", (ProgDetails.pszStartupDir) ? ProgDetails.pszStartupDir : "NULL"));
979 _Pmpf(("pszIcon: \"%s\"", (ProgDetails.pszIcon) ? ProgDetails.pszIcon : "NULL"));
980 _Pmpf(("environment: "));
981 {
982 PSZ pszThis = ProgDetails.pszEnvironment;
983 while (pszThis && *pszThis)
984 {
985 _Pmpf((" \"%s\"", pszThis));
986 pszThis += strlen(pszThis) + 1;
987 }
988 }
989
990 _Pmpf(("swpInitial.fl = 0x%lX, x = %d, y = %d, cx = %d, cy = %d:",
991 ProgDetails.swpInitial.fl,
992 ProgDetails.swpInitial.x,
993 ProgDetails.swpInitial.y,
994 ProgDetails.swpInitial.cx,
995 ProgDetails.swpInitial.cy));
996 _Pmpf((" behind = %d, hwnd = %d, res1 = %d, res2 = %d",
997 ProgDetails.swpInitial.hwndInsertBehind,
998 ProgDetails.swpInitial.hwnd,
999 ProgDetails.swpInitial.ulReserved1,
1000 ProgDetails.swpInitial.ulReserved2));
1001
1002 /* if (WinMessageBox(HWND_DESKTOP,
1003 NULLHANDLE,
1004 (ProgDetails.pszExecutable) ? ProgDetails.pszExecutable : "NULL",
1005 "Start?",
1006 0,
1007 MB_YESNO | MB_MOVEABLE)
1008 == MBID_YES) */
1009 happ = WinStartApp(hwndNotify,
1010 // receives WM_APPTERMINATENOTIFY
1011 &ProgDetails,
1012 strParamsPatched.psz,
1013 NULL, // "reserved", PMREF says...
1014 SAF_INSTALLEDCMDLINE);
1015 // we MUST use SAF_INSTALLEDCMDLINE
1016 // or no Win-OS/2 session will start...
1017 // whatever is going on here... Warp 4 FP11
1018
1019 // do not use SAF_STARTCHILDAPP, or the
1020 // app will be terminated automatically
1021 // when the WPS terminates!
1022
1023 // _Pmpf((__FUNCTION__ ": got happ 0x%lX", happ));
1024
1025 xstrClear(&strParamsPatched);
1026 if (pszWinOS2Env)
1027 free(pszWinOS2Env);
1028 } // end if (ProgDetails.pszExecutable)
1029
1030 return (happ);
1031}
1032
1033
Note: See TracBrowser for help on using the repository browser.