source: trunk/src/helpers/dosh.c@ 52

Last change on this file since 52 was 52, 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: 71.3 KB
Line 
1
2/*
3 *@@sourcefile dosh.c:
4 * dosh.c contains Control Program helper functions.
5 *
6 * This file has miscellaneous system functions,
7 * drive helpers, file helpers, and partition functions.
8 *
9 * Usage: All OS/2 programs.
10 *
11 * Function prefixes (new with V0.81):
12 * -- dosh* Dos (Control Program) helper functions
13 *
14 * These funcs are forward-declared in dosh.h, which
15 * must be #include'd first.
16 *
17 * The resulting dosh.obj object file can be linked
18 * against any application object file. As opposed to
19 * the code in dosh2.c, it does not require any other
20 * code from the helpers.
21 *
22 * dosh.obj can also be used with the VAC subsystem
23 * library (/rn compiler option).
24 *
25 * Note: Version numbering in this file relates to XWorkplace version
26 * numbering.
27 *
28 *@@header "helpers\dosh.h"
29 */
30
31/*
32 * This file Copyright (C) 1997-2000 Ulrich M”ller.
33 * This file is part of the "XWorkplace helpers" source package.
34 * This is free software; you can redistribute it and/or modify
35 * it under the terms of the GNU General Public License as published
36 * by the Free Software Foundation, in version 2 as it comes in the
37 * "COPYING" file of the XWorkplace main distribution.
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
42 */
43
44#define OS2EMX_PLAIN_CHAR
45 // this is needed for "os2emx.h"; if this is defined,
46 // emx will define PSZ as _signed_ char, otherwise
47 // as unsigned char
48
49#define INCL_DOSMODULEMGR
50#define INCL_DOSPROCESS
51#define INCL_DOSSESMGR
52#define INCL_DOSQUEUES
53#define INCL_DOSMISC
54#define INCL_DOSDEVICES
55#define INCL_DOSDEVIOCTL
56#define INCL_DOSERRORS
57
58#define INCL_KBD
59#include <os2.h>
60
61#include <stdlib.h>
62#include <string.h>
63#include <stdio.h>
64
65#include "setup.h" // code generation and debugging options
66
67#include "helpers\dosh.h"
68
69#pragma hdrstop
70
71static const CHAR G_acDriveLetters[28] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
72
73/*
74 *@@category: Helpers\Control program helpers\Miscellaneous
75 * Miscellaneous helpers in dosh.c that didn't fit into any other
76 * category.
77 */
78
79/* ******************************************************************
80 *
81 * Miscellaneous
82 *
83 ********************************************************************/
84
85/*
86 *@@ doshGetChar:
87 * reads a single character from the keyboard.
88 * Useful for VIO sessions, since there's great
89 * confusion between the various C dialects about
90 * how to use getc(), and getc() doesn't work
91 * with the VAC subsystem library.
92 *
93 *@@added V0.9.4 (2000-07-27) [umoeller]
94 */
95
96CHAR doshGetChar(VOID)
97{
98 // CHAR c;
99 // ULONG ulRead = 0;
100
101 KBDKEYINFO kki;
102 KbdCharIn(&kki,
103 0, // wait
104 0);
105
106 return (kki.chChar);
107}
108
109/*
110 *@@ doshQueryShiftState:
111 * returns TRUE if any of the SHIFT keys are
112 * currently pressed. Useful for checks during
113 * WM_COMMAND messages from menus.
114 *
115 *@@changed V0.9.5 (2000-09-27) [umoeller]: added error checking
116 */
117
118BOOL doshQueryShiftState(VOID)
119{
120 BOOL brc = FALSE;
121 APIRET arc = NO_ERROR;
122 HFILE hfKbd;
123 ULONG ulAction;
124
125 arc = DosOpen("KBD$", &hfKbd, &ulAction, 0,
126 FILE_NORMAL, FILE_OPEN,
127 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE,
128 (PEAOP2)NULL);
129 if (arc == NO_ERROR)
130 {
131 SHIFTSTATE ShiftState;
132 ULONG cbDataLen = sizeof(ShiftState);
133
134 arc = DosDevIOCtl(hfKbd, IOCTL_KEYBOARD, KBD_GETSHIFTSTATE,
135 NULL, 0, NULL, // no parameters
136 &ShiftState, cbDataLen, &cbDataLen);
137 if (arc == NO_ERROR)
138 brc = ((ShiftState.fsState & 3) != 0);
139
140 DosClose(hfKbd);
141 }
142
143 return brc;
144}
145
146
147/*
148 *@@ doshIsWarp4:
149 * returns TRUE only if at least OS/2 Warp 4 is running.
150 *
151 *@@changed V0.9.2 (2000-03-05) [umoeller]: reported TRUE on Warp 3 also; fixed
152 *@@changed V0.9.6 (2000-10-16) [umoeller]: patched for speed
153 */
154
155BOOL doshIsWarp4(VOID)
156{
157 static BOOL s_brc = FALSE;
158 static BOOL s_fQueried = FALSE;
159 if (!s_fQueried)
160 {
161 // first call:
162 ULONG aulBuf[3];
163
164 DosQuerySysInfo(QSV_VERSION_MAJOR, // 11
165 QSV_VERSION_MINOR, // 12
166 &aulBuf, sizeof(aulBuf));
167 // Warp 3 is reported as 20.30
168 // Warp 4 is reported as 20.40
169 // Aurora is reported as 20.45
170
171 if ( (aulBuf[0] > 20) // major > 20; not the case with Warp 3, 4, 5
172 || ( (aulBuf[0] == 20) // major == 20 and minor >= 40
173 && (aulBuf[1] >= 40)
174 )
175 )
176 s_brc = TRUE;
177
178 s_fQueried = TRUE;
179 }
180
181 return (s_brc);
182}
183
184/*
185 *@@ doshQuerySysErrorMsg:
186 * this retrieves the error message for a system error
187 * (APIRET) from the system error message file (OSO001.MSG).
188 * This file better be on the DPATH (it normally is).
189 *
190 * This returns the string in the "SYSxxx: blahblah" style,
191 * which is normally displayed on the command line when
192 * errors occur.
193 *
194 * The error message is returned in a newly allocated
195 * buffer, which should be free()'d afterwards.
196 *
197 * Returns NULL upon errors.
198 */
199
200PSZ doshQuerySysErrorMsg(APIRET arc) // in: DOS error code
201{
202 PSZ pszReturn = 0;
203 CHAR szDosError[1000];
204 ULONG cbDosError = 0;
205 DosGetMessage(NULL, 0, // no string replacements
206 szDosError, sizeof(szDosError),
207 arc,
208 "OSO001.MSG", // default OS/2 message file
209 &cbDosError);
210 if (cbDosError > 2)
211 {
212 szDosError[cbDosError - 2] = 0;
213 pszReturn = strdup(szDosError);
214 }
215 return (pszReturn);
216}
217
218/*
219 *@@category: Helpers\Control program helpers\Shared memory management
220 * helpers for allocating and requesting shared memory.
221 */
222
223/* ******************************************************************
224 *
225 * Memory helpers
226 *
227 ********************************************************************/
228
229/*
230 *@@ doshAllocSharedMem:
231 * wrapper for DosAllocSharedMem which has
232 * a malloc()-like syntax. Just due to my
233 * lazyness.
234 *
235 * Note that ulSize is always rounded up to the
236 * next 4KB value, so don't use this hundreds of times.
237 *
238 * Returns NULL upon errors. Possible errors include
239 * that a memory block calle pcszName has already been
240 * allocated.
241 *
242 * Use DosFreeMem(pvrc) to free the memory. The memory
243 * will only be freed if no other process has requested
244 * access.
245 *
246 *@@added V0.9.3 (2000-04-18) [umoeller]
247 */
248
249PVOID doshAllocSharedMem(ULONG ulSize, // in: requested mem block size (rounded up to 4KB)
250 const char* pcszName) // in: name of block ("\\SHAREMEM\\xxx") or NULL
251{
252 PVOID pvrc = NULL;
253 APIRET arc = DosAllocSharedMem((PVOID*)(&pvrc),
254 (PSZ)pcszName,
255 ulSize,
256 PAG_COMMIT | PAG_READ | PAG_WRITE);
257 if (arc == NO_ERROR)
258 return (pvrc);
259
260 return (NULL);
261}
262
263/*
264 *@@ doshRequestSharedMem:
265 * requests access to a block of named shared memory
266 * allocated by doshAllocSharedMem.
267 *
268 * Returns NULL upon errors.
269 *
270 * Use DosFreeMem(pvrc) to free the memory. The memory
271 * will only be freed if no other process has requested
272 * access.
273 *
274 *@@added V0.9.3 (2000-04-19) [umoeller]
275 */
276
277PVOID doshRequestSharedMem(const char *pcszName)
278{
279 PVOID pvrc = NULL;
280 APIRET arc = DosGetNamedSharedMem((PVOID*)(pvrc),
281 (PSZ)pcszName,
282 PAG_READ | PAG_WRITE);
283 if (arc == NO_ERROR)
284 return (pvrc);
285
286 return (NULL);
287}
288
289/*
290 *@@category: Helpers\Control program helpers\Drive management
291 * functions for managing drives... enumerating, testing,
292 * querying etc.
293 */
294
295/* ******************************************************************
296 *
297 * Drive helpers
298 *
299 ********************************************************************/
300
301/*
302 *@@ doshEnumDrives:
303 * this function enumerates all valid drive letters on
304 * the system by composing a string of drive letters
305 * in the buffer pointed to by pszBuffer, which should
306 * be 27 characters in size to hold information for
307 * all drives. The buffer will be null-terminated.
308 *
309 * If (pcszFileSystem != NULL), only drives matching
310 * the specified file system type (e.g. "HPFS") will
311 * be enumerated. If (pcszFileSystem == NULL), all
312 * drives will be enumerated.
313 *
314 * If (fSkipRemovables == TRUE), removeable drives will
315 * be skipped. This applies to floppy, CD-ROM, and
316 * virtual floppy drives. This will start the search
317 * at drive letter C: so that drives A: and B: will
318 * never be checked (to avoid the hardware bumps).
319 *
320 * Otherwise, the search starts at drive A:. Still,
321 * removeable drives will only be added if valid media
322 * is inserted.
323 *
324 *@@changed V0.9.4 (2000-07-03) [umoeller]: this stopped at the first invalid drive letter; fixed
325 *@@changed V0.9.4 (2000-07-03) [umoeller]: added fSkipRemoveables
326 */
327
328VOID doshEnumDrives(PSZ pszBuffer, // out: drive letters
329 const char *pcszFileSystem, // in: FS's to match or NULL
330 BOOL fSkipRemoveables) // in: if TRUE, only non-removeable disks will be returned
331{
332 CHAR szName[5] = "";
333 ULONG ulLogicalDrive = 1, // start with drive A:
334 ulFound = 0; // found drives count
335 APIRET arc = NO_ERROR; // return code
336
337 if (fSkipRemoveables)
338 // start with drive C:
339 ulLogicalDrive = 3;
340
341 // go thru the drives, start with C: (== 3), stop after Z: (== 26)
342 while (ulLogicalDrive <= 26)
343 {
344 UCHAR nonRemovable=0;
345 ULONG parmSize=2;
346 ULONG dataLen=1;
347
348 #pragma pack(1)
349 struct
350 {
351 UCHAR dummy,drive;
352 } parms;
353 #pragma pack()
354
355 parms.drive=(UCHAR)(ulLogicalDrive-1);
356 arc = DosDevIOCtl((HFILE)-1,
357 IOCTL_DISK,
358 DSK_BLOCKREMOVABLE,
359 &parms,
360 parmSize,
361 &parmSize,
362 &nonRemovable,
363 1,
364 &dataLen);
365
366 /* _Pmpf((" ul = %d, Drive %c: arc = %d nonRemoveable = %d",
367 ulLogicalDrive,
368 G_acDriveLetters[ulLogicalDrive],
369 arc,
370 nonRemovable)); */
371
372 if ( // fixed disk and non-removeable
373 ((arc == NO_ERROR) && (nonRemovable))
374 // or network drive:
375 || (arc == ERROR_NOT_SUPPORTED)
376 )
377 {
378 ULONG ulOrdinal = 0; // ordinal of entry in name list
379 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
380 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
381 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
382
383 szName[0] = G_acDriveLetters[ulLogicalDrive];
384 szName[1] = ':';
385 szName[2] = '\0';
386
387 arc = DosQueryFSAttach(szName, // logical drive of attached FS
388 ulOrdinal, // ignored for FSAIL_QUERYNAME
389 FSAIL_QUERYNAME, // return data for a Drive or Device
390 pfsqBuffer, // returned data
391 &cbBuffer); // returned data length
392
393 if (arc == NO_ERROR)
394 {
395 // The data for the last three fields in the FSQBUFFER2
396 // structure are stored at the offset of fsqBuffer.szName.
397 // Each data field following fsqBuffer.szName begins
398 // immediately after the previous item.
399 CHAR* pszFSDName = (PSZ)&(pfsqBuffer->szName) + (pfsqBuffer->cbName) + 1;
400 if (pcszFileSystem == NULL)
401 {
402 // enum-all mode: always copy
403 pszBuffer[ulFound] = szName[0]; // drive letter
404 ulFound++;
405 }
406 else if (strcmp(pszFSDName, pcszFileSystem) == 0)
407 {
408 pszBuffer[ulFound] = szName[0]; // drive letter
409 ulFound++;
410 }
411 }
412 }
413
414 ulLogicalDrive++;
415 } // end while (G_acDriveLetters[ulLogicalDrive] <= 'Z')
416
417 pszBuffer[ulFound] = '\0';
418}
419
420/*
421 *@@ doshQueryBootDrive:
422 * returns the letter of the boot drive as a
423 * single (capital) character, which is useful for
424 * constructing file names using sprintf and such.
425 */
426
427CHAR doshQueryBootDrive(VOID)
428{
429 ULONG ulBootDrive;
430 DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
431 &ulBootDrive,
432 sizeof(ulBootDrive));
433 return (G_acDriveLetters[ulBootDrive]);
434}
435
436/*
437 *@@ doshAssertDrive:
438 * this checks for whether the given drive
439 * is currently available without provoking
440 * those ugly white "Drive not ready" popups.
441 *
442 * This returns (from my testing):
443 * -- NO_ERROR: drive is available.
444 * -- ERROR_INVALID_DRIVE (15): drive letter does not exist.
445 * -- ERROR_NOT_READY (21): drive exists, but is not ready
446 * (e.g. CD-ROM drive without CD inserted).
447 * -- ERROR_NOT_SUPPORTED (50): this is returned by the RAMFS.IFS
448 * file system; apparently, the IFS doesn't support
449 * DASD opening.
450 *
451 *@@changed V0.9.1 (99-12-13) [umoeller]: rewritten, prototype changed. Now using DosOpen on the drive instead of DosError.
452 *@@changed V0.9.1 (2000-01-08) [umoeller]: DosClose was called even if DosOpen failed, which messed up OS/2 error handling.
453 *@@changed V0.9.1 (2000-02-09) [umoeller]: this didn't work for network drives, including RAMFS; fixed.
454 *@@changed V0.9.3 (2000-03-28) [umoeller]: added check for network drives, which weren't working
455 *@@changed V0.9.4 (2000-08-03) [umoeller]: more network fixes
456 *@@changed V0.9.9 (2001-03-19) [pr]: validate drive number
457 */
458
459APIRET doshAssertDrive(ULONG ulLogicalDrive) // in: 1 for A:, 2 for B:, 3 for C:, ...
460{
461 CHAR szDrive[3] = "C:";
462 HFILE hfDrive = 0;
463 ULONG ulTemp = 0;
464 APIRET arc;
465
466 if ((ulLogicalDrive < 1) || (ulLogicalDrive > 26))
467 return(ERROR_PATH_NOT_FOUND);
468
469 szDrive[0] = 'A' + ulLogicalDrive - 1;
470
471 arc = DosOpen(szDrive, // "C:", "D:", ...
472 &hfDrive,
473 &ulTemp,
474 0,
475 FILE_NORMAL,
476 OPEN_ACTION_FAIL_IF_NEW
477 | OPEN_ACTION_OPEN_IF_EXISTS,
478 OPEN_FLAGS_DASD
479 | OPEN_FLAGS_FAIL_ON_ERROR
480 | OPEN_FLAGS_NOINHERIT // V0.9.6 (2000-11-25) [pr]
481 | OPEN_ACCESS_READONLY
482 | OPEN_SHARE_DENYNONE,
483 NULL);
484
485 // _Pmpf((__FUNCTION__ ": DosOpen(OPEN_FLAGS_DASD) returned %d", arc));
486
487 switch (arc)
488 {
489 case ERROR_NETWORK_ACCESS_DENIED: // 65
490 // added V0.9.3 (2000-03-27) [umoeller];
491 // according to user reports, this is returned
492 // by all network drives, which apparently don't
493 // support DASD DosOpen
494 case ERROR_ACCESS_DENIED: // 5
495 // added V0.9.4 (2000-07-10) [umoeller]
496 // LAN drives still didn't work... apparently
497 // the above only works for NFS drives
498 case ERROR_PATH_NOT_FOUND: // 3
499 // added V0.9.4 (2000-08-03) [umoeller]:
500 // this is returned by some other network types...
501 // sigh...
502 case ERROR_NOT_SUPPORTED: // 50
503 {
504 // this is returned by file systems which don't
505 // support DASD DosOpen;
506 // use some other method then, this isn't likely
507 // to fail -- V0.9.1 (2000-02-09) [umoeller]
508 FSALLOCATE fsa;
509 arc = DosQueryFSInfo(ulLogicalDrive,
510 FSIL_ALLOC,
511 &fsa,
512 sizeof(fsa));
513 break; }
514
515 case NO_ERROR:
516 DosClose(hfDrive);
517 break;
518 }
519
520 return (arc);
521
522 /* FSALLOCATE fsa;
523 APIRET arc = NO_ERROR;
524
525 if (fSuppress)
526 {
527 DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
528 DosEnterCritSec();
529 }
530
531 arc = DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa));
532
533 if (fSuppress)
534 {
535 DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
536 DosExitCritSec();
537 }
538
539 return (arc); */
540}
541
542/*
543 *@@ doshSetLogicalMap:
544 * sets the mapping of logical floppy drives onto a single
545 * physical floppy drive.
546 * This means selecting either drive A: or drive B: to refer
547 * to the physical drive.
548 *
549 *@@added V0.9.6 (2000-11-24) [pr]
550 */
551
552APIRET doshSetLogicalMap(ULONG ulLogicalDrive)
553{
554 CHAR name[3] = "?:";
555 ULONG fd = 0,
556 action = 0,
557 paramsize = 0,
558 datasize = 0;
559 APIRET rc = NO_ERROR;
560 USHORT data,
561 param;
562
563 name[0] = doshQueryBootDrive();
564 rc = DosOpen(name,
565 &fd,
566 &action,
567 0,
568 0,
569 OPEN_ACTION_FAIL_IF_NEW
570 | OPEN_ACTION_OPEN_IF_EXISTS,
571 OPEN_FLAGS_DASD
572 | OPEN_FLAGS_FAIL_ON_ERROR
573 | OPEN_FLAGS_NOINHERIT
574 | OPEN_ACCESS_READONLY
575 | OPEN_SHARE_DENYNONE,
576 0);
577 if (rc == NO_ERROR)
578 {
579 param = 0;
580 data = (USHORT)ulLogicalDrive;
581 paramsize = sizeof(param);
582 datasize = sizeof(data);
583 rc = DosDevIOCtl(fd,
584 IOCTL_DISK, DSK_SETLOGICALMAP,
585 &param, paramsize, &paramsize,
586 &data, datasize, &datasize);
587 DosClose(fd);
588 }
589
590 return(rc);
591}
592
593/*
594 *@@ doshQueryDiskFree:
595 * returns the number of bytes remaining on the disk
596 * specified by the given logical drive.
597 *
598 * Note: This returns a "double" value, because a ULONG
599 * can only hold values of some 4 billion, which would
600 * lead to funny results for drives > 4 GB.
601 *
602 *@@changed V0.9.0 [umoeller]: fixed another > 4 GB bug (thanks to Rdiger Ihle)
603 *@@changed V0.9.7 (2000-12-01) [umoeller]: changed prototype
604 */
605
606APIRET doshQueryDiskFree(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
607 double *pdFree)
608{
609 APIRET arc = NO_ERROR;
610 FSALLOCATE fsa;
611 double dbl = -1;
612
613 arc = DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa));
614 if (arc == NO_ERROR)
615 *pdFree = ((double)fsa.cSectorUnit * fsa.cbSector * fsa.cUnitAvail);
616 // ^ fixed V0.9.0
617
618 return (arc);
619}
620
621/*
622 *@@ doshQueryDiskFSType:
623 * copies the file-system type of the given disk object
624 * (HPFS, FAT, CDFS etc.) to pszBuf.
625 * Returns the DOS error code.
626 *
627 *@@changed V0.9.1 (99-12-12) [umoeller]: added cbBuf to prototype
628 */
629
630APIRET doshQueryDiskFSType(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
631 PSZ pszBuf, // out: buffer for FS type
632 ULONG cbBuf) // in: size of that buffer
633{
634 APIRET arc = NO_ERROR;
635 CHAR szName[5];
636
637 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
638 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
639 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
640
641 // compose "D:"-type string from logical drive letter
642 szName[0] = G_acDriveLetters[ulLogicalDrive];
643 szName[1] = ':';
644 szName[2] = '\0';
645
646 arc = DosQueryFSAttach(szName, // logical drive of attached FS ("D:"-style)
647 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
648 FSAIL_QUERYNAME, // return name for a drive or device
649 pfsqBuffer, // buffer for returned data
650 &cbBuffer); // sizeof(*pfsqBuffer)
651
652 if (arc == NO_ERROR)
653 {
654 if (pszBuf)
655 {
656 // The data for the last three fields in the FSQBUFFER2
657 // structure are stored at the offset of fsqBuffer.szName.
658 // Each data field following fsqBuffer.szName begins
659 // immediately after the previous item.
660 strcpy(pszBuf,
661 (CHAR*)(&pfsqBuffer->szName) + pfsqBuffer->cbName + 1);
662 }
663 }
664
665 return (arc);
666}
667
668/*
669 *@@ doshIsFixedDisk:
670 * checks whether a disk is fixed or removeable.
671 * ulLogicalDrive must be 1 for drive A:, 2 for B:, ...
672 * The result is stored in *pfFixed.
673 * Returns DOS error code.
674 *
675 * Warning: This uses DosDevIOCtl, which has proved
676 * to cause problems with some device drivers for
677 * removeable disks.
678 */
679
680APIRET doshIsFixedDisk(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
681 PBOOL pfFixed) // out: TRUE for fixed disks
682{
683 APIRET arc = ERROR_INVALID_DRIVE;
684
685 if (ulLogicalDrive)
686 {
687 // parameter packet
688 #pragma pack(1)
689 struct {
690 UCHAR command, drive;
691 } parms;
692 #pragma pack()
693
694 // data packet
695 UCHAR ucNonRemoveable;
696
697 ULONG ulParmSize = sizeof(parms);
698 ULONG ulDataSize = sizeof(ucNonRemoveable);
699
700 parms.drive = (UCHAR)(ulLogicalDrive-1);
701 arc = DosDevIOCtl((HFILE)-1,
702 IOCTL_DISK,
703 DSK_BLOCKREMOVABLE,
704 &parms,
705 ulParmSize,
706 &ulParmSize,
707 &ucNonRemoveable,
708 ulDataSize,
709 &ulDataSize);
710
711 if (arc == NO_ERROR)
712 *pfFixed = (BOOL)ucNonRemoveable;
713 }
714
715 return (arc);
716}
717
718/*
719 *@@ doshQueryDiskParams:
720 * this retrieves more information about a given drive,
721 * which is stored in the specified DRIVEPARAMS structure
722 * (dosh.h).
723 *
724 * Warning: This uses DosDevIOCtl, which has proved
725 * to cause problems with some device drivers for
726 * removeable disks.
727 *
728 * This returns the DOS error code of DosDevIOCtl.
729 *
730 *@@added V0.9.0 [umoeller]
731 */
732
733APIRET doshQueryDiskParams(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
734 PDRIVEPARAMS pdp) // out: drive parameters
735{
736 APIRET arc = ERROR_INVALID_DRIVE;
737
738 if (ulLogicalDrive)
739 {
740 #pragma pack(1)
741 // parameter packet
742 struct {
743 UCHAR command, drive;
744 } parms;
745 #pragma pack()
746
747 ULONG ulParmSize = sizeof(parms);
748 ULONG ulDataSize = sizeof(DRIVEPARAMS);
749
750 parms.command = 1; // read currently inserted media
751 parms.drive=(UCHAR)(ulLogicalDrive-1);
752
753 arc = DosDevIOCtl((HFILE)-1,
754 IOCTL_DISK,
755 DSK_GETDEVICEPARAMS,
756 // parameter packet:
757 &parms, ulParmSize, &ulParmSize,
758 // data packet: DRIVEPARAMS structure
759 pdp, ulDataSize, &ulDataSize);
760 }
761
762 return (arc);
763}
764
765/*
766 *@@ doshQueryDiskLabel:
767 * this returns the label of a disk into
768 * *pszVolumeLabel, which must be 12 bytes
769 * in size.
770 *
771 * This function was added because the Toolkit
772 * information for DosQueryFSInfo is only partly
773 * correct. On OS/2 2.x, that function does not
774 * take an FSINFO structure as input, but a VOLUMELABEL.
775 * On Warp, this does take an FSINFO.
776 *
777 * DosSetFSInfo is even worse. See doshSetDiskLabel.
778 *
779 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
780 * for details.
781 *
782 *@@added V0.9.0 [umoeller]
783 */
784
785APIRET doshQueryDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
786 PSZ pszVolumeLabel) // out: volume label (must be 12 chars in size)
787{
788 APIRET arc;
789
790 #ifdef __OS2V2X__
791 VOLUMELABEL FSInfoBuf;
792 #else
793 FSINFO FSInfoBuf;
794 #endif
795
796 arc = DosQueryFSInfo(ulLogicalDrive,
797 FSIL_VOLSER,
798 &FSInfoBuf,
799 sizeof(FSInfoBuf)); // depends
800
801 #ifdef __OS2V2X__
802 strcpy(pszVolumeLabel, FSInfoBuf.szVolLabel);
803 #else
804 strcpy(pszVolumeLabel, FSInfoBuf.vol.szVolLabel);
805 #endif
806
807 return (arc);
808}
809
810/*
811 *@@ doshSetDiskLabel:
812 * this sets the label of a disk.
813 *
814 * This function was added because the Toolkit
815 * information for DosSetFSInfo is flat out wrong.
816 * That function does not take an FSINFO structure
817 * as input, but a VOLUMELABEL. As a result, using
818 * that function with the Toolkit's calling specs
819 * results in ERROR_LABEL_TOO_LONG always.
820 *
821 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
822 * for details.
823 *
824 *@@added V0.9.0 [umoeller]
825 */
826
827APIRET doshSetDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
828 PSZ pszNewLabel)
829{
830 VOLUMELABEL FSInfoBuf;
831
832 // check length; 11 chars plus null byte allowed
833 FSInfoBuf.cch = (BYTE)strlen(pszNewLabel);
834 if (FSInfoBuf.cch < sizeof(FSInfoBuf.szVolLabel))
835 {
836 strcpy(FSInfoBuf.szVolLabel, pszNewLabel);
837
838 return (DosSetFSInfo(ulLogicalDrive,
839 FSIL_VOLSER,
840 &FSInfoBuf,
841 sizeof(FSInfoBuf)));
842 }
843 else
844 return (ERROR_LABEL_TOO_LONG);
845}
846
847/*
848 *@@category: Helpers\Control program helpers\File management
849 */
850
851/* ******************************************************************
852 *
853 * File helpers
854 *
855 ********************************************************************/
856
857/*
858 *@@ doshGetExtension:
859 * finds the file name extension of pszFilename,
860 * which can be a file name only or a fully
861 * qualified filename.
862 *
863 * This returns a pointer into pszFilename to
864 * the character after the last dot.
865 *
866 * Returns NULL if not found (e.g. if the filename
867 * has no dot in it).
868 *
869 *@@added V0.9.6 (2000-10-16) [umoeller]
870 *@@changed V0.9.7 (2000-12-10) [umoeller]: fixed "F:filename.ext" case
871 */
872
873PSZ doshGetExtension(const char *pcszFilename)
874{
875 PSZ pReturn = NULL;
876
877 if (pcszFilename)
878 {
879 // find filename
880 const char *p2 = strrchr(pcszFilename + 2, '\\'),
881 // works on "C:\blah" or "\\unc\blah"
882 *pStartOfName = NULL,
883 *pExtension = NULL;
884
885 if (p2)
886 pStartOfName = p2 + 1;
887 else
888 {
889 // no backslash found:
890 // maybe only a drive letter was specified:
891 if (*(pcszFilename + 1) == ':')
892 // yes:
893 pStartOfName = pcszFilename + 2;
894 else
895 // then this is not qualified at all...
896 // use start of filename
897 pStartOfName = (PSZ)pcszFilename;
898 }
899
900 // find last dot in filename
901 pExtension = strrchr(pStartOfName, '.');
902 if (pExtension)
903 pReturn = (PSZ)pExtension + 1;
904 }
905
906 return (pReturn);
907}
908
909/*
910 *@@ doshIsFileOnFAT:
911 * returns TRUE if pszFileName resides on
912 * a FAT drive. Note that pszFileName must
913 * be fully qualified (i.e. the drive letter
914 * must be the first character), or this will
915 * return garbage.
916 */
917
918BOOL doshIsFileOnFAT(const char* pcszFileName)
919{
920 BOOL brc = FALSE;
921 CHAR szName[5];
922
923 APIRET rc = NO_ERROR; // return code
924 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
925 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
926 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
927
928 szName[0] = pcszFileName[0]; // copy drive letter
929 szName[1] = ':';
930 szName[2] = '\0';
931
932 rc = DosQueryFSAttach(szName, // logical drive of attached FS
933 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
934 FSAIL_QUERYNAME, // return data for a Drive or Device
935 pfsqBuffer, // returned data
936 &cbBuffer); // returned data length
937
938 if (rc == NO_ERROR)
939 {
940 // The data for the last three fields in the FSQBUFFER2
941 // structure are stored at the offset of fsqBuffer.szName.
942 // Each data field following fsqBuffer.szName begins
943 // immediately after the previous item.
944 if (strncmp((PSZ)&(pfsqBuffer->szName) + pfsqBuffer->cbName + 1,
945 "FAT",
946 3)
947 == 0)
948 brc = TRUE;
949 }
950
951 return (brc);
952}
953
954/*
955 *@@ doshQueryFileSize:
956 * returns the size of an already opened file
957 * or 0 upon errors.
958 * Use doshQueryPathSize to query the size of
959 * any file.
960 */
961
962ULONG doshQueryFileSize(HFILE hFile)
963{
964 FILESTATUS3 fs3;
965 if (DosQueryFileInfo(hFile, FIL_STANDARD, &fs3, sizeof(fs3)))
966 return (0);
967 else
968 return (fs3.cbFile);
969}
970
971/*
972 *@@ doshQueryPathSize:
973 * returns the size of any file,
974 * or 0 if the file could not be
975 * found.
976 * Use doshQueryFileSize instead to query the
977 * size if you have a HFILE.
978 */
979
980ULONG doshQueryPathSize(PSZ pszFile)
981{
982 FILESTATUS3 fs3;
983 if (DosQueryPathInfo(pszFile, FIL_STANDARD, &fs3, sizeof(fs3)))
984 return (0);
985 else
986 return (fs3.cbFile);
987}
988
989/*
990 *@@ doshQueryPathAttr:
991 * returns the file attributes of pszFile,
992 * which can be fully qualified. The
993 * attributes will be stored in *pulAttr.
994 * pszFile can also specify a directory,
995 * although not all attributes make sense
996 * for directories.
997 *
998 * fAttr can be:
999 * -- FILE_ARCHIVED
1000 * -- FILE_READONLY
1001 * -- FILE_SYSTEM
1002 * -- FILE_HIDDEN
1003 *
1004 * This returns the APIRET of DosQueryPathAttr.
1005 * *pulAttr is only valid if NO_ERROR is
1006 * returned.
1007 *
1008 *@@added V0.9.0 [umoeller]
1009 */
1010
1011APIRET doshQueryPathAttr(const char* pcszFile, // in: file or directory name
1012 PULONG pulAttr) // out: attributes
1013{
1014 FILESTATUS3 fs3;
1015 APIRET arc = DosQueryPathInfo((PSZ)pcszFile,
1016 FIL_STANDARD,
1017 &fs3,
1018 sizeof(fs3));
1019 if (arc == NO_ERROR)
1020 {
1021 if (pulAttr)
1022 *pulAttr = fs3.attrFile;
1023 }
1024
1025 return (arc);
1026}
1027
1028/*
1029 *@@ doshSetPathAttr:
1030 * sets the file attributes of pszFile,
1031 * which can be fully qualified.
1032 * pszFile can also specify a directory,
1033 * although not all attributes make sense
1034 * for directories.
1035 *
1036 * fAttr can be:
1037 * -- FILE_ARCHIVED
1038 * -- FILE_READONLY
1039 * -- FILE_SYSTEM
1040 * -- FILE_HIDDEN
1041 *
1042 * Note that this simply sets all the given
1043 * attributes; the existing attributes
1044 * are lost.
1045 *
1046 * This returns the APIRET of DosQueryPathInfo.
1047 */
1048
1049APIRET doshSetPathAttr(const char* pcszFile, // in: file or directory name
1050 ULONG ulAttr) // in: new attributes
1051{
1052 FILESTATUS3 fs3;
1053 APIRET rc = DosQueryPathInfo((PSZ)pcszFile,
1054 FIL_STANDARD,
1055 &fs3,
1056 sizeof(fs3));
1057
1058 if (rc == NO_ERROR)
1059 {
1060 fs3.attrFile = ulAttr;
1061 rc = DosSetPathInfo((PSZ)pcszFile,
1062 FIL_STANDARD,
1063 &fs3,
1064 sizeof(fs3),
1065 DSPI_WRTTHRU);
1066 }
1067 return (rc);
1068}
1069
1070/*
1071 *@@ doshLoadTextFile:
1072 * reads a text file from disk, allocates memory
1073 * via malloc() and sets a pointer to this
1074 * buffer (or NULL upon errors).
1075 *
1076 * This returns the APIRET of DosOpen and DosRead.
1077 * If any error occured, no buffer was allocated.
1078 * Otherwise, you should free() the buffer when
1079 * no longer needed.
1080 *
1081 *@@changed V0.9.7 (2001-01-15) [umoeller]: renamed from doshReadTextFile
1082 */
1083
1084APIRET doshLoadTextFile(const char *pcszFile, // in: file name to read
1085 PSZ* ppszContent) // out: newly allocated buffer with file's content
1086{
1087 ULONG ulSize,
1088 ulBytesRead = 0,
1089 ulAction, ulLocal;
1090 HFILE hFile;
1091 PSZ pszContent = NULL;
1092
1093 APIRET arc = DosOpen((PSZ)pcszFile,
1094 &hFile,
1095 &ulAction, // action taken
1096 5000L, // primary allocation size
1097 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1098 OPEN_ACTION_OPEN_IF_EXISTS, // open flags
1099 OPEN_FLAGS_NOINHERIT
1100 | OPEN_SHARE_DENYNONE
1101 | OPEN_ACCESS_READONLY, // read-only mode
1102 NULL); // no EAs
1103
1104 if (arc == NO_ERROR)
1105 {
1106 ulSize = doshQueryFileSize(hFile);
1107 pszContent = (PSZ)malloc(ulSize+1);
1108 arc = DosSetFilePtr(hFile,
1109 0L,
1110 FILE_BEGIN,
1111 &ulLocal);
1112 arc = DosRead(hFile,
1113 pszContent,
1114 ulSize,
1115 &ulBytesRead);
1116 DosClose(hFile);
1117 *(pszContent+ulBytesRead) = 0;
1118
1119 // set output buffer pointer
1120 *ppszContent = pszContent;
1121 }
1122 else
1123 *ppszContent = 0;
1124
1125 return (arc);
1126}
1127
1128/*
1129 *@@ doshCreateBackupFileName:
1130 * creates a valid backup filename of pszExisting
1131 * with a numerical file name extension which does
1132 * not exist in the directory where pszExisting
1133 * resides.
1134 * Returns a PSZ to a new buffer which was allocated
1135 * using malloc().
1136 *
1137 * <B>Example:</B> returns "C:\CONFIG.002" for input
1138 * "C:\CONFIG.SYS" if "C:\CONFIG.001" already exists.
1139 *
1140 *@@changed V0.9.1 (99-12-13) [umoeller]: this crashed if pszExisting had no file extension
1141 */
1142
1143PSZ doshCreateBackupFileName(const char* pszExisting)
1144{
1145 CHAR szFilename[CCHMAXPATH];
1146 PSZ pszLastDot;
1147 ULONG ulCount = 1;
1148 CHAR szCount[5];
1149
1150 strcpy(szFilename, pszExisting);
1151 pszLastDot = strrchr(szFilename, '.');
1152 if (!pszLastDot)
1153 // no dot in filename:
1154 pszLastDot = szFilename + strlen(szFilename);
1155 do
1156 {
1157 sprintf(szCount, ".%03lu", ulCount);
1158 strcpy(pszLastDot, szCount);
1159 ulCount++;
1160 } while (doshQueryPathSize(szFilename) != 0);
1161
1162 return (strdup(szFilename));
1163}
1164
1165/*
1166 *@@ doshWriteTextFile:
1167 * writes a text file to disk; pszFile must contain the
1168 * whole path and filename.
1169 *
1170 * An existing file will be backed up if (pszBackup != NULL),
1171 * using doshCreateBackupFileName. In that case, pszBackup
1172 * receives the name of the backup created, so that buffer
1173 * should be CCHMAXPATH in size.
1174 *
1175 * If (pszbackup == NULL), an existing file will be overwritten.
1176 *
1177 * On success (NO_ERROR returned), *pulWritten receives
1178 * the no. of bytes written.
1179 *
1180 *@@changed V0.9.3 (2000-05-01) [umoeller]: optimized DosOpen; added error checking; changed prototype
1181 *@@changed V0.9.3 (2000-05-12) [umoeller]: added pszBackup
1182 */
1183
1184APIRET doshWriteTextFile(const char* pszFile, // in: file name
1185 const char* pszContent, // in: text to write
1186 PULONG pulWritten, // out: bytes written (ptr can be NULL)
1187 PSZ pszBackup) // in/out: create-backup?
1188{
1189 APIRET arc = NO_ERROR;
1190 ULONG ulWritten = 0;
1191
1192 if ((!pszFile) || (!pszContent))
1193 arc = ERROR_INVALID_PARAMETER;
1194 else
1195 {
1196 ULONG ulAction = 0,
1197 ulLocal = 0;
1198 HFILE hFile = 0;
1199
1200 ULONG ulSize = strlen(pszContent); // exclude 0 byte
1201
1202 if (pszBackup)
1203 {
1204 PSZ pszBackup2 = doshCreateBackupFileName(pszFile);
1205 DosCopy((PSZ)pszFile,
1206 pszBackup2,
1207 DCPY_EXISTING); // delete existing
1208 strcpy(pszBackup, pszBackup2);
1209 free(pszBackup2);
1210 }
1211
1212 arc = DosOpen((PSZ)pszFile,
1213 &hFile,
1214 &ulAction, // action taken
1215 ulSize, // primary allocation size
1216 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1217 OPEN_ACTION_CREATE_IF_NEW
1218 | OPEN_ACTION_REPLACE_IF_EXISTS, // open flags
1219 OPEN_FLAGS_NOINHERIT
1220 | OPEN_FLAGS_SEQUENTIAL // sequential, not random access
1221 | OPEN_SHARE_DENYWRITE // deny write mode
1222 | OPEN_ACCESS_WRITEONLY, // write mode
1223 NULL); // no EAs
1224
1225 if (arc == NO_ERROR)
1226 {
1227 arc = DosSetFilePtr(hFile,
1228 0L,
1229 FILE_BEGIN,
1230 &ulLocal);
1231 if (arc == NO_ERROR)
1232 {
1233 arc = DosWrite(hFile,
1234 (PVOID)pszContent,
1235 ulSize,
1236 &ulWritten);
1237 if (arc == NO_ERROR)
1238 arc = DosSetFileSize(hFile, ulSize);
1239 }
1240
1241 DosClose(hFile);
1242 }
1243 } // end if ((pszFile) && (pszContent))
1244
1245 if (pulWritten)
1246 *pulWritten = ulWritten;
1247
1248 return (arc);
1249}
1250
1251/*
1252 *@@ doshOpenLogFile:
1253 * this opens a log file in the root directory of
1254 * the boot drive; it is titled pszFilename, and
1255 * the file handle is returned.
1256 */
1257
1258HFILE doshOpenLogFile(const char* pcszFilename)
1259{
1260 APIRET rc;
1261 CHAR szFileName[CCHMAXPATH];
1262 HFILE hfLog;
1263 ULONG ulAction;
1264 ULONG ibActual;
1265
1266 sprintf(szFileName, "%c:\\%s", doshQueryBootDrive(), pcszFilename);
1267 rc = DosOpen(szFileName,
1268 &hfLog,
1269 &ulAction,
1270 0, // file size
1271 FILE_NORMAL,
1272 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
1273 OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
1274 (PEAOP2)NULL);
1275 if (rc == NO_ERROR)
1276 {
1277 DosSetFilePtr(hfLog, 0, FILE_END, &ibActual);
1278 return (hfLog);
1279 }
1280 else
1281 return (0);
1282}
1283
1284/*
1285 * doshWriteToLogFile
1286 * writes a string to a log file, adding a
1287 * leading timestamp.
1288 */
1289
1290APIRET doshWriteToLogFile(HFILE hfLog, const char* pcsz)
1291{
1292 if (hfLog)
1293 {
1294 DATETIME dt;
1295 CHAR szTemp[2000];
1296 ULONG cbWritten;
1297 DosGetDateTime(&dt);
1298 sprintf(szTemp, "Time: %02d:%02d:%02d %s",
1299 dt.hours, dt.minutes, dt.seconds,
1300 pcsz);
1301 return (DosWrite(hfLog, (PVOID)szTemp, strlen(szTemp), &cbWritten));
1302 }
1303 else return (ERROR_INVALID_HANDLE);
1304}
1305
1306/*
1307 *@@category: Helpers\Control program helpers\Directory management
1308 * directory helpers (querying, creating, deleting etc.).
1309 */
1310
1311/* ******************************************************************
1312 *
1313 * Directory helpers
1314 *
1315 ********************************************************************/
1316
1317/*
1318 *@@ doshQueryDirExist:
1319 * returns TRUE if the given directory
1320 * exists.
1321 */
1322
1323BOOL doshQueryDirExist(const char *pcszDir)
1324{
1325 FILESTATUS3 fs3;
1326 APIRET arc = DosQueryPathInfo((PSZ)pcszDir,
1327 FIL_STANDARD,
1328 &fs3,
1329 sizeof(fs3));
1330 if (arc == NO_ERROR)
1331 // file found:
1332 return ((fs3.attrFile & FILE_DIRECTORY) != 0);
1333 else
1334 return FALSE;
1335}
1336
1337/*
1338 *@@ doshCreatePath:
1339 * this creates the specified directory.
1340 * As opposed to DosCreateDir, this
1341 * function can create several directories
1342 * at the same time, if the parent
1343 * directories do not exist yet.
1344 */
1345
1346APIRET doshCreatePath(PSZ pszPath,
1347 BOOL fHidden) // in: if TRUE, the new directories will get FILE_HIDDEN
1348{
1349 APIRET arc0 = NO_ERROR;
1350 CHAR path[CCHMAXPATH];
1351 CHAR *cp, c;
1352 ULONG cbPath;
1353
1354 strcpy(path, pszPath);
1355 cbPath = strlen(path);
1356
1357 if (path[cbPath] != '\\')
1358 {
1359 path[cbPath] = '\\';
1360 path[cbPath+1] = 0;
1361 }
1362
1363 cp = path;
1364 // advance past the drive letter only if we have one
1365 if (*(cp+1) == ':')
1366 cp += 3;
1367
1368 // go!
1369 while (*cp != 0)
1370 {
1371 if (*cp == '\\')
1372 {
1373 c = *cp;
1374 *cp = 0;
1375 if (!doshQueryDirExist(path))
1376 {
1377 APIRET arc = DosCreateDir(path,
1378 0); // no EAs
1379 if (arc != NO_ERROR)
1380 {
1381 arc0 = arc;
1382 break;
1383 }
1384 else
1385 if (fHidden)
1386 {
1387 // hide the directory we just created
1388 doshSetPathAttr(path, FILE_HIDDEN);
1389 }
1390 }
1391 *cp = c;
1392 }
1393 cp++;
1394 }
1395 return (arc0);
1396}
1397
1398/*
1399 *@@ doshQueryCurrentDir:
1400 * writes the current directory into
1401 * the specified buffer, which should be
1402 * CCHMAXPATH in size.
1403 *
1404 * As opposed to DosQueryCurrentDir, this
1405 * includes the drive letter.
1406 *
1407 *@@added V0.9.4 (2000-07-22) [umoeller]
1408 */
1409
1410APIRET doshQueryCurrentDir(PSZ pszBuf)
1411{
1412 APIRET arc = NO_ERROR;
1413 ULONG ulCurDisk = 0;
1414 ULONG ulMap = 0;
1415 arc = DosQueryCurrentDisk(&ulCurDisk, &ulMap);
1416 if (arc == NO_ERROR)
1417 {
1418 ULONG cbBuf = CCHMAXPATH - 3;
1419 *pszBuf = G_acDriveLetters[ulCurDisk];
1420 *(pszBuf + 1) = ':';
1421 *(pszBuf + 2) = '\\';
1422 arc = DosQueryCurrentDir(0, pszBuf + 3, &cbBuf);
1423 }
1424
1425 return (arc);
1426}
1427
1428/*
1429 *@@ doshDeleteDir:
1430 * deletes a directory. As opposed to DosDeleteDir,
1431 * this removes empty subdirectories and/or files
1432 * as well.
1433 *
1434 * flFlags can be any combination of the following:
1435 *
1436 * -- DOSHDELDIR_RECURSE: recurse into subdirectories.
1437 *
1438 * -- DOSHDELDIR_DELETEFILES: delete all regular files
1439 * which are found on the way.
1440 *
1441 * THIS IS NOT IMPLEMENTED YET.
1442 *
1443 * If 0 is specified, this effectively behaves just as
1444 * DosDeleteDir.
1445 *
1446 * If you specify DOSHDELDIR_RECURSE only, only empty
1447 * subdirectories are deleted as well.
1448 *
1449 * If you specify DOSHDELDIR_RECURSE | DOSHDELDIR_DELETEFILES,
1450 * this removes an entire directory tree, including all
1451 * subdirectories and files.
1452 *
1453 *@@added V0.9.4 (2000-07-01) [umoeller]
1454 */
1455
1456APIRET doshDeleteDir(const char *pcszDir,
1457 ULONG flFlags,
1458 PULONG pulDirs, // out: directories found
1459 PULONG pulFiles) // out: files found
1460{
1461 APIRET arc = NO_ERROR,
1462 arcReturn = NO_ERROR;
1463
1464 HDIR hdirFindHandle = HDIR_CREATE;
1465 FILEFINDBUF3 ffb3 = {0}; // returned from FindFirst/Next
1466 ULONG ulResultBufLen = sizeof(FILEFINDBUF3);
1467 ULONG ulFindCount = 1; // look for 1 file at a time
1468
1469 CHAR szFileMask[2*CCHMAXPATH];
1470 sprintf(szFileMask, "%s\\*", pcszDir);
1471
1472 // find files
1473 arc = DosFindFirst(szFileMask,
1474 &hdirFindHandle, // directory search handle
1475 FILE_ARCHIVED | FILE_DIRECTORY | FILE_SYSTEM
1476 | FILE_HIDDEN | FILE_READONLY,
1477 // search attributes; include all, even dirs
1478 &ffb3, // result buffer
1479 ulResultBufLen, // result buffer length
1480 &ulFindCount, // number of entries to find
1481 FIL_STANDARD); // return level 1 file info
1482
1483 if (arc == NO_ERROR)
1484 {
1485 // keep finding the next file until there are no more files
1486 while (arc == NO_ERROR) // != ERROR_NO_MORE_FILES
1487 {
1488 if (ffb3.attrFile & FILE_DIRECTORY)
1489 {
1490 // we found a directory:
1491
1492 // ignore the pseudo-directories
1493 if ( (strcmp(ffb3.achName, ".") != 0)
1494 && (strcmp(ffb3.achName, "..") != 0)
1495 )
1496 {
1497 // real directory:
1498 if (flFlags & DOSHDELDIR_RECURSE)
1499 {
1500 // recurse!
1501 CHAR szSubDir[2*CCHMAXPATH];
1502 sprintf(szSubDir, "%s\\%s", pcszDir, ffb3.achName);
1503 arcReturn = doshDeleteDir(szSubDir,
1504 flFlags,
1505 pulDirs,
1506 pulFiles);
1507 // this removes ffb3.achName as well
1508 }
1509 else
1510 {
1511 // directory, but no recursion:
1512 // report "access denied"
1513 // (this is what OS/2 reports with DosDeleteDir as well)
1514 arcReturn = ERROR_ACCESS_DENIED; // 5
1515 (*pulDirs)++;
1516 }
1517 }
1518 }
1519 else
1520 {
1521 // it's a file:
1522 arcReturn = ERROR_ACCESS_DENIED;
1523 (*pulFiles)++;
1524 }
1525
1526 if (arc == NO_ERROR)
1527 {
1528 ulFindCount = 1; // reset find count
1529 arc = DosFindNext(hdirFindHandle, // directory handle
1530 &ffb3, // result buffer
1531 ulResultBufLen, // result buffer length
1532 &ulFindCount); // number of entries to find
1533 }
1534 } // endwhile
1535
1536 DosFindClose(hdirFindHandle); // close our find handle
1537 }
1538
1539 if (arcReturn == NO_ERROR)
1540 // success so far:
1541 // delete our directory now
1542 arc = DosDeleteDir((PSZ)pcszDir);
1543
1544 return (arcReturn);
1545}
1546
1547/*
1548 *@@category: Helpers\Control program helpers\Module handling
1549 * helpers for importing functions from a module (DLL).
1550 */
1551
1552/* ******************************************************************
1553 *
1554 * Module handling helpers
1555 *
1556 ********************************************************************/
1557
1558/*
1559 *@@ doshResolveImports:
1560 * this function loads the module called pszModuleName
1561 * and resolves imports dynamically using DosQueryProcAddress.
1562 *
1563 * To specify the functions to be imported, a RESOLVEFUNCTION
1564 * array is used. In each of the array items, specify the
1565 * name of the function and a pointer to a function pointer
1566 * where to store the resolved address.
1567 *
1568 *@@added V0.9.3 (2000-04-29) [umoeller]
1569 */
1570
1571APIRET doshResolveImports(PSZ pszModuleName, // in: DLL to load
1572 HMODULE *phmod, // out: module handle
1573 PRESOLVEFUNCTION paResolves, // in/out: function resolves
1574 ULONG cResolves) // in: array item count (not array size!)
1575{
1576 CHAR szName[CCHMAXPATH];
1577 APIRET arc = DosLoadModule(szName,
1578 sizeof(szName),
1579 pszModuleName,
1580 phmod);
1581 if (arc == NO_ERROR)
1582 {
1583 ULONG ul;
1584 for (ul = 0;
1585 ul < cResolves;
1586 ul++)
1587 {
1588 arc = DosQueryProcAddr(*phmod,
1589 0, // ordinal, ignored
1590 (PSZ)paResolves[ul].pcszFunctionName,
1591 paResolves[ul].ppFuncAddress);
1592
1593 /* _Pmpf(("Resolved %s to 0x%lX, rc: %d",
1594 paResolves[ul].pcszFunctionName,
1595 *paResolves[ul].ppFuncAddress,
1596 arc)); */
1597 if (arc != NO_ERROR)
1598 break;
1599 }
1600 }
1601
1602 return (arc);
1603}
1604
1605/*
1606 *@@category: Helpers\Control program helpers\Performance (CPU load) helpers
1607 * helpers around DosPerfSysCall.
1608 */
1609
1610/* ******************************************************************
1611 *
1612 * Performance Counters (CPU Load)
1613 *
1614 ********************************************************************/
1615
1616/*
1617 *@@ doshPerfOpen:
1618 * initializes the OS/2 DosPerfSysCall API for
1619 * the calling thread.
1620 *
1621 * Note: This API is not supported on all OS/2
1622 * versions. I believe it came up with some Warp 4
1623 * fixpak. The API is resolved dynamically by
1624 * this function (using DosQueryProcAddr). Only
1625 * if NO_ERROR is returned, you may call doshPerfGet
1626 * afterwards.
1627 *
1628 * This properly initializes the internal counters
1629 * which the OS/2 kernel uses for this API. Apparently,
1630 * with newer kernels (FP13/14), IBM has chosen to no
1631 * longer do this automatically, which is the reason
1632 * why many "pulse" utilities display garbage with these
1633 * fixpaks.
1634 *
1635 * After NO_ERROR is returned, DOSHPERFSYS.cProcessors
1636 * contains the no. of processors found on the system.
1637 * All pointers in DOSHPERFSYS then point to arrays
1638 * which have exactly cProcessors array items.
1639 *
1640 * Call doshPerfClose to clean up resources allocated
1641 * by this function.
1642 *
1643 * Example code:
1644 *
1645 + PDOSHPERFSYS pPerf = NULL;
1646 + APIRET arc = doshPerfOpen(&pPerf);
1647 + if (arc == NO_ERROR)
1648 + {
1649 + // this should really be in a timer
1650 + ULONG ulCPU;
1651 + arc = doshPerfGet(&pPerf);
1652 + // go thru all CPUs
1653 + for (ulCPU = 0; ulCPU < pPerf->cProcessors; ulCPU++)
1654 + {
1655 + LONG lLoadThis = pPerf->palLoads[ulCPU];
1656 + ...
1657 + }
1658 +
1659 + ...
1660 +
1661 + // clean up
1662 + doshPerfClose(&pPerf);
1663 + }
1664 +
1665 *
1666 *@@added V0.9.7 (2000-12-02) [umoeller]
1667 *@@changed V0.9.9 (2001-03-14) [umoeller]: added interrupt loads; thanks phaller
1668 */
1669
1670APIRET doshPerfOpen(PDOSHPERFSYS *ppPerfSys) // out: new DOSHPERFSYS structure
1671{
1672 APIRET arc = NO_ERROR;
1673
1674 // allocate DOSHPERFSYS structure
1675 *ppPerfSys = (PDOSHPERFSYS)malloc(sizeof(DOSHPERFSYS));
1676 if (!*ppPerfSys)
1677 arc = ERROR_NOT_ENOUGH_MEMORY;
1678 else
1679 {
1680 // initialize structure
1681 PDOSHPERFSYS pPerfSys = *ppPerfSys;
1682 memset(pPerfSys, 0, sizeof(*pPerfSys));
1683
1684 // resolve DosPerfSysCall API entry
1685 arc = DosLoadModule(NULL, 0, "DOSCALLS", &pPerfSys->hmod);
1686 if (arc == NO_ERROR)
1687 {
1688 arc = DosQueryProcAddr(pPerfSys->hmod,
1689 976,
1690 "DosPerfSysCall",
1691 (PFN*)(&pPerfSys->pDosPerfSysCall));
1692 if (arc == NO_ERROR)
1693 {
1694 // OK, we got the API: initialize!
1695 arc = pPerfSys->pDosPerfSysCall(CMD_KI_ENABLE, 0, 0, 0);
1696 if (arc == NO_ERROR)
1697 {
1698 pPerfSys->fInitialized = TRUE;
1699 // call CMD_KI_DISABLE later
1700
1701 arc = pPerfSys->pDosPerfSysCall(CMD_PERF_INFO,
1702 0,
1703 (ULONG)(&pPerfSys->cProcessors),
1704 0);
1705 if (arc == NO_ERROR)
1706 {
1707 ULONG ul = 0;
1708
1709 // allocate arrays
1710 pPerfSys->paCPUUtils = (PCPUUTIL)calloc(pPerfSys->cProcessors,
1711 sizeof(CPUUTIL));
1712 if (!pPerfSys->paCPUUtils)
1713 arc = ERROR_NOT_ENOUGH_MEMORY;
1714 else
1715 {
1716 pPerfSys->padBusyPrev = (double*)malloc(pPerfSys->cProcessors * sizeof(double));
1717 if (!pPerfSys->padBusyPrev)
1718 arc = ERROR_NOT_ENOUGH_MEMORY;
1719 else
1720 {
1721 pPerfSys->padTimePrev
1722 = (double*)malloc(pPerfSys->cProcessors * sizeof(double));
1723 if (!pPerfSys->padTimePrev)
1724 arc = ERROR_NOT_ENOUGH_MEMORY;
1725 else
1726 {
1727 pPerfSys->padIntrPrev
1728 = (double*)malloc(pPerfSys->cProcessors * sizeof(double));
1729 if (!pPerfSys->padIntrPrev)
1730 arc = ERROR_NOT_ENOUGH_MEMORY;
1731 else
1732 {
1733 pPerfSys->palLoads = (PLONG)malloc(pPerfSys->cProcessors * sizeof(LONG));
1734 if (!pPerfSys->palLoads)
1735 arc = ERROR_NOT_ENOUGH_MEMORY;
1736 else
1737 {
1738 // **patrick, this was missing...
1739 // wonder if you ever tested this, this crashes in
1740 // doshPerfGet otherwise ;-)
1741 /* -----------> */ pPerfSys->palIntrs = (PLONG)malloc(pPerfSys->cProcessors * sizeof(LONG));
1742 if (!pPerfSys->palIntrs)
1743 arc = ERROR_NOT_ENOUGH_MEMORY;
1744 else
1745 {
1746 for (ul = 0; ul < pPerfSys->cProcessors; ul++)
1747 {
1748 pPerfSys->padBusyPrev[ul] = 0.0;
1749 pPerfSys->padTimePrev[ul] = 0.0;
1750 pPerfSys->padIntrPrev[ul] = 0.0;
1751 pPerfSys->palLoads[ul] = 0;
1752 /* and this one too */ pPerfSys->palIntrs[ul] = 0;
1753 }
1754 }
1755 }
1756 }
1757 }
1758 }
1759 }
1760 }
1761 }
1762 } // end if (arc == NO_ERROR)
1763 } // end if (arc == NO_ERROR)
1764
1765 if (arc != NO_ERROR)
1766 {
1767 doshPerfClose(ppPerfSys);
1768 }
1769 } // end else if (!*ppPerfSys)
1770
1771 return (arc);
1772}
1773
1774/*
1775 *@@ doshPerfGet:
1776 * calculates a current snapshot of the system load,
1777 * compared with the load which was calculated on
1778 * the previous call.
1779 *
1780 * If you want to continually measure the system CPU
1781 * load, this is the function you will want to call
1782 * regularly -- e.g. with a timer once per second.
1783 *
1784 * Call this ONLY if doshPerfOpen returned NO_ERROR,
1785 * or you'll get crashes.
1786 *
1787 * If this call returns NO_ERROR, you get LONG load
1788 * values for each CPU in the system in the arrays
1789 * in DOSHPERFSYS (in per-mille, 0-1000).
1790 *
1791 * There are two arrays:
1792 *
1793 * -- DOSHPERFSYS.palLoads contains the "user" load
1794 * for each CPU.
1795 *
1796 * -- DOSHPERFSYS.palIntrs contains the "IRQ" load
1797 * for each CPU.
1798 *
1799 * Sum up the two values to get the total load for
1800 * each CPU.
1801 *
1802 * For example, if there are two CPUs, after this call,
1803 *
1804 * -- DOSHPERFSYS.palLoads[0] contains the "user" load
1805 * of the first CPU,
1806 *
1807 * -- DOSHPERFSYS.palLoads[0] contains the "user" load
1808 * of the second CPU.
1809 *
1810 * See doshPerfOpen for example code.
1811 *
1812 *@@added V0.9.7 (2000-12-02) [umoeller]
1813 *@@changed V0.9.9 (2001-03-14) [umoeller]: added interrupt loads; thanks phaller
1814 */
1815
1816APIRET doshPerfGet(PDOSHPERFSYS pPerfSys)
1817{
1818 APIRET arc = NO_ERROR;
1819 if (!pPerfSys->pDosPerfSysCall)
1820 arc = ERROR_INVALID_PARAMETER;
1821 else
1822 {
1823 arc = pPerfSys->pDosPerfSysCall(CMD_KI_RDCNT,
1824 (ULONG)pPerfSys->paCPUUtils,
1825 0, 0);
1826 if (arc == NO_ERROR)
1827 {
1828 // go thru all processors
1829 ULONG ul = 0;
1830 for (; ul < pPerfSys->cProcessors; ul++)
1831 {
1832 PCPUUTIL pCPUUtilThis = &pPerfSys->paCPUUtils[ul];
1833
1834 double dTime = LL2F(pCPUUtilThis->ulTimeHigh,
1835 pCPUUtilThis->ulTimeLow);
1836 double dBusy = LL2F(pCPUUtilThis->ulBusyHigh,
1837 pCPUUtilThis->ulBusyLow);
1838 double dIntr = LL2F(pCPUUtilThis->ulIntrHigh,
1839 pCPUUtilThis->ulIntrLow);
1840
1841 double *pdBusyPrevThis = &pPerfSys->padBusyPrev[ul];
1842 double *pdTimePrevThis = &pPerfSys->padTimePrev[ul];
1843 double *pdIntrPrevThis = &pPerfSys->padIntrPrev[ul];
1844
1845 // avoid division by zero
1846 double dTimeDelta = (dTime - *pdTimePrevThis);
1847 if (dTimeDelta)
1848 {
1849 pPerfSys->palLoads[ul]
1850 = (LONG)( (double)( (dBusy - *pdBusyPrevThis)
1851 / dTimeDelta
1852 * 1000.0
1853 )
1854 );
1855 pPerfSys->palIntrs[ul]
1856 = (LONG)( (double)( (dIntr - *pdIntrPrevThis)
1857 / dTimeDelta
1858 * 1000.0
1859 )
1860 );
1861 }
1862 else
1863 {
1864 // no clear readings are available
1865 pPerfSys->palLoads[ul] = 0;
1866 pPerfSys->palIntrs[ul] = 0;
1867 }
1868
1869 *pdTimePrevThis = dTime;
1870 *pdBusyPrevThis = dBusy;
1871 *pdIntrPrevThis = dIntr;
1872 }
1873 }
1874 }
1875
1876 return (arc);
1877}
1878
1879/*
1880 *@@ doshPerfClose:
1881 * frees all resources allocated by doshPerfOpen.
1882 *
1883 *@@added V0.9.7 (2000-12-02) [umoeller]
1884 *@@changed V0.9.9 (2001-02-06) [umoeller]: removed disable; this broke the WarpCenter
1885 *@@changed V0.9.9 (2001-03-14) [umoeller]: fixed memory leak
1886 *@@changed V0.9.9 (2001-03-14) [umoeller]: added interrupt loads; thanks phaller
1887 */
1888
1889APIRET doshPerfClose(PDOSHPERFSYS *ppPerfSys)
1890{
1891 APIRET arc = NO_ERROR;
1892 PDOSHPERFSYS pPerfSys = *ppPerfSys;
1893 if (!pPerfSys)
1894 arc = ERROR_INVALID_PARAMETER;
1895 else
1896 {
1897 // do not call this, this messes up the WarpCenter V0.9.9 (2001-02-06) [umoeller]
1898 // if (pPerfSys->fInitialized) pPerfSys->pDosPerfSysCall(CMD_KI_DISABLE, 0, 0, 0);
1899
1900 if (pPerfSys->paCPUUtils)
1901 free(pPerfSys->paCPUUtils);
1902 if (pPerfSys->padBusyPrev)
1903 free(pPerfSys->padBusyPrev);
1904 if (pPerfSys->padTimePrev)
1905 free(pPerfSys->padTimePrev);
1906 if (pPerfSys->padIntrPrev)
1907 free(pPerfSys->padIntrPrev);
1908 if (pPerfSys->palLoads) // was missing V0.9.9 (2001-03-14) [umoeller]
1909 free(pPerfSys->palLoads);
1910 if (pPerfSys->palIntrs)
1911 free(pPerfSys->palIntrs);
1912
1913 if (pPerfSys->hmod)
1914 DosFreeModule(pPerfSys->hmod);
1915 free(pPerfSys);
1916 *ppPerfSys = NULL;
1917 }
1918
1919 return (arc);
1920}
1921
1922/*
1923 *@@category: Helpers\Control program helpers\Process management
1924 * helpers for starting subprocesses.
1925 */
1926
1927/* ******************************************************************
1928 *
1929 * Process helpers
1930 *
1931 ********************************************************************/
1932
1933/*
1934 *@@ doshFindExecutable:
1935 * this searches the PATH for the specified pcszCommand
1936 * by calling DosSearchPath.
1937 *
1938 * papcszExtensions determines if additional searches are to be
1939 * performed if DosSearchPath returns ERROR_FILE_NOT_FOUND.
1940 * This must point to an array of strings specifying the extra
1941 * extensions to search for.
1942 *
1943 * If both papcszExtensions and cExtensions are null, no
1944 * extra searches are performed.
1945 *
1946 * If this returns NO_ERROR, pszExecutable receives
1947 * the full path of the executable found by DosSearchPath.
1948 * Otherwise ERROR_FILE_NOT_FOUND is returned.
1949 *
1950 * Example:
1951 *
1952 + const char *aExtensions[] = { "EXE",
1953 + "COM",
1954 + "CMD"
1955 + };
1956 + CHAR szExecutable[CCHMAXPATH];
1957 + APIRET arc = doshFindExecutable("lvm",
1958 + szExecutable,
1959 + sizeof(szExecutable),
1960 + aExtensions,
1961 + 3);
1962 *
1963 *@@added V0.9.9 (2001-03-07) [umoeller]
1964 */
1965
1966APIRET doshFindExecutable(const char *pcszCommand, // in: command (e.g. "lvm")
1967 PSZ pszExecutable, // out: full path (e.g. "F:\os2\lvm.exe")
1968 ULONG cbExecutable, // in: sizeof (*pszExecutable)
1969 const char **papcszExtensions, // in: array of extensions (without dots)
1970 ULONG cExtensions) // in: array item count
1971{
1972 APIRET arc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY,
1973 "PATH",
1974 (PSZ)pcszCommand,
1975 pszExecutable,
1976 cbExecutable);
1977 if ( (arc == ERROR_FILE_NOT_FOUND) // not found?
1978 && (cExtensions) // any extra searches wanted?
1979 )
1980 {
1981 // try additional things then
1982 PSZ psz2 = (PSZ)malloc(strlen(pcszCommand) + 20);
1983 if (psz2)
1984 {
1985 ULONG ul;
1986 for (ul = 0;
1987 ul < cExtensions;
1988 ul++)
1989 {
1990 const char *pcszExtThis = papcszExtensions[ul];
1991 sprintf(psz2, "%s.%s", pcszCommand, pcszExtThis);
1992 arc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY,
1993 "PATH",
1994 psz2,
1995 pszExecutable,
1996 cbExecutable);
1997 if (arc != ERROR_FILE_NOT_FOUND)
1998 break;
1999 }
2000
2001 free(psz2);
2002 }
2003 else
2004 arc = ERROR_NOT_ENOUGH_MEMORY;
2005 }
2006
2007 return (arc);
2008}
2009
2010/*
2011 *@@ doshExecVIO:
2012 * executes cmd.exe with the /c parameter
2013 * and pcszExecWithArgs. This is equivalent
2014 * to the C library system() function,
2015 * except that an OS/2 error code is returned
2016 * and that this works with the VAC subsystem
2017 * library.
2018 *
2019 * This uses DosExecPgm and handles the sick
2020 * argument passing.
2021 *
2022 * If NO_ERROR is returned, *plExitCode receives
2023 * the exit code of the process. If the process
2024 * was terminated abnormally, *plExitCode receives:
2025 *
2026 * -- -1: hard error halt
2027 * -- -2: 16-bit trap
2028 * -- -3: DosKillProcess
2029 * -- -4: 32-bit exception
2030 *
2031 *@@added V0.9.4 (2000-07-27) [umoeller]
2032 */
2033
2034APIRET doshExecVIO(const char *pcszExecWithArgs,
2035 PLONG plExitCode) // out: exit code (ptr can be NULL)
2036{
2037 APIRET arc = NO_ERROR;
2038
2039 if (strlen(pcszExecWithArgs) > 255)
2040 arc = ERROR_INSUFFICIENT_BUFFER;
2041 {
2042 CHAR szObj[CCHMAXPATH];
2043 RESULTCODES res = {0};
2044 CHAR szBuffer[300];
2045
2046 // DosExecPgm expects two args in szBuffer:
2047 // -- cmd.exe\0
2048 // -- then the actual argument, terminated by two 0 bytes.
2049 memset(szBuffer, 0, sizeof(szBuffer));
2050 strcpy(szBuffer, "cmd.exe\0");
2051 sprintf(szBuffer + 8, "/c %s",
2052 pcszExecWithArgs);
2053
2054 arc = DosExecPgm(szObj, sizeof(szObj),
2055 EXEC_SYNC,
2056 szBuffer,
2057 0,
2058 &res,
2059 "cmd.exe");
2060 if ((arc == NO_ERROR) && (plExitCode))
2061 {
2062 if (res.codeTerminate == 0)
2063 // normal exit:
2064 *plExitCode = res.codeResult;
2065 else
2066 *plExitCode = -((LONG)res.codeTerminate);
2067 }
2068 }
2069
2070 return (arc);
2071}
2072
2073/*
2074 *@@ doshQuickStartSession:
2075 * this is a shortcut to DosStartSession w/out having to
2076 * deal with all the messy parameters.
2077 *
2078 * This one starts pszPath as a child session and passes
2079 * pszParams to it.
2080 *
2081 * In usPgmCtl, OR any or none of the following (V0.9.0):
2082 * -- SSF_CONTROL_NOAUTOCLOSE (0x0008): do not close automatically.
2083 * This bit is used only for VIO Windowable apps and ignored
2084 * for all other applications.
2085 * -- SSF_CONTROL_MINIMIZE (0x0004)
2086 * -- SSF_CONTROL_MAXIMIZE (0x0002)
2087 * -- SSF_CONTROL_INVISIBLE (0x0001)
2088 * -- SSF_CONTROL_VISIBLE (0x0000)
2089 *
2090 * Specifying 0 will therefore auto-close the session and make it
2091 * visible.
2092 *
2093 * If (fWait), this function will create a termination queue
2094 * and not return until the child session has ended. Otherwise
2095 * the function will return immediately, and the SID/PID of
2096 * the child session can be found in *pulSID and *ppid.
2097 *
2098 * Returns the error code of DosStartSession.
2099 *
2100 * Note: According to CPREF, calling DosStartSession calls
2101 * DosExecPgm in turn for all full-screen, VIO, and PM sessions.
2102 *
2103 *@@changed V0.9.0 [umoeller]: prototype changed to include usPgmCtl
2104 *@@changed V0.9.1 (99-12-30) [umoeller]: queue was sometimes not closed. Fixed.
2105 *@@changed V0.9.3 (2000-05-03) [umoeller]: added fForeground
2106 */
2107
2108APIRET doshQuickStartSession(const char *pcszPath, // in: program to start
2109 const char *pcszParams, // in: parameters for program
2110 BOOL fForeground, // in: if TRUE, session will be in foreground
2111 USHORT usPgmCtl, // in: STARTDATA.PgmControl
2112 BOOL fWait, // in: wait for termination?
2113 PULONG pulSID, // out: session ID (req.)
2114 PPID ppid) // out: process ID (req.)
2115{
2116 APIRET arc;
2117 // queue stuff
2118 const char *pcszQueueName = "\\queues\\xwphlpsw.que";
2119 HQUEUE hq = 0;
2120 PID qpid = 0;
2121 STARTDATA SData;
2122 CHAR szObjBuf[CCHMAXPATH];
2123
2124 if (fWait)
2125 {
2126 if ((arc = DosCreateQueue(&hq,
2127 QUE_FIFO | QUE_CONVERT_ADDRESS,
2128 (PSZ)pcszQueueName))
2129 != NO_ERROR)
2130 return (arc);
2131
2132 if ((arc = DosOpenQueue(&qpid, &hq, (PSZ)pcszQueueName)) != NO_ERROR)
2133 return (arc);
2134 }
2135
2136 SData.Length = sizeof(STARTDATA);
2137 SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
2138 SData.FgBg = (fForeground) ? SSF_FGBG_FORE : SSF_FGBG_BACK;
2139 // V0.9.3 (2000-05-03) [umoeller]
2140 SData.TraceOpt = SSF_TRACEOPT_NONE;
2141
2142 SData.PgmTitle = (PSZ)pcszPath; // title for window
2143 SData.PgmName = (PSZ)pcszPath;
2144 SData.PgmInputs = (PSZ)pcszParams;
2145
2146 SData.TermQ = (fWait) ? (PSZ)pcszQueueName : NULL;
2147 SData.Environment = 0;
2148 SData.InheritOpt = SSF_INHERTOPT_PARENT;
2149 SData.SessionType = SSF_TYPE_DEFAULT;
2150 SData.IconFile = 0;
2151 SData.PgmHandle = 0;
2152
2153 SData.PgmControl = usPgmCtl;
2154
2155 SData.InitXPos = 30;
2156 SData.InitYPos = 40;
2157 SData.InitXSize = 200;
2158 SData.InitYSize = 140;
2159 SData.Reserved = 0;
2160 SData.ObjectBuffer = (CHAR*)&szObjBuf;
2161 SData.ObjectBuffLen = (ULONG)sizeof(szObjBuf);
2162
2163 arc = DosStartSession(&SData, pulSID, ppid);
2164
2165 if (arc == NO_ERROR)
2166 {
2167 if (fWait)
2168 {
2169 REQUESTDATA rqdata;
2170 ULONG DataLength = 0;
2171 PULONG DataAddress;
2172 BYTE elpri;
2173
2174 rqdata.pid = qpid;
2175 DosReadQueue(hq, // in: queue handle
2176 &rqdata, // out: pid and ulData
2177 &DataLength, // out: size of data returned
2178 (PVOID*)&DataAddress, // out: data returned
2179 0, // in: remove first element in queue
2180 0, // in: wait for queue data (block thread)
2181 &elpri, // out: element's priority
2182 0); // in: event semaphore to be posted
2183 }
2184 }
2185
2186 if (hq)
2187 DosCloseQueue(hq);
2188
2189 return (arc);
2190}
2191
2192
Note: See TracBrowser for help on using the repository browser.