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

Last change on this file since 43 was 43, 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: 68.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
71const 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 */
457
458APIRET doshAssertDrive(ULONG ulLogicalDrive) // in: 1 for A:, 2 for B:, 3 for C:, ...
459{
460 CHAR szDrive[3] = "C:";
461 HFILE hfDrive = 0;
462 ULONG ulTemp = 0;
463 APIRET arc;
464
465 szDrive[0] = 'A' + ulLogicalDrive - 1;
466
467 arc = DosOpen(szDrive, // "C:", "D:", ...
468 &hfDrive,
469 &ulTemp,
470 0,
471 FILE_NORMAL,
472 OPEN_ACTION_FAIL_IF_NEW
473 | OPEN_ACTION_OPEN_IF_EXISTS,
474 OPEN_FLAGS_DASD
475 | OPEN_FLAGS_FAIL_ON_ERROR
476 | OPEN_FLAGS_NOINHERIT // V0.9.6 (2000-11-25) [pr]
477 | OPEN_ACCESS_READONLY
478 | OPEN_SHARE_DENYNONE,
479 NULL);
480
481 // _Pmpf((__FUNCTION__ ": DosOpen(OPEN_FLAGS_DASD) returned %d", arc));
482
483 switch (arc)
484 {
485 case ERROR_NETWORK_ACCESS_DENIED: // 65
486 // added V0.9.3 (2000-03-27) [umoeller];
487 // according to user reports, this is returned
488 // by all network drives, which apparently don't
489 // support DASD DosOpen
490 case ERROR_ACCESS_DENIED: // 5
491 // added V0.9.4 (2000-07-10) [umoeller]
492 // LAN drives still didn't work... apparently
493 // the above only works for NFS drives
494 case ERROR_PATH_NOT_FOUND: // 3
495 // added V0.9.4 (2000-08-03) [umoeller]:
496 // this is returned by some other network types...
497 // sigh...
498 case ERROR_NOT_SUPPORTED: // 50
499 {
500 // this is returned by file systems which don't
501 // support DASD DosOpen;
502 // use some other method then, this isn't likely
503 // to fail -- V0.9.1 (2000-02-09) [umoeller]
504 FSALLOCATE fsa;
505 arc = DosQueryFSInfo(ulLogicalDrive,
506 FSIL_ALLOC,
507 &fsa,
508 sizeof(fsa));
509 break; }
510
511 case NO_ERROR:
512 DosClose(hfDrive);
513 break;
514 }
515
516 return (arc);
517
518 /* FSALLOCATE fsa;
519 APIRET arc = NO_ERROR;
520
521 if (fSuppress)
522 {
523 DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
524 DosEnterCritSec();
525 }
526
527 arc = DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa));
528
529 if (fSuppress)
530 {
531 DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
532 DosExitCritSec();
533 }
534
535 return (arc); */
536}
537
538/*
539 *@@ doshSetLogicalMap:
540 * sets the mapping of logical floppy drives onto a single
541 * physical floppy drive.
542 * This means selecting either drive A: or drive B: to refer
543 * to the physical drive.
544 *
545 *@@added V0.9.6 (2000-11-24) [pr]
546 */
547
548APIRET doshSetLogicalMap(ULONG ulLogicalDrive)
549{
550 CHAR name[3] = "?:";
551 ULONG fd = 0,
552 action = 0,
553 paramsize = 0,
554 datasize = 0;
555 APIRET rc = NO_ERROR;
556 USHORT data,
557 param;
558
559 name[0] = doshQueryBootDrive();
560 rc = DosOpen(name,
561 &fd,
562 &action,
563 0,
564 0,
565 OPEN_ACTION_FAIL_IF_NEW
566 | OPEN_ACTION_OPEN_IF_EXISTS,
567 OPEN_FLAGS_DASD
568 | OPEN_FLAGS_FAIL_ON_ERROR
569 | OPEN_FLAGS_NOINHERIT
570 | OPEN_ACCESS_READONLY
571 | OPEN_SHARE_DENYNONE,
572 0);
573 if (rc == NO_ERROR)
574 {
575 param = 0;
576 data = (USHORT)ulLogicalDrive;
577 paramsize = sizeof(param);
578 datasize = sizeof(data);
579 rc = DosDevIOCtl(fd,
580 IOCTL_DISK, DSK_SETLOGICALMAP,
581 &param, paramsize, &paramsize,
582 &data, datasize, &datasize);
583 DosClose(fd);
584 }
585
586 return(rc);
587}
588
589/*
590 *@@ doshQueryDiskFree:
591 * returns the number of bytes remaining on the disk
592 * specified by the given logical drive.
593 *
594 * Note: This returns a "double" value, because a ULONG
595 * can only hold values of some 4 billion, which would
596 * lead to funny results for drives > 4 GB.
597 *
598 *@@changed V0.9.0 [umoeller]: fixed another > 4 GB bug (thanks to Rdiger Ihle)
599 *@@changed V0.9.7 (2000-12-01) [umoeller]: changed prototype
600 */
601
602APIRET doshQueryDiskFree(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
603 double *pdFree)
604{
605 APIRET arc = NO_ERROR;
606 FSALLOCATE fsa;
607 double dbl = -1;
608
609 arc = DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa));
610 if (arc == NO_ERROR)
611 *pdFree = ((double)fsa.cSectorUnit * fsa.cbSector * fsa.cUnitAvail);
612 // ^ fixed V0.9.0
613
614 return (arc);
615}
616
617/*
618 *@@ doshQueryDiskFSType:
619 * copies the file-system type of the given disk object
620 * (HPFS, FAT, CDFS etc.) to pszBuf.
621 * Returns the DOS error code.
622 *
623 *@@changed V0.9.1 (99-12-12) [umoeller]: added cbBuf to prototype
624 */
625
626APIRET doshQueryDiskFSType(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
627 PSZ pszBuf, // out: buffer for FS type
628 ULONG cbBuf) // in: size of that buffer
629{
630 APIRET arc = NO_ERROR;
631 CHAR szName[5];
632
633 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
634 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
635 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
636
637 // compose "D:"-type string from logical drive letter
638 szName[0] = G_acDriveLetters[ulLogicalDrive];
639 szName[1] = ':';
640 szName[2] = '\0';
641
642 arc = DosQueryFSAttach(szName, // logical drive of attached FS ("D:"-style)
643 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
644 FSAIL_QUERYNAME, // return name for a drive or device
645 pfsqBuffer, // buffer for returned data
646 &cbBuffer); // sizeof(*pfsqBuffer)
647
648 if (arc == NO_ERROR)
649 {
650 if (pszBuf)
651 {
652 // The data for the last three fields in the FSQBUFFER2
653 // structure are stored at the offset of fsqBuffer.szName.
654 // Each data field following fsqBuffer.szName begins
655 // immediately after the previous item.
656 strcpy(pszBuf,
657 (CHAR*)(&pfsqBuffer->szName) + pfsqBuffer->cbName + 1);
658 }
659 }
660
661 return (arc);
662}
663
664/*
665 *@@ doshIsFixedDisk:
666 * checks whether a disk is fixed or removeable.
667 * ulLogicalDrive must be 1 for drive A:, 2 for B:, ...
668 * The result is stored in *pfFixed.
669 * Returns DOS error code.
670 *
671 * Warning: This uses DosDevIOCtl, which has proved
672 * to cause problems with some device drivers for
673 * removeable disks.
674 */
675
676APIRET doshIsFixedDisk(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
677 PBOOL pfFixed) // out: TRUE for fixed disks
678{
679 APIRET arc = ERROR_INVALID_DRIVE;
680
681 if (ulLogicalDrive)
682 {
683 // parameter packet
684 #pragma pack(1)
685 struct {
686 UCHAR command, drive;
687 } parms;
688 #pragma pack()
689
690 // data packet
691 UCHAR ucNonRemoveable;
692
693 ULONG ulParmSize = sizeof(parms);
694 ULONG ulDataSize = sizeof(ucNonRemoveable);
695
696 parms.drive = (UCHAR)(ulLogicalDrive-1);
697 arc = DosDevIOCtl((HFILE)-1,
698 IOCTL_DISK,
699 DSK_BLOCKREMOVABLE,
700 &parms,
701 ulParmSize,
702 &ulParmSize,
703 &ucNonRemoveable,
704 ulDataSize,
705 &ulDataSize);
706
707 if (arc == NO_ERROR)
708 *pfFixed = (BOOL)ucNonRemoveable;
709 }
710
711 return (arc);
712}
713
714/*
715 *@@ doshQueryDiskParams:
716 * this retrieves more information about a given drive,
717 * which is stored in the specified DRIVEPARAMS structure
718 * (dosh.h).
719 *
720 * Warning: This uses DosDevIOCtl, which has proved
721 * to cause problems with some device drivers for
722 * removeable disks.
723 *
724 * This returns the DOS error code of DosDevIOCtl.
725 *
726 *@@added V0.9.0 [umoeller]
727 */
728
729APIRET doshQueryDiskParams(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
730 PDRIVEPARAMS pdp) // out: drive parameters
731{
732 APIRET arc = ERROR_INVALID_DRIVE;
733
734 if (ulLogicalDrive)
735 {
736 #pragma pack(1)
737 // parameter packet
738 struct {
739 UCHAR command, drive;
740 } parms;
741 #pragma pack()
742
743 ULONG ulParmSize = sizeof(parms);
744 ULONG ulDataSize = sizeof(DRIVEPARAMS);
745
746 parms.command = 1; // read currently inserted media
747 parms.drive=(UCHAR)(ulLogicalDrive-1);
748
749 arc = DosDevIOCtl((HFILE)-1,
750 IOCTL_DISK,
751 DSK_GETDEVICEPARAMS,
752 // parameter packet:
753 &parms, ulParmSize, &ulParmSize,
754 // data packet: DRIVEPARAMS structure
755 pdp, ulDataSize, &ulDataSize);
756 }
757
758 return (arc);
759}
760
761/*
762 *@@ doshQueryDiskLabel:
763 * this returns the label of a disk into
764 * *pszVolumeLabel, which must be 12 bytes
765 * in size.
766 *
767 * This function was added because the Toolkit
768 * information for DosQueryFSInfo is only partly
769 * correct. On OS/2 2.x, that function does not
770 * take an FSINFO structure as input, but a VOLUMELABEL.
771 * On Warp, this does take an FSINFO.
772 *
773 * DosSetFSInfo is even worse. See doshSetDiskLabel.
774 *
775 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
776 * for details.
777 *
778 *@@added V0.9.0 [umoeller]
779 */
780
781APIRET doshQueryDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
782 PSZ pszVolumeLabel) // out: volume label (must be 12 chars in size)
783{
784 APIRET arc;
785
786 #ifdef __OS2V2X__
787 VOLUMELABEL FSInfoBuf;
788 #else
789 FSINFO FSInfoBuf;
790 #endif
791
792 arc = DosQueryFSInfo(ulLogicalDrive,
793 FSIL_VOLSER,
794 &FSInfoBuf,
795 sizeof(FSInfoBuf)); // depends
796
797 #ifdef __OS2V2X__
798 strcpy(pszVolumeLabel, FSInfoBuf.szVolLabel);
799 #else
800 strcpy(pszVolumeLabel, FSInfoBuf.vol.szVolLabel);
801 #endif
802
803 return (arc);
804}
805
806/*
807 *@@ doshSetDiskLabel:
808 * this sets the label of a disk.
809 *
810 * This function was added because the Toolkit
811 * information for DosSetFSInfo is flat out wrong.
812 * That function does not take an FSINFO structure
813 * as input, but a VOLUMELABEL. As a result, using
814 * that function with the Toolkit's calling specs
815 * results in ERROR_LABEL_TOO_LONG always.
816 *
817 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
818 * for details.
819 *
820 *@@added V0.9.0 [umoeller]
821 */
822
823APIRET doshSetDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
824 PSZ pszNewLabel)
825{
826 VOLUMELABEL FSInfoBuf;
827
828 // check length; 11 chars plus null byte allowed
829 FSInfoBuf.cch = (BYTE)strlen(pszNewLabel);
830 if (FSInfoBuf.cch < sizeof(FSInfoBuf.szVolLabel))
831 {
832 strcpy(FSInfoBuf.szVolLabel, pszNewLabel);
833
834 return (DosSetFSInfo(ulLogicalDrive,
835 FSIL_VOLSER,
836 &FSInfoBuf,
837 sizeof(FSInfoBuf)));
838 }
839 else
840 return (ERROR_LABEL_TOO_LONG);
841}
842
843/*
844 *@@category: Helpers\Control program helpers\File management
845 */
846
847/* ******************************************************************
848 *
849 * File helpers
850 *
851 ********************************************************************/
852
853/*
854 *@@ doshGetExtension:
855 * finds the file name extension of pszFilename,
856 * which can be a file name only or a fully
857 * qualified filename.
858 *
859 * This returns a pointer into pszFilename to
860 * the character after the last dot.
861 *
862 * Returns NULL if not found (e.g. if the filename
863 * has no dot in it).
864 *
865 *@@added V0.9.6 (2000-10-16) [umoeller]
866 *@@changed V0.9.7 (2000-12-10) [umoeller]: fixed "F:filename.ext" case
867 */
868
869PSZ doshGetExtension(const char *pcszFilename)
870{
871 PSZ pReturn = NULL;
872
873 if (pcszFilename)
874 {
875 // find filename
876 const char *p2 = strrchr(pcszFilename + 2, '\\'),
877 // works on "C:\blah" or "\\unc\blah"
878 *pStartOfName = NULL,
879 *pExtension = NULL;
880
881 if (p2)
882 pStartOfName = p2 + 1;
883 else
884 {
885 // no backslash found:
886 // maybe only a drive letter was specified:
887 if (*(pcszFilename + 1) == ':')
888 // yes:
889 pStartOfName = pcszFilename + 2;
890 else
891 // then this is not qualified at all...
892 // use start of filename
893 pStartOfName = (PSZ)pcszFilename;
894 }
895
896 // find last dot in filename
897 pExtension = strrchr(pStartOfName, '.');
898 if (pExtension)
899 pReturn = (PSZ)pExtension + 1;
900 }
901
902 return (pReturn);
903}
904
905/*
906 *@@ doshIsFileOnFAT:
907 * returns TRUE if pszFileName resides on
908 * a FAT drive. Note that pszFileName must
909 * be fully qualified (i.e. the drive letter
910 * must be the first character), or this will
911 * return garbage.
912 */
913
914BOOL doshIsFileOnFAT(const char* pcszFileName)
915{
916 BOOL brc = FALSE;
917 CHAR szName[5];
918
919 APIRET rc = NO_ERROR; // return code
920 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
921 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
922 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
923
924 szName[0] = pcszFileName[0]; // copy drive letter
925 szName[1] = ':';
926 szName[2] = '\0';
927
928 rc = DosQueryFSAttach(szName, // logical drive of attached FS
929 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
930 FSAIL_QUERYNAME, // return data for a Drive or Device
931 pfsqBuffer, // returned data
932 &cbBuffer); // returned data length
933
934 if (rc == NO_ERROR)
935 {
936 // The data for the last three fields in the FSQBUFFER2
937 // structure are stored at the offset of fsqBuffer.szName.
938 // Each data field following fsqBuffer.szName begins
939 // immediately after the previous item.
940 if (strncmp((PSZ)&(pfsqBuffer->szName) + pfsqBuffer->cbName + 1,
941 "FAT",
942 3)
943 == 0)
944 brc = TRUE;
945 }
946
947 return (brc);
948}
949
950/*
951 *@@ doshQueryFileSize:
952 * returns the size of an already opened file
953 * or 0 upon errors.
954 * Use doshQueryPathSize to query the size of
955 * any file.
956 */
957
958ULONG doshQueryFileSize(HFILE hFile)
959{
960 FILESTATUS3 fs3;
961 if (DosQueryFileInfo(hFile, FIL_STANDARD, &fs3, sizeof(fs3)))
962 return (0);
963 else
964 return (fs3.cbFile);
965}
966
967/*
968 *@@ doshQueryPathSize:
969 * returns the size of any file,
970 * or 0 if the file could not be
971 * found.
972 * Use doshQueryFileSize instead to query the
973 * size if you have a HFILE.
974 */
975
976ULONG doshQueryPathSize(PSZ pszFile)
977{
978 FILESTATUS3 fs3;
979 if (DosQueryPathInfo(pszFile, FIL_STANDARD, &fs3, sizeof(fs3)))
980 return (0);
981 else
982 return (fs3.cbFile);
983}
984
985/*
986 *@@ doshQueryPathAttr:
987 * returns the file attributes of pszFile,
988 * which can be fully qualified. The
989 * attributes will be stored in *pulAttr.
990 * pszFile can also specify a directory,
991 * although not all attributes make sense
992 * for directories.
993 *
994 * fAttr can be:
995 * -- FILE_ARCHIVED
996 * -- FILE_READONLY
997 * -- FILE_SYSTEM
998 * -- FILE_HIDDEN
999 *
1000 * This returns the APIRET of DosQueryPathAttr.
1001 * *pulAttr is only valid if NO_ERROR is
1002 * returned.
1003 *
1004 *@@added V0.9.0 [umoeller]
1005 */
1006
1007APIRET doshQueryPathAttr(const char* pcszFile, // in: file or directory name
1008 PULONG pulAttr) // out: attributes
1009{
1010 FILESTATUS3 fs3;
1011 APIRET arc = DosQueryPathInfo((PSZ)pcszFile,
1012 FIL_STANDARD,
1013 &fs3,
1014 sizeof(fs3));
1015 if (arc == NO_ERROR)
1016 {
1017 if (pulAttr)
1018 *pulAttr = fs3.attrFile;
1019 }
1020
1021 return (arc);
1022}
1023
1024/*
1025 *@@ doshSetPathAttr:
1026 * sets the file attributes of pszFile,
1027 * which can be fully qualified.
1028 * pszFile can also specify a directory,
1029 * although not all attributes make sense
1030 * for directories.
1031 *
1032 * fAttr can be:
1033 * -- FILE_ARCHIVED
1034 * -- FILE_READONLY
1035 * -- FILE_SYSTEM
1036 * -- FILE_HIDDEN
1037 *
1038 * Note that this simply sets all the given
1039 * attributes; the existing attributes
1040 * are lost.
1041 *
1042 * This returns the APIRET of DosQueryPathInfo.
1043 */
1044
1045APIRET doshSetPathAttr(const char* pcszFile, // in: file or directory name
1046 ULONG ulAttr) // in: new attributes
1047{
1048 FILESTATUS3 fs3;
1049 APIRET rc = DosQueryPathInfo((PSZ)pcszFile,
1050 FIL_STANDARD,
1051 &fs3,
1052 sizeof(fs3));
1053
1054 if (rc == NO_ERROR)
1055 {
1056 fs3.attrFile = ulAttr;
1057 rc = DosSetPathInfo((PSZ)pcszFile,
1058 FIL_STANDARD,
1059 &fs3,
1060 sizeof(fs3),
1061 DSPI_WRTTHRU);
1062 }
1063 return (rc);
1064}
1065
1066/*
1067 *@@ doshLoadTextFile:
1068 * reads a text file from disk, allocates memory
1069 * via malloc() and sets a pointer to this
1070 * buffer (or NULL upon errors).
1071 *
1072 * This returns the APIRET of DosOpen and DosRead.
1073 * If any error occured, no buffer was allocated.
1074 * Otherwise, you should free() the buffer when
1075 * no longer needed.
1076 *
1077 *@@changed V0.9.7 (2001-01-15) [umoeller]: renamed from doshReadTextFile
1078 */
1079
1080APIRET doshLoadTextFile(const char *pcszFile, // in: file name to read
1081 PSZ* ppszContent) // out: newly allocated buffer with file's content
1082{
1083 ULONG ulSize,
1084 ulBytesRead = 0,
1085 ulAction, ulLocal;
1086 HFILE hFile;
1087 PSZ pszContent = NULL;
1088
1089 APIRET arc = DosOpen((PSZ)pcszFile,
1090 &hFile,
1091 &ulAction, // action taken
1092 5000L, // primary allocation size
1093 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1094 OPEN_ACTION_OPEN_IF_EXISTS, // open flags
1095 OPEN_FLAGS_NOINHERIT
1096 | OPEN_SHARE_DENYNONE
1097 | OPEN_ACCESS_READONLY, // read-only mode
1098 NULL); // no EAs
1099
1100 if (arc == NO_ERROR)
1101 {
1102 ulSize = doshQueryFileSize(hFile);
1103 pszContent = (PSZ)malloc(ulSize+1);
1104 arc = DosSetFilePtr(hFile,
1105 0L,
1106 FILE_BEGIN,
1107 &ulLocal);
1108 arc = DosRead(hFile,
1109 pszContent,
1110 ulSize,
1111 &ulBytesRead);
1112 DosClose(hFile);
1113 *(pszContent+ulBytesRead) = 0;
1114
1115 // set output buffer pointer
1116 *ppszContent = pszContent;
1117 }
1118 else
1119 *ppszContent = 0;
1120
1121 return (arc);
1122}
1123
1124/*
1125 *@@ doshCreateBackupFileName:
1126 * creates a valid backup filename of pszExisting
1127 * with a numerical file name extension which does
1128 * not exist in the directory where pszExisting
1129 * resides.
1130 * Returns a PSZ to a new buffer which was allocated
1131 * using malloc().
1132 *
1133 * <B>Example:</B> returns "C:\CONFIG.002" for input
1134 * "C:\CONFIG.SYS" if "C:\CONFIG.001" already exists.
1135 *
1136 *@@changed V0.9.1 (99-12-13) [umoeller]: this crashed if pszExisting had no file extension
1137 */
1138
1139PSZ doshCreateBackupFileName(const char* pszExisting)
1140{
1141 CHAR szFilename[CCHMAXPATH];
1142 PSZ pszLastDot;
1143 ULONG ulCount = 1;
1144 CHAR szCount[5];
1145
1146 strcpy(szFilename, pszExisting);
1147 pszLastDot = strrchr(szFilename, '.');
1148 if (!pszLastDot)
1149 // no dot in filename:
1150 pszLastDot = szFilename + strlen(szFilename);
1151 do
1152 {
1153 sprintf(szCount, ".%03lu", ulCount);
1154 strcpy(pszLastDot, szCount);
1155 ulCount++;
1156 } while (doshQueryPathSize(szFilename) != 0);
1157
1158 return (strdup(szFilename));
1159}
1160
1161/*
1162 *@@ doshWriteTextFile:
1163 * writes a text file to disk; pszFile must contain the
1164 * whole path and filename.
1165 *
1166 * An existing file will be backed up if (pszBackup != NULL),
1167 * using doshCreateBackupFileName. In that case, pszBackup
1168 * receives the name of the backup created, so that buffer
1169 * should be CCHMAXPATH in size.
1170 *
1171 * If (pszbackup == NULL), an existing file will be overwritten.
1172 *
1173 * On success (NO_ERROR returned), *pulWritten receives
1174 * the no. of bytes written.
1175 *
1176 *@@changed V0.9.3 (2000-05-01) [umoeller]: optimized DosOpen; added error checking; changed prototype
1177 *@@changed V0.9.3 (2000-05-12) [umoeller]: added pszBackup
1178 */
1179
1180APIRET doshWriteTextFile(const char* pszFile, // in: file name
1181 const char* pszContent, // in: text to write
1182 PULONG pulWritten, // out: bytes written (ptr can be NULL)
1183 PSZ pszBackup) // in/out: create-backup?
1184{
1185 APIRET arc = NO_ERROR;
1186 ULONG ulWritten = 0;
1187
1188 if ((!pszFile) || (!pszContent))
1189 arc = ERROR_INVALID_PARAMETER;
1190 else
1191 {
1192 ULONG ulAction = 0,
1193 ulLocal = 0;
1194 HFILE hFile = 0;
1195
1196 ULONG ulSize = strlen(pszContent); // exclude 0 byte
1197
1198 if (pszBackup)
1199 {
1200 PSZ pszBackup2 = doshCreateBackupFileName(pszFile);
1201 DosCopy((PSZ)pszFile,
1202 pszBackup2,
1203 DCPY_EXISTING); // delete existing
1204 strcpy(pszBackup, pszBackup2);
1205 free(pszBackup2);
1206 }
1207
1208 arc = DosOpen((PSZ)pszFile,
1209 &hFile,
1210 &ulAction, // action taken
1211 ulSize, // primary allocation size
1212 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1213 OPEN_ACTION_CREATE_IF_NEW
1214 | OPEN_ACTION_REPLACE_IF_EXISTS, // open flags
1215 OPEN_FLAGS_NOINHERIT
1216 | OPEN_FLAGS_SEQUENTIAL // sequential, not random access
1217 | OPEN_SHARE_DENYWRITE // deny write mode
1218 | OPEN_ACCESS_WRITEONLY, // write mode
1219 NULL); // no EAs
1220
1221 if (arc == NO_ERROR)
1222 {
1223 arc = DosSetFilePtr(hFile,
1224 0L,
1225 FILE_BEGIN,
1226 &ulLocal);
1227 if (arc == NO_ERROR)
1228 {
1229 arc = DosWrite(hFile,
1230 (PVOID)pszContent,
1231 ulSize,
1232 &ulWritten);
1233 if (arc == NO_ERROR)
1234 arc = DosSetFileSize(hFile, ulSize);
1235 }
1236
1237 DosClose(hFile);
1238 }
1239 } // end if ((pszFile) && (pszContent))
1240
1241 if (pulWritten)
1242 *pulWritten = ulWritten;
1243
1244 return (arc);
1245}
1246
1247/*
1248 *@@ doshOpenLogFile:
1249 * this opens a log file in the root directory of
1250 * the boot drive; it is titled pszFilename, and
1251 * the file handle is returned.
1252 */
1253
1254HFILE doshOpenLogFile(const char* pcszFilename)
1255{
1256 APIRET rc;
1257 CHAR szFileName[CCHMAXPATH];
1258 HFILE hfLog;
1259 ULONG ulAction;
1260 ULONG ibActual;
1261
1262 sprintf(szFileName, "%c:\\%s", doshQueryBootDrive(), pcszFilename);
1263 rc = DosOpen(szFileName,
1264 &hfLog,
1265 &ulAction,
1266 0, // file size
1267 FILE_NORMAL,
1268 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
1269 OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
1270 (PEAOP2)NULL);
1271 if (rc == NO_ERROR)
1272 {
1273 DosSetFilePtr(hfLog, 0, FILE_END, &ibActual);
1274 return (hfLog);
1275 }
1276 else
1277 return (0);
1278}
1279
1280/*
1281 * doshWriteToLogFile
1282 * writes a string to a log file, adding a
1283 * leading timestamp.
1284 */
1285
1286APIRET doshWriteToLogFile(HFILE hfLog, const char* pcsz)
1287{
1288 if (hfLog)
1289 {
1290 DATETIME dt;
1291 CHAR szTemp[2000];
1292 ULONG cbWritten;
1293 DosGetDateTime(&dt);
1294 sprintf(szTemp, "Time: %02d:%02d:%02d %s",
1295 dt.hours, dt.minutes, dt.seconds,
1296 pcsz);
1297 return (DosWrite(hfLog, (PVOID)szTemp, strlen(szTemp), &cbWritten));
1298 }
1299 else return (ERROR_INVALID_HANDLE);
1300}
1301
1302/*
1303 *@@category: Helpers\Control program helpers\Directory management
1304 * directory helpers (querying, creating, deleting etc.).
1305 */
1306
1307/* ******************************************************************
1308 *
1309 * Directory helpers
1310 *
1311 ********************************************************************/
1312
1313/*
1314 *@@ doshQueryDirExist:
1315 * returns TRUE if the given directory
1316 * exists.
1317 */
1318
1319BOOL doshQueryDirExist(const char *pcszDir)
1320{
1321 FILESTATUS3 fs3;
1322 APIRET arc = DosQueryPathInfo((PSZ)pcszDir,
1323 FIL_STANDARD,
1324 &fs3,
1325 sizeof(fs3));
1326 if (arc == NO_ERROR)
1327 // file found:
1328 return ((fs3.attrFile & FILE_DIRECTORY) != 0);
1329 else
1330 return FALSE;
1331}
1332
1333/*
1334 *@@ doshCreatePath:
1335 * this creates the specified directory.
1336 * As opposed to DosCreateDir, this
1337 * function can create several directories
1338 * at the same time, if the parent
1339 * directories do not exist yet.
1340 */
1341
1342APIRET doshCreatePath(PSZ pszPath,
1343 BOOL fHidden) // in: if TRUE, the new directories will get FILE_HIDDEN
1344{
1345 APIRET arc0 = NO_ERROR;
1346 CHAR path[CCHMAXPATH];
1347 CHAR *cp, c;
1348 ULONG cbPath;
1349
1350 strcpy(path, pszPath);
1351 cbPath = strlen(path);
1352
1353 if (path[cbPath] != '\\')
1354 {
1355 path[cbPath] = '\\';
1356 path[cbPath+1] = 0;
1357 }
1358
1359 cp = path;
1360 // advance past the drive letter only if we have one
1361 if (*(cp+1) == ':')
1362 cp += 3;
1363
1364 // go!
1365 while (*cp != 0)
1366 {
1367 if (*cp == '\\')
1368 {
1369 c = *cp;
1370 *cp = 0;
1371 if (!doshQueryDirExist(path))
1372 {
1373 APIRET arc = DosCreateDir(path,
1374 0); // no EAs
1375 if (arc != NO_ERROR)
1376 {
1377 arc0 = arc;
1378 break;
1379 }
1380 else
1381 if (fHidden)
1382 {
1383 // hide the directory we just created
1384 doshSetPathAttr(path, FILE_HIDDEN);
1385 }
1386 }
1387 *cp = c;
1388 }
1389 cp++;
1390 }
1391 return (arc0);
1392}
1393
1394/*
1395 *@@ doshQueryCurrentDir:
1396 * writes the current directory into
1397 * the specified buffer, which should be
1398 * CCHMAXPATH in size.
1399 *
1400 * As opposed to DosQueryCurrentDir, this
1401 * includes the drive letter.
1402 *
1403 *@@added V0.9.4 (2000-07-22) [umoeller]
1404 */
1405
1406APIRET doshQueryCurrentDir(PSZ pszBuf)
1407{
1408 APIRET arc = NO_ERROR;
1409 ULONG ulCurDisk = 0;
1410 ULONG ulMap = 0;
1411 arc = DosQueryCurrentDisk(&ulCurDisk, &ulMap);
1412 if (arc == NO_ERROR)
1413 {
1414 ULONG cbBuf = CCHMAXPATH - 3;
1415 *pszBuf = G_acDriveLetters[ulCurDisk];
1416 *(pszBuf + 1) = ':';
1417 *(pszBuf + 2) = '\\';
1418 arc = DosQueryCurrentDir(0, pszBuf + 3, &cbBuf);
1419 }
1420
1421 return (arc);
1422}
1423
1424/*
1425 *@@ doshDeleteDir:
1426 * deletes a directory. As opposed to DosDeleteDir,
1427 * this removes empty subdirectories and/or files
1428 * as well.
1429 *
1430 * flFlags can be any combination of the following:
1431 *
1432 * -- DOSHDELDIR_RECURSE: recurse into subdirectories.
1433 *
1434 * -- DOSHDELDIR_DELETEFILES: delete all regular files
1435 * which are found on the way.
1436 *
1437 * THIS IS NOT IMPLEMENTED YET.
1438 *
1439 * If 0 is specified, this effectively behaves just as
1440 * DosDeleteDir.
1441 *
1442 * If you specify DOSHDELDIR_RECURSE only, only empty
1443 * subdirectories are deleted as well.
1444 *
1445 * If you specify DOSHDELDIR_RECURSE | DOSHDELDIR_DELETEFILES,
1446 * this removes an entire directory tree, including all
1447 * subdirectories and files.
1448 *
1449 *@@added V0.9.4 (2000-07-01) [umoeller]
1450 */
1451
1452APIRET doshDeleteDir(const char *pcszDir,
1453 ULONG flFlags,
1454 PULONG pulDirs, // out: directories found
1455 PULONG pulFiles) // out: files found
1456{
1457 APIRET arc = NO_ERROR,
1458 arcReturn = NO_ERROR;
1459
1460 HDIR hdirFindHandle = HDIR_CREATE;
1461 FILEFINDBUF3 ffb3 = {0}; // returned from FindFirst/Next
1462 ULONG ulResultBufLen = sizeof(FILEFINDBUF3);
1463 ULONG ulFindCount = 1; // look for 1 file at a time
1464
1465 CHAR szFileMask[2*CCHMAXPATH];
1466 sprintf(szFileMask, "%s\\*", pcszDir);
1467
1468 // find files
1469 arc = DosFindFirst(szFileMask,
1470 &hdirFindHandle, // directory search handle
1471 FILE_ARCHIVED | FILE_DIRECTORY | FILE_SYSTEM
1472 | FILE_HIDDEN | FILE_READONLY,
1473 // search attributes; include all, even dirs
1474 &ffb3, // result buffer
1475 ulResultBufLen, // result buffer length
1476 &ulFindCount, // number of entries to find
1477 FIL_STANDARD); // return level 1 file info
1478
1479 if (arc == NO_ERROR)
1480 {
1481 // keep finding the next file until there are no more files
1482 while (arc == NO_ERROR) // != ERROR_NO_MORE_FILES
1483 {
1484 if (ffb3.attrFile & FILE_DIRECTORY)
1485 {
1486 // we found a directory:
1487
1488 // ignore the pseudo-directories
1489 if ( (strcmp(ffb3.achName, ".") != 0)
1490 && (strcmp(ffb3.achName, "..") != 0)
1491 )
1492 {
1493 // real directory:
1494 if (flFlags & DOSHDELDIR_RECURSE)
1495 {
1496 // recurse!
1497 CHAR szSubDir[2*CCHMAXPATH];
1498 sprintf(szSubDir, "%s\\%s", pcszDir, ffb3.achName);
1499 arcReturn = doshDeleteDir(szSubDir,
1500 flFlags,
1501 pulDirs,
1502 pulFiles);
1503 // this removes ffb3.achName as well
1504 }
1505 else
1506 {
1507 // directory, but no recursion:
1508 // report "access denied"
1509 // (this is what OS/2 reports with DosDeleteDir as well)
1510 arcReturn = ERROR_ACCESS_DENIED; // 5
1511 (*pulDirs)++;
1512 }
1513 }
1514 }
1515 else
1516 {
1517 // it's a file:
1518 arcReturn = ERROR_ACCESS_DENIED;
1519 (*pulFiles)++;
1520 }
1521
1522 if (arc == NO_ERROR)
1523 {
1524 ulFindCount = 1; // reset find count
1525 arc = DosFindNext(hdirFindHandle, // directory handle
1526 &ffb3, // result buffer
1527 ulResultBufLen, // result buffer length
1528 &ulFindCount); // number of entries to find
1529 }
1530 } // endwhile
1531
1532 DosFindClose(hdirFindHandle); // close our find handle
1533 }
1534
1535 if (arcReturn == NO_ERROR)
1536 // success so far:
1537 // delete our directory now
1538 arc = DosDeleteDir((PSZ)pcszDir);
1539
1540 return (arcReturn);
1541}
1542
1543/*
1544 *@@category: Helpers\Control program helpers\Module handling
1545 * helpers for importing functions from a module (DLL).
1546 */
1547
1548/* ******************************************************************
1549 *
1550 * Module handling helpers
1551 *
1552 ********************************************************************/
1553
1554/*
1555 *@@ doshResolveImports:
1556 * this function loads the module called pszModuleName
1557 * and resolves imports dynamically using DosQueryProcAddress.
1558 *
1559 * To specify the functions to be imported, a RESOLVEFUNCTION
1560 * array is used. In each of the array items, specify the
1561 * name of the function and a pointer to a function pointer
1562 * where to store the resolved address.
1563 *
1564 *@@added V0.9.3 (2000-04-29) [umoeller]
1565 */
1566
1567APIRET doshResolveImports(PSZ pszModuleName, // in: DLL to load
1568 HMODULE *phmod, // out: module handle
1569 PRESOLVEFUNCTION paResolves, // in/out: function resolves
1570 ULONG cResolves) // in: array item count (not array size!)
1571{
1572 CHAR szName[CCHMAXPATH];
1573 APIRET arc = DosLoadModule(szName,
1574 sizeof(szName),
1575 pszModuleName,
1576 phmod);
1577 if (arc == NO_ERROR)
1578 {
1579 ULONG ul;
1580 for (ul = 0;
1581 ul < cResolves;
1582 ul++)
1583 {
1584 arc = DosQueryProcAddr(*phmod,
1585 0, // ordinal, ignored
1586 (PSZ)paResolves[ul].pcszFunctionName,
1587 paResolves[ul].ppFuncAddress);
1588
1589 /* _Pmpf(("Resolved %s to 0x%lX, rc: %d",
1590 paResolves[ul].pcszFunctionName,
1591 *paResolves[ul].ppFuncAddress,
1592 arc)); */
1593 if (arc != NO_ERROR)
1594 break;
1595 }
1596 }
1597
1598 return (arc);
1599}
1600
1601/*
1602 *@@category: Helpers\Control program helpers\Performance (CPU load) helpers
1603 * helpers around DosPerfSysCall.
1604 */
1605
1606/* ******************************************************************
1607 *
1608 * Performance Counters (CPU Load)
1609 *
1610 ********************************************************************/
1611
1612/*
1613 *@@ doshPerfOpen:
1614 * initializes the OS/2 DosPerfSysCall API for
1615 * the calling thread.
1616 *
1617 * Note: This API is not supported on all OS/2
1618 * versions. I believe it came up with some Warp 4
1619 * fixpak. The API is resolved dynamically by
1620 * this function (using DosQueryProcAddr). Only
1621 * if NO_ERROR is returned, you may call doshPerfGet
1622 * afterwards.
1623 *
1624 * This properly initializes the internal counters
1625 * which the OS/2 kernel uses for this API. Apparently,
1626 * with newer kernels (FP13/14), IBM has chosen to no
1627 * longer do this automatically, which is the reason
1628 * why many "pulse" utilities display garbage with these
1629 * fixpaks.
1630 *
1631 * After NO_ERROR is returned, DOSHPERFSYS.cProcessors
1632 * contains the no. of processors found on the system.
1633 * All pointers in DOSHPERFSYS then point to arrays
1634 * which have exactly cProcessors array items.
1635 *
1636 * Call doshPerfClose to clean up resources allocated
1637 * by this function.
1638 *
1639 * Example code:
1640 *
1641 + PDOSHPERFSYS pPerf = NULL;
1642 + APIRET arc = doshPerfOpen(&pPerf);
1643 + if (arc == NO_ERROR)
1644 + {
1645 + // this should really be in a timer
1646 + ULONG ulCPU;
1647 + arc = doshPerfGet(&pPerf);
1648 + // go thru all CPUs
1649 + for (ulCPU = 0; ulCPU < pPerf->cProcessors; ulCPU++)
1650 + {
1651 + LONG lLoadThis = pPerf->palLoads[ulCPU];
1652 + ...
1653 + }
1654 +
1655 + ...
1656 +
1657 + // clean up
1658 + doshPerfClose(&pPerf);
1659 + }
1660 +
1661 *
1662 *@@added V0.9.7 (2000-12-02) [umoeller]
1663 */
1664
1665APIRET doshPerfOpen(PDOSHPERFSYS *ppPerfSys) // out: new DOSHPERFSYS structure
1666{
1667 APIRET arc = NO_ERROR;
1668
1669 // allocate DOSHPERFSYS structure
1670 *ppPerfSys = (PDOSHPERFSYS)malloc(sizeof(DOSHPERFSYS));
1671 if (!*ppPerfSys)
1672 arc = ERROR_NOT_ENOUGH_MEMORY;
1673 else
1674 {
1675 // initialize structure
1676 PDOSHPERFSYS pPerfSys = *ppPerfSys;
1677 memset(pPerfSys, 0, sizeof(*pPerfSys));
1678
1679 // resolve DosPerfSysCall API entry
1680 arc = DosLoadModule(NULL, 0, "DOSCALLS", &pPerfSys->hmod);
1681 if (arc == NO_ERROR)
1682 {
1683 arc = DosQueryProcAddr(pPerfSys->hmod,
1684 976,
1685 "DosPerfSysCall",
1686 (PFN*)(&pPerfSys->pDosPerfSysCall));
1687 if (arc == NO_ERROR)
1688 {
1689 // OK, we got the API: initialize!
1690 arc = pPerfSys->pDosPerfSysCall(CMD_KI_ENABLE, 0, 0, 0);
1691 if (arc == NO_ERROR)
1692 {
1693 pPerfSys->fInitialized = TRUE;
1694 // call CMD_KI_DISABLE later
1695
1696 arc = pPerfSys->pDosPerfSysCall(CMD_PERF_INFO,
1697 0,
1698 (ULONG)(&pPerfSys->cProcessors),
1699 0);
1700 if (arc == NO_ERROR)
1701 {
1702 ULONG ul = 0;
1703
1704 // allocate arrays
1705 pPerfSys->paCPUUtils = (PCPUUTIL)calloc(pPerfSys->cProcessors,
1706 sizeof(CPUUTIL));
1707 if (!pPerfSys->paCPUUtils)
1708 arc = ERROR_NOT_ENOUGH_MEMORY;
1709 else
1710 {
1711 pPerfSys->padBusyPrev = (double*)malloc(pPerfSys->cProcessors * sizeof(double));
1712 if (!pPerfSys->padBusyPrev)
1713 arc = ERROR_NOT_ENOUGH_MEMORY;
1714 else
1715 {
1716 pPerfSys->padTimePrev
1717 = (double*)malloc(pPerfSys->cProcessors * sizeof(double));
1718 if (!pPerfSys->padTimePrev)
1719 arc = ERROR_NOT_ENOUGH_MEMORY;
1720 else
1721 {
1722 pPerfSys->palLoads = (PLONG)malloc(pPerfSys->cProcessors * sizeof(LONG));
1723 if (!pPerfSys->palLoads)
1724 arc = ERROR_NOT_ENOUGH_MEMORY;
1725 else
1726 {
1727 for (ul = 0; ul < pPerfSys->cProcessors; ul++)
1728 {
1729 pPerfSys->padBusyPrev[ul] = 0.0;
1730 pPerfSys->padTimePrev[ul] = 0.0;
1731 pPerfSys->palLoads[ul] = 0;
1732 }
1733 }
1734 }
1735 }
1736 }
1737 }
1738 }
1739 } // end if (arc == NO_ERROR)
1740 } // end if (arc == NO_ERROR)
1741
1742 if (arc != NO_ERROR)
1743 {
1744 doshPerfClose(ppPerfSys);
1745 }
1746 } // end else if (!*ppPerfSys)
1747
1748 return (arc);
1749}
1750
1751/*
1752 *@@ doshPerfGet:
1753 * calculates a current snapshot of the system load,
1754 * compared with the load which was calculated on
1755 * the previous call.
1756 *
1757 * If you want to continually measure the system CPU
1758 * load, this is the function you will want to call
1759 * regularly -- e.g. with a timer once per second.
1760 *
1761 * Call this ONLY if doshPerfOpen returned NO_ERROR,
1762 * or you'll get crashes.
1763 *
1764 * If this call returns NO_ERROR, you get a LONG
1765 * CPU load for each CPU in the system in the
1766 * DOSHPERFSYS.palLoads array (in per-mille, 0-1000).
1767 *
1768 * For example, if there are two CPUs, after this call,
1769 *
1770 * -- DOSHPERFSYS.palLoads[0] contains the load of
1771 * the first CPU,
1772 *
1773 * -- DOSHPERFSYS.palLoads[1] contains the load of
1774 * the second CPU.
1775 *
1776 * See doshPerfOpen for example code.
1777 *
1778 *@@added V0.9.7 (2000-12-02) [umoeller]
1779 */
1780
1781APIRET doshPerfGet(PDOSHPERFSYS pPerfSys)
1782{
1783 APIRET arc = NO_ERROR;
1784 if (!pPerfSys->pDosPerfSysCall)
1785 arc = ERROR_INVALID_PARAMETER;
1786 else
1787 {
1788 arc = pPerfSys->pDosPerfSysCall(CMD_KI_RDCNT,
1789 (ULONG)pPerfSys->paCPUUtils,
1790 0, 0);
1791 if (arc == NO_ERROR)
1792 {
1793 // go thru all processors
1794 ULONG ul = 0;
1795 for (; ul < pPerfSys->cProcessors; ul++)
1796 {
1797 PCPUUTIL pCPUUtilThis = &pPerfSys->paCPUUtils[ul];
1798
1799 double dTime = LL2F(pCPUUtilThis->ulTimeHigh,
1800 pCPUUtilThis->ulTimeLow);
1801 double dBusy = LL2F(pCPUUtilThis->ulBusyHigh,
1802 pCPUUtilThis->ulBusyLow);
1803
1804 double *pdBusyPrevThis = &pPerfSys->padBusyPrev[ul];
1805 double *pdTimePrevThis = &pPerfSys->padTimePrev[ul];
1806
1807 // avoid division by zero
1808 double dTimeDelta = (dTime - *pdTimePrevThis);
1809 if (dTimeDelta)
1810 pPerfSys->palLoads[ul]
1811 = (LONG)( (double)( (dBusy - *pdBusyPrevThis)
1812 / dTimeDelta
1813 * 1000.0
1814 )
1815 );
1816 else
1817 pPerfSys->palLoads[ul] = 0;
1818
1819 *pdTimePrevThis = dTime;
1820 *pdBusyPrevThis = dBusy;
1821 }
1822 }
1823 }
1824
1825 return (arc);
1826}
1827
1828/*
1829 *@@ doshPerfClose:
1830 * frees all resources allocated by doshPerfOpen.
1831 *
1832 *@@added V0.9.7 (2000-12-02) [umoeller]
1833 *@@changed V0.9.9 (2001-02-06) [umoeller]: removed disable; this broke the WarpCenter
1834 */
1835
1836APIRET doshPerfClose(PDOSHPERFSYS *ppPerfSys)
1837{
1838 APIRET arc = NO_ERROR;
1839 PDOSHPERFSYS pPerfSys = *ppPerfSys;
1840 if (!pPerfSys)
1841 arc = ERROR_INVALID_PARAMETER;
1842 else
1843 {
1844 /* if (pPerfSys->fInitialized)
1845 pPerfSys->pDosPerfSysCall(CMD_KI_DISABLE,
1846 0, 0, 0); */
1847
1848 if (pPerfSys->paCPUUtils)
1849 free(pPerfSys->paCPUUtils);
1850 if (pPerfSys->padBusyPrev)
1851 free(pPerfSys->padBusyPrev);
1852 if (pPerfSys->padTimePrev)
1853 free(pPerfSys->padTimePrev);
1854
1855 if (pPerfSys->hmod)
1856 DosFreeModule(pPerfSys->hmod);
1857 free(pPerfSys);
1858 *ppPerfSys = NULL;
1859 }
1860
1861 return (arc);
1862}
1863
1864/*
1865 *@@category: Helpers\Control program helpers\Process management
1866 * helpers for starting subprocesses.
1867 */
1868
1869/* ******************************************************************
1870 *
1871 * Process helpers
1872 *
1873 ********************************************************************/
1874
1875/*
1876 *@@ doshFindExecutable:
1877 * this searches the PATH for the specified pcszCommand
1878 * by calling DosSearchPath.
1879 *
1880 * papcszExtensions determines if additional searches are to be
1881 * performed if DosSearchPath returns ERROR_FILE_NOT_FOUND.
1882 * This must point to an array of strings specifying the extra
1883 * extensions to search for.
1884 *
1885 * If both papcszExtensions and cExtensions are null, no
1886 * extra searches are performed.
1887 *
1888 * If this returns NO_ERROR, pszExecutable receives
1889 * the full path of the executable found by DosSearchPath.
1890 * Otherwise ERROR_FILE_NOT_FOUND is returned.
1891 *
1892 * Example:
1893 *
1894 + const char *aExtensions[] = { "EXE",
1895 + "COM",
1896 + "CMD"
1897 + };
1898 + CHAR szExecutable[CCHMAXPATH];
1899 + APIRET arc = doshFindExecutable("lvm",
1900 + szExecutable,
1901 + sizeof(szExecutable),
1902 + aExtensions,
1903 + 3);
1904 *
1905 *@@added V0.9.9 (2001-03-07) [umoeller]
1906 */
1907
1908APIRET doshFindExecutable(const char *pcszCommand, // in: command (e.g. "lvm")
1909 PSZ pszExecutable, // out: full path (e.g. "F:\os2\lvm.exe")
1910 ULONG cbExecutable, // in: sizeof (*pszExecutable)
1911 const char **papcszExtensions, // in: array of extensions (without dots)
1912 ULONG cExtensions) // in: array item count
1913{
1914 APIRET arc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY,
1915 "PATH",
1916 (PSZ)pcszCommand,
1917 pszExecutable,
1918 cbExecutable);
1919 if ( (arc == ERROR_FILE_NOT_FOUND) // not found?
1920 && (cExtensions) // any extra searches wanted?
1921 )
1922 {
1923 // try additional things then
1924 PSZ psz2 = malloc(strlen(pcszCommand) + 20);
1925 if (psz2)
1926 {
1927 ULONG ul;
1928 for (ul = 0;
1929 ul < cExtensions;
1930 ul++)
1931 {
1932 const char *pcszExtThis = papcszExtensions[ul];
1933 sprintf(psz2, "%s.%s", pcszCommand, pcszExtThis);
1934 arc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY,
1935 "PATH",
1936 psz2,
1937 pszExecutable,
1938 cbExecutable);
1939 if (arc != ERROR_FILE_NOT_FOUND)
1940 break;
1941 }
1942
1943 free(psz2);
1944 }
1945 else
1946 arc = ERROR_NOT_ENOUGH_MEMORY;
1947 }
1948
1949 return (arc);
1950}
1951
1952/*
1953 *@@ doshExecVIO:
1954 * executes cmd.exe with the /c parameter
1955 * and pcszExecWithArgs. This is equivalent
1956 * to the C library system() function,
1957 * except that an OS/2 error code is returned
1958 * and that this works with the VAC subsystem
1959 * library.
1960 *
1961 * This uses DosExecPgm and handles the sick
1962 * argument passing.
1963 *
1964 * If NO_ERROR is returned, *plExitCode receives
1965 * the exit code of the process. If the process
1966 * was terminated abnormally, *plExitCode receives:
1967 *
1968 * -- -1: hard error halt
1969 * -- -2: 16-bit trap
1970 * -- -3: DosKillProcess
1971 * -- -4: 32-bit exception
1972 *
1973 *@@added V0.9.4 (2000-07-27) [umoeller]
1974 */
1975
1976APIRET doshExecVIO(const char *pcszExecWithArgs,
1977 PLONG plExitCode) // out: exit code (ptr can be NULL)
1978{
1979 APIRET arc = NO_ERROR;
1980
1981 if (strlen(pcszExecWithArgs) > 255)
1982 arc = ERROR_INSUFFICIENT_BUFFER;
1983 {
1984 CHAR szObj[CCHMAXPATH];
1985 RESULTCODES res = {0};
1986 CHAR szBuffer[300];
1987
1988 // DosExecPgm expects two args in szBuffer:
1989 // -- cmd.exe\0
1990 // -- then the actual argument, terminated by two 0 bytes.
1991 memset(szBuffer, 0, sizeof(szBuffer));
1992 strcpy(szBuffer, "cmd.exe\0");
1993 sprintf(szBuffer + 8, "/c %s",
1994 pcszExecWithArgs);
1995
1996 arc = DosExecPgm(szObj, sizeof(szObj),
1997 EXEC_SYNC,
1998 szBuffer,
1999 0,
2000 &res,
2001 "cmd.exe");
2002 if ((arc == NO_ERROR) && (plExitCode))
2003 {
2004 if (res.codeTerminate == 0)
2005 // normal exit:
2006 *plExitCode = res.codeResult;
2007 else
2008 *plExitCode = -((LONG)res.codeTerminate);
2009 }
2010 }
2011
2012 return (arc);
2013}
2014
2015/*
2016 *@@ doshQuickStartSession:
2017 * this is a shortcut to DosStartSession w/out having to
2018 * deal with all the messy parameters.
2019 *
2020 * This one starts pszPath as a child session and passes
2021 * pszParams to it.
2022 *
2023 * In usPgmCtl, OR any or none of the following (V0.9.0):
2024 * -- SSF_CONTROL_NOAUTOCLOSE (0x0008): do not close automatically.
2025 * This bit is used only for VIO Windowable apps and ignored
2026 * for all other applications.
2027 * -- SSF_CONTROL_MINIMIZE (0x0004)
2028 * -- SSF_CONTROL_MAXIMIZE (0x0002)
2029 * -- SSF_CONTROL_INVISIBLE (0x0001)
2030 * -- SSF_CONTROL_VISIBLE (0x0000)
2031 *
2032 * Specifying 0 will therefore auto-close the session and make it
2033 * visible.
2034 *
2035 * If (fWait), this function will create a termination queue
2036 * and not return until the child session has ended. Otherwise
2037 * the function will return immediately, and the SID/PID of
2038 * the child session can be found in *pulSID and *ppid.
2039 *
2040 * Returns the error code of DosStartSession.
2041 *
2042 * Note: According to CPREF, calling DosStartSession calls
2043 * DosExecPgm in turn for all full-screen, VIO, and PM sessions.
2044 *
2045 *@@changed V0.9.0 [umoeller]: prototype changed to include usPgmCtl
2046 *@@changed V0.9.1 (99-12-30) [umoeller]: queue was sometimes not closed. Fixed.
2047 *@@changed V0.9.3 (2000-05-03) [umoeller]: added fForeground
2048 */
2049
2050APIRET doshQuickStartSession(const char *pcszPath, // in: program to start
2051 const char *pcszParams, // in: parameters for program
2052 BOOL fForeground, // in: if TRUE, session will be in foreground
2053 USHORT usPgmCtl, // in: STARTDATA.PgmControl
2054 BOOL fWait, // in: wait for termination?
2055 PULONG pulSID, // out: session ID (req.)
2056 PPID ppid) // out: process ID (req.)
2057{
2058 APIRET arc;
2059 // queue stuff
2060 const char *pcszQueueName = "\\queues\\kfgstart.que";
2061 HQUEUE hq = 0;
2062 PID qpid = 0;
2063 STARTDATA SData;
2064 CHAR szObjBuf[CCHMAXPATH];
2065
2066 if (fWait)
2067 {
2068 if ((arc = DosCreateQueue(&hq,
2069 QUE_FIFO | QUE_CONVERT_ADDRESS,
2070 (PSZ)pcszQueueName))
2071 != NO_ERROR)
2072 return (arc);
2073
2074 if ((arc = DosOpenQueue(&qpid, &hq, (PSZ)pcszQueueName)) != NO_ERROR)
2075 return (arc);
2076 }
2077
2078 SData.Length = sizeof(STARTDATA);
2079 SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
2080 SData.FgBg = (fForeground) ? SSF_FGBG_FORE : SSF_FGBG_BACK;
2081 // V0.9.3 (2000-05-03) [umoeller]
2082 SData.TraceOpt = SSF_TRACEOPT_NONE;
2083
2084 SData.PgmTitle = (PSZ)pcszPath; // title for window
2085 SData.PgmName = (PSZ)pcszPath;
2086 SData.PgmInputs = (PSZ)pcszParams;
2087
2088 SData.TermQ = (fWait) ? "\\queues\\kfgstart.que" : NULL;
2089 SData.Environment = 0;
2090 SData.InheritOpt = SSF_INHERTOPT_PARENT;
2091 SData.SessionType = SSF_TYPE_DEFAULT;
2092 SData.IconFile = 0;
2093 SData.PgmHandle = 0;
2094
2095 SData.PgmControl = usPgmCtl;
2096
2097 SData.InitXPos = 30;
2098 SData.InitYPos = 40;
2099 SData.InitXSize = 200;
2100 SData.InitYSize = 140;
2101 SData.Reserved = 0;
2102 SData.ObjectBuffer = (CHAR*)&szObjBuf;
2103 SData.ObjectBuffLen = (ULONG)sizeof(szObjBuf);
2104
2105 arc = DosStartSession(&SData, pulSID, ppid);
2106
2107 if (arc == NO_ERROR)
2108 {
2109 if (fWait)
2110 {
2111 REQUESTDATA rqdata;
2112 ULONG DataLength = 0;
2113 PULONG DataAddress;
2114 BYTE elpri;
2115
2116 rqdata.pid = qpid;
2117 DosReadQueue(hq, // in: queue handle
2118 &rqdata, // out: pid and ulData
2119 &DataLength, // out: size of data returned
2120 (PVOID*)&DataAddress, // out: data returned
2121 0, // in: remove first element in queue
2122 0, // in: wait for queue data (block thread)
2123 &elpri, // out: element's priority
2124 0); // in: event semaphore to be posted
2125 }
2126 }
2127
2128 if (hq)
2129 DosCloseQueue(hq);
2130
2131 return (arc);
2132}
2133
2134
Note: See TracBrowser for help on using the repository browser.