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

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

Lots of changes for icons and refresh.

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