source: trunk/Library/FileUtilsUnit.pas@ 235

Last change on this file since 235 was 235, checked in by RBRi, 18 years ago

more constants; small cleanup

  • Property svn:eol-style set to native
File size: 32.4 KB
Line 
1Unit FileUtilsUnit;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2003-2006 Aaron Lawrence
5// Copyright 2006-2007 Ronald Brill (rbri at rbri dot de)
6// This software is released under the GNU Public License - see readme.txt
7
8// Helper functions for file handling
9
10Interface
11
12uses
13 Classes,
14 ACLUtility;
15
16
17const
18 DIRECTORY_SEPARATOR = '\';
19 PATH_SEPARATOR = ';';
20 CURRENT_DIRECTORY = '.';
21 PARENT_DIRECTORY = '..';
22 FILE_EXTENSION_DELIMITER = '.';
23
24 // Drive numbers are one based
25 MinDriveNumber = 1;
26 MaxDriveNumber = 26;
27
28
29 // TODO
30 HelpPathEnvironmentVar = 'HELP';
31 BookshelfEnvironmentVar = 'BOOKSHELF';
32 LanguageEnvironmentVar = 'LANG';
33 DEFAULT_LANGUAGE = 'EN_US';
34 HELP_FILE_EXTENSION = FILE_EXTENSION_DELIMITER + 'hlp';
35
36
37type
38 TDriveType =
39 (
40 dtNone,
41 dtFloppy,
42 dtHard,
43 dtCD,
44 dtNetwork,
45 dtRemovable
46 );
47
48
49 // Adds a slash to the end of dir if not present
50 // if aDir is empty this returns '\'
51 Function AddDirectorySeparator(aDirectory : String) : String;
52
53 // Adds a slash to the end of dir if not present
54 // if aDir is empty this returns ''
55 Function AddDirectorySeparatorIfNotEmpty(aDirectory: String) : String;
56
57 // Removes a directory seperator from the end of aDirectory
58 // (if present)
59 Function RemoveRightDirectorySeparator(aDirectory : String) : String;
60
61 // Expands the path given, relative to aBaseDirectory
62 // Handles leading \ for root dir,
63 // .. for parent, . (ignored),
64 // drive spec at start,
65 // ignores repeated \ e.g. \\
66 Function ExpandPath(aBaseDirectory : String; aPath : String): String;
67
68 Function GetLogFilesDir: String;
69
70 Function SearchPath(const aPathEnvVar: String; const aFilename: String; var aResultFilename: String) : boolean;
71
72 Function SearchHelpPaths(const aFilename: String; var aResultFilename: String; const anIncludeAppDir: boolean) : boolean;
73
74 // Find the help file for the current app based on LANG
75 Function FindDefaultLanguageHelpFile(const anApplicationName: String; const aLanguage : String) : String;
76
77 // Breaks up specified Env var path
78 // this always clears the list at the beginning
79 Procedure GetDirsInPath(const aPathEnvVar: String; var aList: TStrings);
80
81 // Breaks up specified Env var path
82 // then adds all matching files to the list
83 Procedure GetFilesInPath( const aPathEnvVar: String;
84 const aFilter: String;
85 var aList: TStrings );
86
87 // searches for all files in aDirectory matching aFilter and add
88 // them to aList
89 // it is possible to define different filter if you separate them by semicolon
90 Procedure ListFilesInDirectory( const aDirectory : String;
91 const aFilter : String;
92 const aWithDirectoryFlag : boolean;
93 var aList : TStrings);
94
95 // searches for all directories in aDirectory and add them to aList
96 Procedure ListSubDirectories(const aDirectory: String; var aList: TStrings);
97
98 Procedure ListFilesInDirectoryRecursiveWithTermination(const aDirectory : String;
99 const aFilter : String;
100 const aWithDirectoryFlag : boolean;
101 var aList : TStrings;
102 const aTerminateCheck : TTerminateCheck;
103 const aUseTerminateCheck : boolean);
104
105 Function ParentDir(const aDirectory : String) : String;
106
107 // In the directory startpath, create directory and subdirectories
108 // specified in DirsString
109 // e.g. bob\bill\fred will make bob, then bill in bob, then fred in bob
110 // returns path to lowest dir created
111 Function MakeDirs(const aFullDirectoryPath: String) : String;
112
113
114
115 Function DirectoryExists(const aDirectory : String) : boolean;
116
117 Function DriveLetterToDriveNumber(const aDriveLetter : char) : longint;
118 Function DriveNumberToDriveLetter(const aDriveNumber : longint) : char;
119
120 Function GetVolumeLabel(aDrive: char) : String;
121
122 Function GetBootDriveLetter: char;
123
124 // Returns true if file exists and is read only
125 Function FileIsReadOnly(const aFilename : String) : boolean;
126
127
128 // TODO
129 Function IsFloppyDrive( DriveNumber: longint ): Boolean;
130 Function GetLocalDriveType( DriveNumber: longint ): TDriveType;
131 Function GetDriveType( DriveNumber: longint ): TDriveType;
132 Function GetNetworkDriveRemotePath( DriveNumber: longint ): String;
133
134
135Implementation
136
137uses
138 Dos,
139 BseDos,
140 BseErr,
141 BseDev,
142 Os2Def,
143 SysUtils,
144 StringUtilsUnit,
145 CharUtilsUnit;
146
147imports
148 FUNCTION _DosQueryFSAttach( VAR pszDeviceName: CSTRING;
149 ulOrdinal: ULONG;
150 ulFSAInfoLevel:ULONG;
151 pfsqb: PFSQBUFFER2;
152 VAR pcbBuffLength: ULONG ): APIRET; APIENTRY;
153 'DOSCALLS' index 277;
154end;
155
156
157type
158 TWord = Record // Bytes of a Word
159 LoByte, HiByte : Byte;
160 End;
161
162 TBPB = Array[0..30] Of Byte; // Puffer fuer BPB-Struktur
163
164 TDeviceParameters = Record
165 BPB: TBPB;
166 Cylinders: word;
167 DeviceType: Byte;
168 Attributes: Word;
169 End;
170
171
172
173 Function AddDirectorySeparator(aDirectory : String) : String;
174 begin
175 if aDirectory = '' then
176 begin
177 Result:= DIRECTORY_SEPARATOR;
178 exit;
179 end;
180
181 if aDirectory[length(aDirectory)] <> DIRECTORY_SEPARATOR then
182 begin
183 Result := aDirectory + DIRECTORY_SEPARATOR;
184 exit;
185 end;
186
187 Result := aDirectory;
188 end;
189
190
191 Function AddDirectorySeparatorIfNotEmpty(aDirectory: String): String;
192 begin
193 if aDirectory = '' then
194 begin
195 Result := '';
196 exit;
197 end;
198 Result := AddDirectorySeparator(aDirectory);
199 end;
200
201
202 Function RemoveRightDirectorySeparator(aDirectory : String) : String;
203 begin
204 Result := StrTrimRightChars(aDirectory, [DIRECTORY_SEPARATOR]);
205 end;
206
207
208 Function ExpandPath(aBaseDirectory : String; aPath : String): String;
209 var
210 tmpDirectory: String;
211 tmpDirectories : TStringList;
212 i : integer;
213 begin
214 Result:= aBaseDirectory;
215
216 if aPath = '' then
217 begin
218 Result := StrTrimRightChars(Result, [DIRECTORY_SEPARATOR]);
219 exit;
220 end;
221
222 aPath := trim(aPath);
223 if Length(aPath) > 1 then
224 begin
225 // check for drive spec
226 if aPath[2] = ':' then
227 begin
228 Result := AddDirectorySeparator(aPath);
229 if Length(aPath) > 3 then
230 begin
231 Result := StrTrimRightChars(Result, [DIRECTORY_SEPARATOR]);
232 end;
233 exit;
234 end
235 end;
236
237 if Length(aPath) > 0 then
238 begin
239 // check for root dir spec
240 if aPath[1] = DIRECTORY_SEPARATOR then
241 begin
242 // take just the drive from the basedir
243 if aBaseDirectory[2] = ':' then
244 begin
245 Result := StrLeft(aBaseDirectory, 2);
246 end
247 else
248 begin
249 Result := DIRECTORY_SEPARATOR;
250 end;
251 aPath := StrTrimLeftChars(aPath, [DIRECTORY_SEPARATOR]);
252 end;
253 end;
254
255 tmpDirectories := TStringList.Create;
256 StrExtractStringsIgnoreEmpty(tmpDirectories, aPath, [DIRECTORY_SEPARATOR], #0);
257 for i := 0 to tmpDirectories.count-1 do
258 begin
259 tmpDirectory := tmpDirectories[i];
260 if tmpDirectory = PARENT_DIREcTORY then
261 begin
262 if NOT ((Length(Result) = 2) AND (Result[2] = ':')) then
263 begin
264 Result := ParentDir(Result);
265 end;
266 end
267 else if tmpDirectory = CURRENT_DIRECTORY then
268 begin
269 ; // nothing to do
270 end
271 else
272 begin
273 Result := AddDirectorySeparator(Result) + tmpDirectory;
274 end;
275
276 // strip any extra leading slashes
277 aPath := StrTrimLeftChars(aPath, [DIRECTORY_SEPARATOR]);
278 end;
279 tmpDirectories.Destroy;
280
281 if Length(Result) = 2 then
282 begin
283 if Result[2] = ':' then
284 begin
285 // just a drive spec X:, so add a slash
286 Result := Result + DIRECTORY_SEPARATOR;
287 end;
288 end;
289 end;
290
291 Function GetLogFilesDir: String;
292 begin
293 // ecomstation 1.1 compat
294 Result := GetEnv('LOGFILES');
295 if Result <> '' then
296 begin
297 Result := AddDirectorySeparator(Result);
298 exit;
299 end;
300 // TODO
301 Result := AddDirectorySeparator(GetApplicationDir);
302 end;
303
304
305 Function SearchPath(const aPathEnvVar: String;
306 const aFilename: String;
307 var aResultFilename: String) : boolean;
308 var
309 tmpSzEnvVar : CString;
310 tmpSzFilename : CString;
311 tmpSzFilenameFound : CString;
312 tmpRC: APIRET;
313 begin
314 Result := false;
315 aResultFilename := '';
316
317 tmpSzEnvVar := aPathEnvVar;
318 tmpSzFilename := aFilename;
319 tmpRC := DosSearchPath( SEARCH_IGNORENETERRS
320 + SEARCH_ENVIRONMENT
321 + SEARCH_CUR_DIRECTORY,
322 tmpSzEnvVar,
323 tmpSzFilename,
324 tmpSzFilenameFound,
325 sizeof(tmpSzFilenameFound));
326 if tmpRC = 0 then
327 begin
328 Result := true;
329 aResultFilename := tmpSzFilenameFound;
330 end;
331 end;
332
333
334 Function SearchHelpPaths(const aFilename: String;
335 var aResultFilename: String;
336 const anIncludeAppDir: boolean) : boolean;
337 begin
338 Result := SearchPath(HelpPathEnvironmentVar, aFileName, aResultFilename);
339 if not Result then
340 begin
341 Result := SearchPath(BookshelfEnvironmentVar, aFileName, aResultFilename);
342 end;
343
344 if (not Result) and anIncludeAppDir then
345 begin
346 aResultFilename := AddDirectorySeparator(GetApplicationDir) + aFilename;
347 Result := FileExists(aResultFilename);
348 if not Result then
349 begin
350 aResultFilename := '';
351 end;
352 end;
353 end;
354
355
356 Function FindDefaultLanguageHelpFile(const anApplicationName: String; const aLanguage : String) : String;
357 var
358 tmpLanguage : String;
359 tmpLanguageParts : TStringList;
360 tmpMajorLanguage : String;
361 tmpMinorLanguage : String;
362 begin
363 Result := '';
364
365 tmpLanguage := aLanguage;
366 if aLanguage = '' then
367 begin
368 tmpLanguage := DEFAULT_LANGUAGE;
369 end;
370
371 tmpLanguageParts := TStringList.Create;
372 StrExtractStrings(tmpLanguageParts, tmpLanguage, ['_'], #0);
373
374 tmpMajorLanguage := '';
375 if tmpLanguageParts.count > 0 then
376 begin
377 tmpMajorLanguage := tmpLanguageParts[0];
378 end;
379
380 tmpMinorLanguage := '';
381 if tmpLanguageParts.count > 1 then
382 begin
383 tmpMinorLanguage := tmpMinorLanguage[1];
384 end;
385
386 tmpLanguageParts.Destroy;
387
388 // note there might be some other stuff on the end of LANG
389 // such as ES_ES_EURO...
390 if tmpMinorLanguage <> '' then
391 begin
392 if SearchHelpPaths( anApplicationName
393 + '_' + tmpMajorLanguage
394 + '_' + tmpMinorLanguage
395 + HELP_FILE_EXTENSION,
396 Result,
397 true ) then
398 begin
399 // found a specifc language
400 exit;
401 end;
402 end;
403
404 // try generic language?
405 if SearchHelpPaths( anApplicationName
406 + '_' + tmpMajorLanguage
407 + HELP_FILE_EXTENSION,
408 Result,
409 true ) then
410 begin
411 exit;
412 end;
413
414 // nothing specific, search for default
415 SearchHelpPaths(anApplicationName + HELP_FILE_EXTENSION, Result, true);
416 end;
417
418
419 Procedure GetDirsInPath(const aPathEnvVar: String; var aList: TStrings);
420 var
421 tmpRC : APIRET;
422 tmpPszPathEnvVar : PChar;
423 tmpSzEnvVar : CString;
424 begin
425 // do this in any case also if there is an error
426 // to garantie a defined behavior
427 aList.Clear;
428
429 tmpSzEnvVar := aPathEnvVar;
430 tmpRC := DosScanEnv(tmpSzEnvVar, tmpPszPathEnvVar);
431
432 if tmpRC <> 0 then
433 begin
434 exit;
435 end;
436
437 StrExtractStringsIgnoreEmpty(aList, StrPas(tmpPszPathEnvVar), [PATH_SEPARATOR], #0);
438 end;
439
440
441 Procedure GetFilesInPath( const aPathEnvVar: String;
442 const aFilter: String;
443 var aList: TStrings );
444 var
445 tmpDirectories : TStringList;
446 i : integer;
447 begin
448 tmpDirectories := TStringList.Create;
449 GetDirsInPath(aPathEnvVar, tmpDirectories);
450
451 for i:=0 to tmpDirectories.count-1 do
452 begin
453 ListFilesInDirectory(tmpDirectories[i], aFilter, false, aList);
454 end;
455
456 tmpDirectories.Destroy;
457 end;
458
459
460 Procedure ListFilesInDirectory( const aDirectory: String;
461 const aFilter: String;
462 const aWithDirectoryFlag: boolean;
463 var aList: TStrings);
464 var
465 tmpRC : APIRET;
466 tmpSearchResults: TSearchRec;
467 tmpMask: String;
468 tmpFilterParts : TStringList;
469 tmpDirectory : String;
470 i : integer;
471 begin
472 tmpFilterParts := TStringList.Create;
473 StrExtractStrings(tmpFilterParts, aFilter, [PATH_SEPARATOR], #0);
474
475 for i:=0 to tmpFilterParts.count-1 do
476 begin
477 tmpMask := tmpFilterParts[i];
478 tmpDirectory := AddDirectorySeparator(aDirectory);
479 tmpRC := FindFirst(tmpDirectory + tmpMask, faAnyFile, tmpSearchResults);
480
481 while tmpRC = 0 do
482 begin
483 if tmpSearchResults.Attr And faDirectory = 0 then
484 begin
485 if (aWithDirectoryFlag) then
486 begin
487 aList.Add(tmpDirectory + tmpSearchResults.Name);
488 end
489 else
490 begin
491 aList.Add(tmpSearchResults.Name);
492 end;
493 end;
494
495 tmpRC := FindNext(tmpSearchResults);
496 end;
497
498 FindClose(tmpSearchResults);
499 end;
500 tmpFilterParts.Destroy;
501 end;
502
503
504 Procedure ListSubDirectories(const aDirectory: String; var aList: TStrings);
505 var
506 tmpRC : APIRET;
507 tmpSearchResults: TSearchRec;
508 tmpName : String;
509 begin
510
511 tmpRC := FindFirst(AddDirectorySeparator(aDirectory) + '*', faDirectory or faMustDirectory, tmpSearchResults);
512 if (tmpRC <> 0) then
513 begin
514 exit;
515 end;
516
517 while tmpRC = 0 do
518 begin
519 tmpName := tmpSearchResults.Name;
520 if (tmpName <> CURRENT_DIRECTORY) AND (tmpName <> PARENT_DIRECTORY) then
521 begin
522 aList.Add(AddDirectorySeparatorIfNotEmpty(aDirectory) + tmpSearchResults.Name );
523 end;
524 tmpRC := FindNext(tmpSearchResults);
525 end;
526 FindClose(tmpSearchResults);
527 end;
528
529
530 Procedure ListFilesInDirectoryRecursiveWithTermination(const aDirectory : String;
531 const aFilter : String;
532 const aWithDirectoryFlag : boolean;
533 var aList : TStrings;
534 const aTerminateCheck : TTerminateCheck;
535 const aUseTerminateCheck : boolean);
536 var
537 i : integer;
538 tmpSubDirectories : TStringList;
539 tmpSubDirectory : String;
540 begin
541 // at first add all files from the directory itself
542 ListFilesInDirectory(aDirectory, aFilter, aWithDirectoryFlag, aList);
543
544 // now determine all subdirectories
545 tmpSubDirectories := TStringList.Create;
546 ListSubDirectories(aDirectory, tmpSubDirectories);
547
548 for i := 0 to tmpSubDirectories.Count - 1 do
549 begin
550 // if Assigned( TerminateCheck ) then - doesn't work in sibyl
551 if aUseTerminateCheck then
552 if aTerminateCheck then
553 break;
554
555 tmpSubDirectory := tmpSubDirectories[i];
556
557 ListFilesInDirectoryRecursiveWithTermination(tmpSubDirectory, aFilter, aWithDirectoryFlag, aList, aTerminateCheck, aUseTerminateCheck);
558 end;
559 tmpSubDirectories.Destroy;
560 end;
561
562
563 Function ParentDir(const aDirectory : String) : String;
564 var
565 tmpPos: integer;
566 begin
567 tmpPos := Length(aDirectory);
568
569 // ends with slash
570 while (aDirectory[tmpPos] = DIRECTORY_SEPARATOR) AND (tmpPos > 0) do
571 begin
572 dec(tmpPos);
573 end;
574
575 // find slash
576 while (aDirectory[tmpPos] <> DIRECTORY_SEPARATOR) AND (tmpPos > 0) do
577 begin
578 dec(tmpPos);
579 end;
580
581 result:= StrLeft(aDirectory, tmpPos-1);
582 end;
583
584
585 Function MakeDirs(const aFullDirectoryPath: String) : String;
586 Var
587 tmpDirectoryParts : TStringList;
588 tmpDirectoryPart : String;
589 tmpCompletePart : String;
590 i : integer;
591 begin
592 tmpDirectoryParts := TStringList.Create;
593 StrExtractStringsIgnoreEmpty(tmpDirectoryParts, aFullDirectoryPath, [DIRECTORY_SEPARATOR], #0);
594
595 tmpCompletePart := '';
596 for i:=0 to tmpDirectoryParts.count-1 do
597 begin
598 tmpDirectoryPart := trim(tmpDirectoryParts[i]);
599
600 if tmpDirectoryPart <> '' then
601 begin
602 tmpCompletePart := AddDirectorySeparatorIfNotEmpty(tmpCompletePart) + tmpDirectoryPart;
603
604 if not DirectoryExists(tmpCompletePart) then
605 begin
606 MkDir(tmpCompletePart);
607 end;
608 end;
609 end;
610
611 Result := tmpCompletePart;
612 end;
613
614
615 Function DirectoryExists(const aDirectory : String) : boolean;
616 Var
617 tmpRC : APIRET;
618 tmpSearchResults : TSearchRec;
619 tmpDriveMap : ULONG;
620 tmpActualDrive : ULONG;
621 tmpDrive : Char;
622 tmpDriveNum : integer;
623 tmpDriveBit : longword;
624 tmpDirectory : String;
625 Begin
626 Result := false;
627 tmpDirectory := RemoveRightDirectorySeparator(aDirectory);
628 if tmpDirectory = '' then
629 begin
630 Result:= true;
631 exit;
632 end;
633
634 if Length(tmpDirectory) = 2 then
635 begin
636 if tmpDirectory[2] = ':' then
637 begin
638 // a drive only has been specified
639 tmpDrive:= UpCase(tmpDirectory[1] );
640 if (tmpDrive < 'A') or (tmpDrive > 'Z') then
641 begin
642 // invalid drive; return false;
643 exit;
644 end;
645
646 DosQueryCurrentDisk(tmpActualDrive, tmpDriveMap);
647 tmpDriveNum := Ord(tmpDrive) - Ord('A') + 1; // A -> 1, B -> 2...
648 tmpDriveBit := 1 shl (tmpDriveNum-1); // 2^DriveNum
649
650 Result := tmpDriveMap and (tmpDriveBit) > 0;
651 exit;
652 end;
653 end;
654
655 tmpRC := FindFirst(tmpDirectory, faDirectory or faMustDirectory, tmpSearchResults);
656 if tmpRC = 0 then
657 begin
658 Result:= true;
659 FindClose(tmpSearchResults);
660 end;
661 end;
662
663
664 Function DriveLetterToDriveNumber(const aDriveLetter : char) : longint;
665 begin
666 if (aDriveLetter >= 'a')
667 and (aDriveLetter <= 'z') then
668 begin
669 Result := Ord(aDriveLetter) - Ord('a') + 1;
670 exit;
671 end;
672
673 if (aDriveLetter >= 'A')
674 and (aDriveLetter <= 'Z') then
675 begin
676 Result := Ord(aDriveLetter) - Ord('A') + 1;
677 exit;
678 end;
679
680 // not a valid drive letter
681 Result := 0;
682 end;
683
684
685 Function DriveNumberToDriveLetter(const aDriveNumber: longint) : char;
686 begin
687 Result := Chr(aDriveNumber - 1 + Ord('A'));
688 end;
689
690
691 Function GetVolumeLabel(aDrive: char) : String;
692 var
693 tmpRC : APIRET;
694 tmpFileSystemInfo : FSINFO;
695 e : EInOutError;
696 begin
697 DosErrorAPI( FERR_DISABLEHARDERR );
698 Result := '';
699 tmpRC := DosQueryFSInfo( DriveLetterToDriveNumber(aDrive),
700 FSIL_VOLSER,
701 tmpFileSystemInfo,
702 sizeof(tmpFileSystemInfo));
703 if tmpRC = 0 then
704 begin
705 Result := StrPasWithLength(Addr(tmpFileSystemInfo.vol.szVolLabel), tmpFileSystemInfo.vol.cch);
706 Result := LowerCase(Result);
707 end;
708 DosErrorAPI( FERR_ENABLEHARDERR );
709
710 if tmpRC <> 0 then
711 begin
712 e := EInOutError.Create( 'Cannot read drive ' + aDrive + ':');
713 e.ErrorCode := tmpRC;
714 raise e;
715 end;
716 end;
717
718
719 Function GetBootDriveLetter: char;
720 var
721 tmpBuffer: longword;
722 begin
723 DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, tmpBuffer, sizeof(tmpBuffer));
724 Result := Chr(ord('A') + tmpBuffer - 1);
725 end;
726
727
728 Function FileIsReadOnly(const aFilename : String ) : boolean;
729 begin
730 Result :=(FileGetAttr(aFilename) AND faReadonly) > 0;
731 end;
732
733
734
735
736 // TODO
737
738
739Function IsFloppyDrive( DriveNumber: longint ): Boolean;
740Var
741 bResult : Byte;
742Begin
743 DosDevConfig( bResult, DEVINFO_FLOPPY );
744 Result := ( Abs( DriveNumber ) <= bResult);
745End;
746
747// -------------------------------------------------------------------------
748// Funktion/Function: QueryCDRoms()
749//
750// Beschreibung:
751// Die Funktion QueryCDRom ermittelt ueber eine nicht dokumentierte
752// Schnittstelle die Anzahl der CDRom-Laufwerke und den ersten, fuer
753// ein CDRom-Laufwerk, vergebenen UnitIdentifier.
754// Der Treiber OS2CDROM.DMD stellt dem System zwei Devices (CD-ROM1$
755// und CD-ROM2$) zur Verfuegung. Die beiden Devices unterscheiden sich
756// durch DeviceAttribute. Beide Devices unterstuetzen (zumindest unter
757// Warp) den undokumentierten Generic IOCtl 0x82/0x60, welcher Infor-
758// mationen ueber die angeschlossenen CDRom-Laufwerke liefert.
759//
760// Description:
761// This Functions finds out how many CD-Rom Drives are present in System
762// and which Drive Letter is the first occupied by a CD-Rom. It uses an
763// undocumented Interface to OS2CDROM.DMD.
764// OS2CDROM.DMD presents two Devices (CD-ROM1$ and CD-ROM2$). These De-
765// vices are distinguished by their Device-Attributes. Both Devices sup-
766// port (under Warp) the undocumented generic IOCtl-Call 0x82/0x60 which
767// deliver some Information about the connected CD-Rom Drives.
768//
769// Parameter:
770// Var ulCDRomCount ULONG Anzahl CD-Rom Laufwerke im System
771// Number of CD-Rom Drives in System
772//
773// Var ulFirstCDRomDiskNo ULONG erste Laufwerksnummer, die an ein
774// CD-Rom vergeben ist
775// first Drive-Letter occupied by a
776// CD-Rom Drive
777//
778// Rueckgabe/Returnvalue: keine/none
779// -------------------------------------------------------------------------
780Procedure QueryCDRoms(Var ulCDRomCount, ulFirstCDRomDiskNo: ULONG);
781
782Const cszDriverName : CSTRING = 'CD-ROM?$';
783
784Var cCurDriver : Char; // Indexvariable fuer aktuell bearbeites Device (1 oder 2)
785 // Index for current Device (1 or 2)
786
787 hDevHandle : HFILE; // Handle fuer Device
788 // Device handle
789
790 ulAction : ULONG; // Aktionscode (DosOpen())
791 // Actioncode (DosOpen())
792
793 ulParams : ULONG; // Anzahl Bytes von IOCtl gelieferter Parameterdaten
794 // Number of Bytes for delivered Parameterdata
795
796 ulData : ULONG; // Anzahl Bytes von IOCtl gelieferter Daten
797 // Number of Bytes delivered by IOCtl
798
799 rCDInfo : Record // Ergebnisstruktur der IOCtl-Funktion (s.o.)
800 // Record for Results of IOCtl-Call (see above)
801 usCDRomCount : USHORT; // Anzahl CD-Roms / Number of CD-Rom Drives
802 usFirstUnitNo: USHORT; // erste vergebene Laufwerksnummer / first Driver Letter
803 End;
804
805Begin (* uQueryCDRom *)
806 /************************************
807 * Vorbelegungen
808 *
809 * initial assignments
810 ************************************/
811 ulCDRomCount := 0;
812 ulFirstCDRomDiskNo := 0;
813
814 ulParams := 0;
815
816 /************************************
817 * die beiden Devices abarbeiten
818 *
819 * accessing both Devices
820 ************************************/
821 For cCurDriver := '1' To '2' Do
822 Begin
823 /************************************
824 * Device oeffnen
825 *
826 * open Device
827 ************************************/
828 cszDriverName[6] := cCurDriver;
829 If (DosOpen(cszDriverName, // Devicename
830 hDevHandle, // Handle
831 ulAction, // Aktionscode
832 0, // DateigrӇe
833 FILE_NORMAL, // Attribute: read/write
834 OPEN_ACTION_OPEN_IF_EXISTS, // OpenFlag: ”ffnen, wenn vorhanden
835 OPEN_FLAGS_FAIL_ON_ERROR Or // Modus: Fehlermeldung per Returncode
836 OPEN_SHARE_DENYNONE Or // keine Einschr„nkungen fr Dritte
837 OPEN_ACCESS_READONLY, // nur lesender Zugriff
838 NIL)=NO_ERROR) Then // keine EA
839 Begin
840 /************************************
841 * IOCtl-Funktion aufrufen
842 *
843 * Call to IOCtl
844 ************************************/
845 If (DosDevIOCtl(hDevHandle, // Handle / Handle
846 $82, // Kategorie / Category
847 $60, // Funktion / Function
848 NIL, // keine Parameterliste / No Parameterlist
849 0, // Laenge Parameterliste / Length of Parameterlist
850 ulParams, // Groesse der gelieferten Parameterdaten
851 // / Number of Bytes for Parameterdata
852 rCDInfo, // Puffer fuer gelieferte Daten
853 // / Buffer for returned Data
854 SizeOf(rCDInfo), // Groesse des Datenpuffers
855 // / Size of Databuffer
856 ulData)=NO_ERROR) Then // Groesse der gelieferten Daten
857 // / Number of Bytes for returned Data
858 Begin
859 ulCDRomCount := rCDInfo.usCDRomCount;
860 ulFirstCDRomDiskNo := Succ(rCDInfo.usFirstUnitNo);
861 End;
862
863 DosClose(hDevHandle);
864 End;
865
866 End; (* For *)
867
868End; (* uQueryCDRom *)
869
870
871Function GetLocalDriveType( DriveNumber: longint ): TDriveType;
872var
873 IOCtlParameters: Word;
874 rc: APIRET;
875 ParameterLength: longWord;
876 DataLength: longword;
877 DeviceData: TDeviceParameters;
878 Fixed: boolean;
879 FirstCDDrive: ULONG;
880 NumCDDrives: ULONG;
881begin
882
883 TWord( IOCtlParameters ).LoByte := 0; // BPB of physical Device
884 TWord( IOCtlParameters ).HiByte := DriveNumber - 1; // drive number, zero base
885
886 ParameterLength := SizeOf( IOCtlParameters ); // input length of parameters
887 DataLength := 0; // input length of data (none)
888
889 rc := DosDevIOCTL( HFILE(-1), // Open Device (not a file)
890 IOCTL_DISK, // Category
891 DSK_GETDEVICEPARAMS, // Function
892 IOCtlParameters, // Parameters
893 SizeOf( IOCtlParameters ), // (max) size of parameters
894 ParameterLength, // parameters length
895 DeviceData, // results
896 SizeOf( DeviceData ), // (max) size of data block
897 DataLength ); // data block length
898
899 Fixed := ( DeviceData.Attributes and 1 ) > 0; // bit 0 indicates fixed (1) or removable (0)
900 if not Fixed then
901 begin
902 result := dtRemovable;
903
904 QueryCDRoms( FirstCDDrive,
905 NumCDDrives );
906
907 if ( DriveNumber >= FirstCDDrive )
908 and ( DriveNumber < FirstCDDrive + NumCDDrives ) then
909 result := dtCD;
910
911 exit;
912 end;
913
914 result := dtHard;
915end;
916
917// Takes a one-based drive number
918Function GetDriveType( DriveNumber: longint ): TDriveType;
919var
920 szDrive: CString;
921
922 FSData: array[ 0..sizeof( FSQBuffer) + 3*_MAX_PATH ] of char;
923 pBuffer: PFSQBUFFER2;
924 FSDataLength: ULONG;
925
926 rc: APIRET;
927begin
928 assert( DriveNumber >= 1 );
929 assert( DriveNumber <= 26 );
930
931 if ( DriveNumber >=1 ) and ( DriveNumber <= 2 ) then
932 begin
933 if IsFloppyDrive( DriveNumber ) then
934 begin
935 result := dtFloppy;
936 exit;
937 end;
938
939 result := dtNone; // don't let OS/2 try a fake B: drive
940 exit;
941 end;
942
943 DosErrorAPI( FERR_DISABLEHARDERR );
944
945 szDrive := DriveNumberToDriveLetter( DriveNumber ) + ':';
946 FSDataLength := sizeof( FSData );
947 pBuffer := Addr( FSData );
948 rc := _DosQueryFSAttach( szDrive,
949 0, // ignored
950 FSAIL_QUERYNAME,
951 pBuffer,
952 FSDataLength );
953
954 if rc = 0 then
955 begin
956 case pBuffer^.iType of
957 FSAT_REMOTEDRV:
958 result := dtNetwork;
959
960 FSAT_LOCALDRV:
961 // Figure out what kind of local drive it is...
962 result := GetLocalDriveType( DriveNumber );
963
964 else
965 begin
966 // should never happen
967 result := dtNone;
968 exit;
969 end;
970 end;
971 end
972 else if rc = ERROR_NOT_READY then
973 begin
974 // No media?
975 // Have a look for a local disk anyway.
976 result := GetLocalDriveType( DriveNumber );
977 end
978 else
979 begin
980 result := dtNone;
981 end;
982
983 DosErrorAPI( FERR_ENABLEHARDERR );
984end;
985
986const
987 DEVLEN = 8;
988 CNLEN = 15; // Computer name length
989 UNCLEN = (CNLEN+2); // UNC computer name length
990 NNLEN = 12; // 8.3 Net name length (share name length)
991 RMLEN = (UNCLEN+1+NNLEN); // Maximum remote name length
992
993type
994 use_info_0 = record
995 ui0_local: cstring[ DEVLEN ]; // note this is of size DEVLEN + 1
996 ui0_pad_1: char;
997 ui0_remote: pchar;
998 space: array[ 0..RMLEN ] of char; // remote path is written to somewhere in here
999 end;
1000
1001 use_info_1 = record
1002 ui0_local: cstring[ DEVLEN ];
1003 ui0_pad_1: char;
1004 ui0_remote: pchar; // address of a buffer to hold remote path
1005 ui1_password: pchar; //
1006 ui1_status: USHORT;
1007 ui1_asg_type: SHORT;
1008 ui1_refcount: USHORT;
1009 ui1_usecount: USHORT;
1010 space: array[ 0..RMLEN ] of char; // remote path is written to somewhere in here
1011 end;
1012
1013 TNet32UseGetInfo = Function( pszServer: pchar;
1014 pszUseName: pchar; // e.g. drive x:
1015 ulLevel: ULONG;
1016 pbBuffer: pointer; // pointer to output buffer
1017 ulBuffer: ULONG; // size of output in buffer
1018 Var pulTotalAvail: ULONG )
1019 : word; CDecl;
1020
1021Var
1022 Net32UseGetInfo: TNet32UseGetInfo;
1023 hNetAPI32DLL: HMODULE;
1024 TriedLoading: boolean;
1025
1026// 129 Net32UseGetInfo
1027Function GetNetworkDriveRemotePath( DriveNumber: longint ): string;
1028var
1029 ErrorName: array[ 0..255 ] of char;
1030 dummy: cstring;
1031 rc: word;
1032 UseName: array[ 0..255 ] of char;
1033 UseInfo: use_info_0;
1034 pUseInfo: pointer;
1035 TotalBytesNeeded: ULONG;
1036 RemotePath: array[ 0..255 ] of char;
1037 Dummy2: array[ 0..4096 ] of char; // try to fix stack probs
1038begin
1039 Result := '';
1040
1041 if not TriedLoading then
1042 begin
1043 TriedLoading := true;
1044 rc := DosLoadModule( ErrorName,
1045 sizeof( ErrorName ),
1046 'NETAPI32',
1047 hNetAPI32DLL );
1048 if rc = NO_ERROR then
1049 begin
1050 // NetAPI32.DLL loaded OK
1051 rc := DosQueryProcAddr( hNetAPI32DLL,
1052 129,
1053 dummy,
1054 pointer( Net32UseGetInfo ) );
1055 if rc <> 0 then
1056 Net32UseGetInfo := nil;
1057 end;
1058 end;
1059
1060 if Assigned( Net32UseGetInfo ) then
1061 begin
1062 UseName[ 0 ] := DriveNumberToDriveLetter( DriveNumber );
1063 UseName[ 1 ] := ':';
1064 UseName[ 2 ] := #0;
1065
1066 RemotePath[ 0 ] := #0;
1067// UseInfo.ui0_remote := Addr( RemotePath );
1068
1069 pUseInfo := Addr( UseInfo );
1070 rc := Net32UseGetInfo( nil, // server - always nil
1071 Addr( UseName ),
1072 0, // info level 0
1073 pUseInfo,
1074 sizeof( UseInfo ),
1075 TotalBytesNeeded );
1076
1077 if rc = 0 then
1078 Result := StrPas( UseInfo.ui0_remote );
1079
1080 end;
1081end;
1082
1083
1084Initialization
1085End.
Note: See TracBrowser for help on using the repository browser.