source: trunk/Library/FileUtilsUnit.pas@ 219

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

Copyright updates

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