source: trunk/Library/FileUtilsUnit.pas@ 187

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

moved to library

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