home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 May / Chip_2002-05_cd1.bin / zkuste / delphi / kompon / d5 / CAKDIR.ZIP / VWIN32.PAS < prev    next >
Pascal/Delphi Source File  |  1999-10-21  |  110KB  |  2,369 lines

  1. {------------------------------------------------------------------------------}
  2. { unit       : vwin32                                                          }
  3. { version    : 1.0                                                             }
  4. { last update: 1999/04/06                                                      }
  5. { written for: Delphi 3 & 4                                                    }
  6. { written by : Geir Wikran                                                     }
  7. { e-mail     : gwikran@online.no                                               }
  8. {                                                                              }
  9. { This source code is freeware. You may use, change, and distribute without    }
  10. { charge the source code as you like. This unit can be used freely in any      }
  11. { commercial applications. However, it may not be sold as a standalone product }
  12. { and the source code may not be included in a commercial product. This unit   }
  13. { is provided as is with no warrent or support. Make sure to read relevant     }
  14. { information and documentation from Microsoft before using this unit.         }
  15. {------------------------------------------------------------------------------}
  16.  
  17.  
  18. {- Relevant information and documentation from Microsoft ----------------------}
  19. {                                                                              }
  20. { Go to http://www.microsoft.com/ and select "Search".                         }
  21. { Enter "VWIN32" for search word, and select search                            }
  22. { category "Support & the Knowledge Base". The search                          }
  23. { will give articles on how to do low-level disk access                        }
  24. { under Win9x.                                                                 }
  25. {                                                                              }
  26. { Go to http://msdn.microsoft.com/library/                                     }
  27. { Browse down the tree to find                                                 }
  28. { -Platform SDK                                                                }
  29. {   -Windows Base Services                                                     }
  30. {     -Windows 95 Features                                                     }
  31. {       -Windows 95 Reference                                                  }
  32. { Before doing any direct disk I/O make sure to read                           }
  33. { all information on using the drive locking and lock                          }
  34. { hierarcy. This is important.                                                 }
  35. {                                                                              }
  36. {------------------------------------------------------------------------------}
  37.  
  38.  
  39. unit vwin32;
  40.  
  41. {==============================================================================}
  42. interface
  43.  
  44. uses
  45.   Windows;
  46.  
  47. {- VWIN32 DeviceIoControl -----------------------------------------------------}
  48.  
  49. { Windows 95/98 does not support opening disk drives or partitions with the    }
  50. { CreateFile() function as Windows NT does. Windows 9x does not support the    }
  51. { DeviceIoControl() IOCTL APIs as Windows NT does. Instead, low-level disk     }
  52. { access in Windows 9x is supported through DeviceIoControl() calls to the     }
  53. { VWIN32 VxD, which supports a set of control codes that applications can use  }
  54. { to issue low-level disk I/O functions. These functions include interrup 13h, }
  55. { interrupt 25h, interrupt 26h, interrupt 21h function 44xx and function 730x. }
  56.  
  57. const
  58.   { Name of DIOC device: }
  59.   VWIN32_DEVICE_NAME        = '\\.\VWIN32';
  60.  
  61.   { VWIN32 device control codes used with VWIN32DIOC function: }
  62.   VWIN32_DIOC_CLOSE         = 0; { Close the device.                           }
  63.  
  64.   VWIN32_DIOC_DOS_IOCTL     = 1; { MS-DOS device I/O control function,         }
  65.                                  { interrupt 21h function 4400h through 4411h  }
  66.   VWIN32_DIOC_DOS_INT25     = 2; { MS-DOS absolute disk read command,          }
  67.                                  { interrupt 25h.                              }
  68.   VWIN32_DIOC_DOS_INT26     = 3; { MS-DOS absolute disk write command,         }
  69.                                  { interrupt 26h.                              }
  70.   VWIN32_DIOC_DOS_INT13     = 4; { Low-level BIOS disk functions,              }
  71.                                  { interrupt 13h.                              }
  72.   VWIN32_DIOC_DOS_DRIVEINFO = 6; { MS-DOS Interrupt 21h new function 730x.     }
  73.                                  { Supported only by Windows 95 OSR2 and later.}
  74.  
  75. type
  76.   PDIOC_Registers = ^TDIOC_Registers;
  77.   TDIOC_Registers = record
  78.     case Byte of
  79.     0: (EBX,EDX,ECX,EAX,EDI,ESI,Flags: DWord);
  80.     1: (BX,BXE,DX,DXE,CX,CXE,AX,AXE,DI,DIE,SI,SIE: Word);
  81.   end;
  82.  
  83.   { Some functions require far pointers passed in segment:offset pairs. Since  }
  84.   { 32-bit code does not have segments, the TDIOC_Registers structure contains }
  85.   { no segment registers. The full pointer should be placed into the register  }
  86.   { corresponding to the offset portion of the real-mode pointer. For example, }
  87.   { use EDX for pointer that go into DS:DX.                                    }
  88.  
  89. const
  90.   FLAG_CARRY = $00000001;
  91.  
  92. function  VWIN32DIOC(ControlCode: Integer; Registers: PDIOC_Registers): Boolean;
  93.           { Implements DeviceIoControl() calls to VWIN32.VXD. The device is    }
  94.           { automatically opened when needed. The ControlCode VWIN32_DIOC_CLOSE}
  95.           { can be used to close the device. However, the device will be closed}
  96.           { automatically by the units finalization. The function returnes     }
  97.           { ERROR_OS_NOT_SUPPORTED in VWIN32Error it is not supported by the   }
  98.           { running Windows version, or it returne ERROR_OPENING_DEVICE if an  }
  99.           { error occured when trying to open the device.                      }
  100.  
  101. {- Windows Version ------------------------------------------------------------}
  102.  
  103. function  WindowsVersion(Major,Minor,Build,Platform: DWord): Boolean;
  104.           { Tests the running version of Windows. Returns true if it is equal  }
  105.           { or higher than the specified version info. See GetVersionEx in     }
  106.           { Win32.hlp for more information.                                    }
  107.  
  108. { Windows 9x      - WindowsVersion(0,0,0,VER_PLATFORM_WIN32_WINDOWS)           }
  109. { Windows 95 OSR2 - WindowsVersion(0,0,1081,VER_PLATFORM_WIN32_WINDOWS)        }
  110.  
  111. { Because of changes to functions and data structures after the introduction   }
  112. { of FAT32 in Windows 95 OSR2, a test for this Windows version will often be   }
  113. { needed. To make the test simple this unit provides the boolean variable      }
  114. { Win95OSR2, which is initialized to true if the running Windows 9x is         }
  115. { Windows 95 OSR2 or later.                                                    }
  116.  
  117. var
  118.   Win95OSR2: Boolean;
  119.  
  120. {------------------------------------------------------------------------------}
  121.  
  122. { Logical drives: 0=default, 1=A, 2=B, 3=C ... 26=Z }
  123.  
  124. {------------------------------------------------------------------------------}
  125.  
  126. function  DriveIsRemovable(Drive: Byte): Boolean;
  127.           { Returns true if a drive is removable.                              }
  128. function  DriveIsRemote(Drive: Byte): Boolean;
  129.           { Returns true if a drive is remote.                                 }
  130. function  DriveIsSubstitute(Drive: Byte): Boolean;
  131.           { Returns true if a drive is substituted (see MS-DOS subst command). }
  132. function  DirectAccessAllowed(Drive: Byte): Boolean;
  133.           { Returns true if a drive allows direct I/O.                         }
  134. function  LockRemovableMedia(Drive: Byte): Boolean;
  135.           { Locks the media in a drive (preventing its removal).               }
  136. function  UnlockRemovableMedia(Drive: Byte): Boolean;
  137.           { Unlocks the media in a drive (permitting its removal).             }
  138. function  GetRemovableMediaLocks(Drive: Byte; var Locks: Byte): Boolean;
  139.           { Returns the lock status on a drive (number of pending locks).      }
  140. function  EjectRemovableMedia(Drive: Byte): Boolean;
  141.           { Ejects the media in a drive.                                       }
  142. function  GetAccessFlag(Drive: Byte; var Flag: Byte): Boolean;
  143.           { Returns the access flag for a drive. Flag=0 if access blocked      }
  144.           { (unformatted), Flag<>0 if access allowed.                          }
  145. function  SetAccessFlag(Drive: Byte; Flag: Byte): Boolean;
  146.           { Sets the access flag for a drive.                                  }
  147.  
  148.  
  149. {- Volume Locking -------------------------------------------------------------}
  150.  
  151. const
  152.   { Lock peermission codes: }
  153.   LOCK_ALLOW_WRITING  = $0001; { Allow write operations in level 1 lock. Write }
  154.                                { operations are always blocked in level 2 & 3  }
  155.                                { lock.                                         }
  156.   LOCK_BLOCK_MAPPING  = $0002; { Block new file mappings in level 1 & 2 lock.  }
  157.                                { New file mappings are always blocked in level }
  158.                                { 3 lock.                                       }
  159.                                { Read operations are always allowed in level   }
  160.                                { 1 & 2 lock, and blocked in level 3 lock.      }
  161.   LOCK_FOR_FORMATTING = $0004; { Locks the volume for formatting. Specified    }
  162.                                { when a level 0 lock is obtained for the second}
  163.                                { time.                                         }
  164.  
  165. function  LockLogicalVolume(Drive: Byte; Level,Permission: Byte): Boolean;
  166.           { Locks a logical drive. A drive must be locked before direct disk   }
  167.           { write operations through Interrupt 26h or Interrupt 21h IOCTL      }
  168.           { functions can be performed.                                        }
  169. function  LockPhysicalVolume(Disk: Byte; Level,Permission: Byte): Boolean;
  170.           { Locks a physical disk. Disk 00-7Fh for floppy disk drives          }
  171.           { (00=first floppy drive, 01=second, and so on). Disk 80-FEh         }
  172.           { for hard disk drives (80=first hard disk, 81=second, and so on).   }
  173.           { A disk must be locked before direct disk write operations through  }
  174.           { Interrupt 13h can be performed. The system automatically takes a   }
  175.           { logical volume lock on all logical drives on the physical disk.    }
  176. function  UnlockLogicalVolume(Drive: Byte): Boolean;
  177.           { Unlocks a logical drive and decrements the lock level. To release  }
  178.           { the lock on a drive the unlock function must be called the same    }
  179.           { number of times that lock function was called.                     }
  180. function  UnlockPhysicalVolume(Disk: Byte): Boolean;
  181.           { Unlocks a physical disk and decrements the lock level. To release  }
  182.           { the lock on a disk the unlock function must be called the same     }
  183.           { number of times that lock function was called.                     }
  184. function  GetCurrentLockState(Drive: Byte; var Level,Permission: Byte): Boolean;
  185.           { Returns a drive's current lock level and permission.               }
  186. function  GetLockFlagState(Drive: Byte; var Flags: Word): Boolean;
  187.           { Polls the state of the access flag for a drive to determine if a   }
  188.           { write operation (deleting or renaming a file, writing to a file    }
  189.           { etc.) or a new file mapping has occurred since the last time the   }
  190.           { flags were polled. Flag values:                                    }
  191.           { 0= no operation has occured                                        }
  192.           { 1= write operations have occured                                   }
  193.           { 2= file mapping has occured                                        }
  194.  
  195. const
  196.   { Access modes (bits 0-3): }
  197.   OPEN_ACCESS_READONLY           = $0000;
  198.   OPEN_ACCESS_WRITEONLY          = $0001;
  199.   OPEN_ACCESS_READWRITE          = $0002;
  200.   OPEN_ACCESS_RO_NOMODLASTACCESS = $0004;
  201.   { Share modes (bits 4-6): }
  202.   OPEN_SHARE_COMPATIBLE          = $0000;
  203.   OPEN_SHARE_DENYREADWRITE       = $0010;
  204.   OPEN_SHARE_DENYWRITE           = $0020;
  205.   OPEN_SHARE_DENYREAD            = $0030;
  206.   OPEN_SHARE_DENYNONE            = $0040;
  207.   { Open flags (bits 7-15): }
  208.   OPEN_FLAGS_NOINHERIT           = $0080;
  209.   OPEN_FLAGS_NO_BUFFERING        = $0100;
  210.   OPEN_FLAGS_NO_COMPRESS         = $0200;
  211.   OPEN_FLAGS_ALIAS_HINT          = $0400;
  212.   OPEN_FLAGS_NOCRITERR           = $2000;
  213.   OPEN_FLAGS_COMMIT              = $4000;
  214.  
  215.   { File types: }
  216.   FILE_TYPE_NORMAL               = $0000; { Normal file                        }
  217.   FILE_TYPE_MEMORY_MAPPED        = $0001; { Memory-mapped file (are unmovable) }
  218.   FILE_TYPE_UNMOVABLE            = $0002; { Unmovable (32-bit DLLs and EXEs)   }
  219.   FILE_TYPE_SWAP                 = $0004; { Windows' swap file                 }
  220.  
  221. function  EnumerateOpenFiles(Drive: Byte; FileIndex: DWord; var FilePath: String;
  222.                              var OpenMode,FileType: Word): Boolean;
  223.           { Enumerates open files on the specified drive. The function returns }
  224.           { information about one file at a time. To enumerate all open files, }
  225.           { the function must be called repeatedly with FileIndex set to a new }
  226.           { value for each call. FileIndex should be set to zero initially and }
  227.           { then incremented by one for each subsequent call. The path of the  }
  228.           { open file is returned in PathBuf. The mode that the file was opened}
  229.           { in is returned in OpenMode, which is a combination of access mode, }
  230.           { share mode, and open flags. The type of the file is returned in    }
  231.           { FileType.                                                          }
  232.           { ERROR_NO_MORE_FILES are returned when all open files on the volume }
  233.           { have been enumerated. ERROR_ACCESS_DENIED is returned if FileIndex }
  234.           { exceeds the number of open files on the drive.                     }
  235.           { The function may return inconsistent results when used on a volume }
  236.           { where other processes may be opening and closing files. The volume }
  237.           { should be in a level 3 lock before enumerating open files.         }
  238.  
  239. function  FindSwapFile(var FilePath: String; var PagerType: Word; var PageCount: DWord): Boolean;
  240.           { Returns information about Windows' swap file. The path of the swap }
  241.           { file is returned in FilePath. The type of the pager is returned in }
  242.           { PagerType (1=no pager, 2=paging trough MS-DOS, 3=paging through    }
  243.           { protected-mode I/O supervisor). The current number of 4Kb pages in }
  244.           { the swap file is returned in PageCount.                            }
  245.  
  246. const
  247.   { Reset drive flags: }
  248.   RESET_DRIVE_BUFFERS       = $0000; { Reset drive, flush file system buffers. }
  249.   RESET_DRIVE_BUFFERS_CACHE = $0001; { Reset drive, flush file system buffers, }
  250.                                      { flush and ivalidate drive cache.        }
  251.   RESET_DRIVE_DRIVESPACE    = $0002; { Remounts drivespace volume.             }
  252.  
  253. {function  ResetDrive(Drive: Byte; Flag: Word): Boolean;}
  254.           { Flushes file system buffers and cache and optionally remounts the  }
  255.           { drivespace volume. Any Buffered write operations are performed, and}
  256.           { all waiting data is written to the appropriate drive.              }
  257.  
  258.  
  259. {- Media Identifier -----------------------------------------------------------}
  260.  
  261. type
  262.   TMediaIdentifier = packed record
  263.     InfoLevel          : Word;  { Information level (must be zero).            }
  264.     SerialNumber       : DWord; { Serial number for the medium.                }
  265.     VolumeLabel        : array[0..10] of Char; { Volume label for the medium.  }
  266.     FileSysType        : array[0..7] of Char; { 'FAT12' 12-bit FAT file system }
  267.                                               { 'FAT16' 16-bit FAT file system }
  268.                                               { 'FAT32' 32-bit FAT file system }
  269.                                               { 'CDROM' High Sierra file system}
  270.                                               { 'CD001' ISO9660 file system    }
  271.                                               { 'CDAUDIO' Audio disk           }
  272.   end;
  273.  
  274. function  GetMediaIdentifier(Drive: Byte; var Media: TMediaIdentifier): Boolean;
  275.           { Returnes a drive's serial number, volume label, and file system.   }
  276. function  SetMediaIdentifier(Drive: Byte; Media: TMediaIdentifier): Boolean;
  277.           { Sets a drive's serial number, volume label, and file system.       }
  278.  
  279.  
  280. {- Media Type -----------------------------------------------------------------}
  281.  
  282. type
  283.   TMediaType = packed record
  284.     DefaultType        : ByteBool; { True for the default media type.          }
  285.     CurrentType        : Byte;     { See TDeviceParameters.DeviceType.         }
  286.   end;
  287.  
  288. function  SenseMediaType(Drive: Byte; var Media: TMediaType): Boolean;
  289.           { Returnes the media type for a drive.                               }
  290.  
  291.  
  292. {- Drive Map Info -------------------------------------------------------------}
  293.  
  294. const
  295.   { Drive map info flags: }
  296.   PROT_MODE_LOGICAL_DRIVE  = $01; { Protected-mode driver is in use for this   }
  297.                                   { logical drive.                             }
  298.   PROT_MODE_PHYSICAL_DRIVE = $02; { Protected-mode driver is in use for the    }
  299.                                   { physical drive of this logical drive.      }
  300.   PROT_MODE_ONLY_DRIVE     = $04; { Drive is not available when running with   }
  301.                                   { MS-DOS.                                    }
  302.   PROT_MODE_EJECT          = $08; { Protected-mode drive supports an electronic}
  303.                                   { eject operation.                           }
  304.   PROT_MODE_ASYNC_NOTIFY   = $10; { Drive issues media arrival and removal     }
  305.                                   { notifications.                             }
  306.  
  307. type
  308.   TDriveMapInfo = packed record
  309.     Flags              : Byte;  { Combination of flags describing the drive.   }
  310.     Int13Unit          : Byte;  { Physical drive number of the given drive.    }
  311.                                 { 00-7Fh = floppy disk drive (00 for the first }
  312.                                 { floppy drive, 01 for the second, and so on). }
  313.                                 { 80-FEh = hard disk drive (80 for the first   }
  314.                                 { hard disk, 81 for the second, and so on).    }
  315.                                 { FFh = drive does not map to a physical drive.}
  316.     AssociatedDriveMap : DWord; { Logical drive numbers associated with the    }
  317.                                 { physical drive. For example, a host drive C  }
  318.                                 { with child drive letters A and B would return}
  319.                                 { with bits 0 and 1 set.                       }
  320.     PartitionStartRBA  : DWord; { 64 bits relative block address offset from   }
  321.     PartitionStartRBAHi: DWord; { start of the physical volume to start of the }
  322.                                 { given partition.                             }
  323.   end;
  324.  
  325. function  GetDriveMapInfo(Drive: Byte; var Info: TDriveMapInfo): Boolean;
  326.           { Retrieves maping information about the specified drive.            }
  327.  
  328.  
  329. {- Parameter Blocks -----------------------------------------------------------}
  330.  
  331. type
  332.   PDPB = ^TDPB;
  333.   TDPB = packed record { Drive Parameter Block for FAT12 and FAT16: }
  334.     DriveNumber        : Byte;  { Drive number (0=A, 1=B, and so on).          }
  335.     UnitNumber         : Byte;  { Drive unit number on device driver.          }
  336.     SectorSize         : Word;  { Size of each sector in bytes.                }
  337.     ClusterMask        : Byte;  { Number of sectors per cluster minus 1.       }
  338.     ClusterShift       : Byte;  { Number of sectors per cluster as power of 2. }
  339.     FirstFAT           : Word;  { First sector for the File Allocation Table.  }
  340.     FATCount           : Byte;  { Number of FATs on the drive.                 }
  341.     RootEntries        : Word;  { Number of entries in root directory.         }
  342.     FirstSector        : Word;  { First sector of the first cluster.           }
  343.     MaxCluster         : Word;  { Number of clusters on drive plus 1.          }
  344.     FATSize            : Word;  { Number of sectors occupied by each FAT.      }
  345.     DirSector          : Word;  { First sector for the root directory.         }
  346.     Reserved2          : DWord;
  347.     MediaID            : Byte;  { Media descriptor for the drive.              }
  348.     FirstAccess        : Byte;  { 00h if disk accessed, FFh if not accessed.   }
  349.     Reserved3          : DWord;
  350.     NextFree           : Word;  { Most recently allocated cluster. Cluster at  }
  351.                                 { which to start search for free clusters.     }
  352.     FreeCount          : Word;  { Number of free clusters on the drive.        }
  353.                                 { FFFF if the number is unknown.               }
  354.   end;
  355.  
  356.   PExtDPB = ^TExtDPB;
  357.   TExtDPB = packed record { Extended Drive Parameter Block for FAT32: }
  358.     DriveNumber        : Byte;  { Drive number (0=A, 1=B, and so on).          }
  359.     UnitNumber         : Byte;  { Drive unit number on device driver.          }
  360.     SectorSize         : Word;  { Size of each sector in bytes.                }
  361.     ClusterMask        : Byte;  { Number of sectors per cluster minus 1.       }
  362.     ClusterShift       : Byte;  { Number of sectors per cluster as power of 2. }
  363.     FirstFAT           : Word;  { First sector for the File Allocation Table.  }
  364.     FATCount           : Byte;  { Number of FATs on the drive.                 }
  365.     RootEntries        : Word;  { Number of entries in root directory.         }
  366.     FirstSector        : Word;  { First sector of the first cluster.           }
  367.     MaxCluster         : Word;  { Number of clusters on drive plus 1.          }
  368.                                 { Field is undefined for FAT32 drives.         }
  369.     FATSize            : Word;  { Number of sectors occupied by each FAT.      }
  370.                                 { Zero indicates a FAT32 drive.                }
  371.                                 { Use ExtFATSize for FAT32 media.              }
  372.     DirSector          : Word;  { First sector for the root directory.         }
  373.                                 { Field is undefined for FAT32 drives.         }
  374.     Reserved2          : DWord;
  375.     MediaID            : Byte;  { Media descriptor for the drive.              }
  376.     Reserved           : Byte;
  377.     Reserved3          : DWord;
  378.     NextFree           : Word;  { Most recently allocated cluster. Cluster at  }
  379.                                 { which to start search for free clusters.     }
  380.     ExtFreeCount       : DWord; { Number of free clusters on the drive.        }
  381.                                 { FFFFFFFF if the number is unknown.           }
  382.     ExtFlags           : Word;  { Flags describing the drive:                  }
  383.                                 { bits 0-3: 0-based number of active FAT       }
  384.                                 { bits 4-6: reserved                           }
  385.                                 { bit 7: FAT mirroring enabled if bit cleared  }
  386.                                 { bits 8-15: reserved                          }
  387.     ExtFSInfoSec       : Word;  { Sector containing information about the file }
  388.                                 { system in TBifFATBootFSInfo structure.       }
  389.                                 { This field is set to 0FFFFh if there is no   }
  390.                                 { FileSysInfo sector. Otherwise, this value    }
  391.                                 { must be non-zero and less than the reserved  }
  392.                                 { sector count.                                }
  393.     ExtBkUpBootSec     : Word;  { Sector containing the backup boot sector.    }
  394.                                 { This field is set to 0FFFFh if there is no   }
  395.                                 { backup boot sector. Otherwise, this value    }
  396.                                 { must be non-zero and less than the reserved  }
  397.                                 { sector count.                                }
  398.     ExtFirstSector     : DWord; { First sector of the first cluster.           }
  399.     ExtMaxCluster      : DWord; { Number of clusters on drive plus 1.          }
  400.     ExtFATSize         : DWord; { Number of sectors occupied by each FAT.      }
  401.     ExtRootCluster     : DWord; { First cluster in the root directory.         }
  402.     ExtNextFree        : DWord; { Most recently allocated cluster. Cluster at  }
  403.                                 { which to start search for free clusters.     }
  404.   end;
  405.  
  406.   PBPB = ^TBPB;
  407.   TBPB = packed record { BIOS Parameter Block for FAT12 and FAT16: }
  408.     BytesPerSector     : Word;  { Number of bytes per sector.                  }
  409.     SectorsPerCluster  : Byte;  { Number of sectors per cluster.               }
  410.     ReservedSectors    : Word;  { Number of reserved sectors.                  }
  411.     NumberOfFATs       : Byte;  { Number of File Allocation Tables.            }
  412.     RootDirEntries     : Word;  { Number of entries in root directory.         }
  413.     SectorsOnDrive     : Word;  { Number of sectors on the drive or partition. }
  414.     MediaDescriptor    : Byte;  { Media descriptor.                            }
  415.     SectorsPerFAT      : Word;  { Number of sectors per FAT.                   }
  416.     SectorsPerTrack    : Word;  { Number of sectors per track.                 }
  417.     NumberOfHeads      : Word;  { Number of heads on the drive.                }
  418.     HiddenSectors      : DWord; { Number of hidden sectors on the drive.       }
  419.     BigSectorsOnDrive  : DWord; { Number of sectors if SectorsOnDrive=0.       }
  420.   end;
  421.  
  422.   PExtBPB = ^TExtBPB;
  423.   TExtBPB = packed record { Extended BIOS Parameter Block for FAT32: }
  424.     BytesPerSector     : Word;  { Number of bytes per sector.                  }
  425.     SectorsPerCluster  : Byte;  { Number of sectors per cluster.               }
  426.     ReservedSectors    : Word;  { Number of reserved sectors.                  }
  427.     NumberOfFATs       : Byte;  { Number of File Allocation Tables.            }
  428.     RootDirEntries     : Word;  { Number of entries in root directory.         }
  429.                                 { Ignored on FAT32 drives.                     }
  430.     SectorsOnDrive     : Word;  { Number of sectorson the drive or partition.  }
  431.     MediaDescriptor    : Byte;  { Media descriptor.                            }
  432.     SectorsPerFAT      : Word;  { Number of sectors per FAT.                   }
  433.                                 { This field will be zero in a FAT32 BPB.      }
  434.                                 { Use BigSectorsPerFat for FAT32 media.        }
  435.     SectorsPerTrack    : Word;  { Number of sectors per track.                 }
  436.     NumberOfHeads      : Word;  { Number of heads on the drive.                }
  437.     HiddenSectors      : DWord; { Number of hidden sectors on the drive.       }
  438.     BigSectorsOnDrive  : DWord; { Number of sectors if SectorsOnDrive=0.       }
  439.     BigSectorsPerFat   : DWord; { Number of sectors per FAT on FAT32 drive.    }
  440.     ExtFlags           : Word;  { Flags describing the drive:                  }
  441.                                 { bits 0-3: 0-based number of active FAT       }
  442.                                 { bits 4-6: reserved                           }
  443.                                 { bit 7: FAT mirroring enabled if bit cleared  }
  444.                                 { bits 8-15: reserved                          }
  445.     FileSysVersion     : Word;  { File system version of the FAT32 drive:      }
  446.                                 { high byte: major version.                    }
  447.                                 { low byte: minor version.                     }
  448.     RootDirStartCluster: DWord; { First cluster of root directory on FAT32     }
  449.                                 { drive.                                       }
  450.     FileSysInfoSector  : Word;  { Sector containing information about the file }
  451.                                 { system in TBifFATBootFSInfo structure.       }
  452.                                 { This field is set to FFFFh if there is no    }
  453.                                 { FileSysInfo sector. Otherwise, this value    }
  454.                                 { must be non-zero and less than the reserved  }
  455.                                 { sector count.                                }
  456.     BackupBootSector   : Word;  { Sector containing the backup boot sector.    }
  457.                                 { This field is set to FFFFh if there is no    }
  458.                                 { backup boot sector. Otherwise, this value    }
  459.                                 { must be non-zero and less than the reserved  }
  460.                                 { sector count.                                }
  461.     Reserved           : array[0..5] of Word;
  462.   end;
  463.  
  464.   PBigFATBootInfo = ^TBigFATBootInfo;
  465.   TBigFATBootInfo = packed record
  466.     Signature          : DWord; { Signature of FileSysInfo sector, 61417272h.  }
  467.     FreeClustersCount  : DWord; { Number of free clusters on drive,            }
  468.                                 { FFFFFFFF if the number is unknown.           }
  469.     NextFreeCluster    : DWord; { Most recently allocated cluster.             }
  470.     Reserved           : array[0..5] of Word;
  471.   end;
  472.  
  473. {- Device Parameters ----------------------------------------------------------}
  474.  
  475.   PSectorEntry = ^TSectorEntry;
  476.   TSectorEntry = packed record { Sector entry for SectorTable: }
  477.     SectorNumber: Word;
  478.     SectorSize  : Word;
  479.   end;
  480.  
  481.   PDeviceParameters = ^TDeviceParameters;
  482.   TDeviceParameters = packed record { Device Parameters for FAT12 and FAT16: }
  483.     SpecialFunctions   : Byte; { Special functions:                            }
  484.                                { bit 0 set to use current BPB                  }
  485.                                {       clear to use BPB in this structure      }
  486.                                { bit 1 set to use track layout field only      }
  487.                                {       must be clear for get function          }
  488.                                { bit 2 set if all sectors has the same size    }
  489.                                {       (should be set)                         }
  490.                                { bit 3-7 reserved                              }
  491.     DeviceType         : Byte; { Device type:                                  }
  492.                                { 00h = 5.25" 320Kb/360Kb disk                  }
  493.                                { 01h = 5.25" 1.2Mb disk                        }
  494.                                { 02h = 3.5" 720Kb disk                         }
  495.                                { 03h = 8" low-density disk                     }
  496.                                { 04h = 8" high-density disk                    }
  497.                                { 05h = hard disk                               }
  498.                                { 06h = tape drive                              }
  499.                                { 07h = 3.5" 1.44Mb disk                        }
  500.                                { 08h = optical disk                            }
  501.                                { 09h = 3.5" 2.88Mb disk                        }
  502.     DeviceAttributes   : Word; { Device attributes:                            }
  503.                                { bit 0 set if nonremovable media               }
  504.                                { bit 1 set if door lock supported              }
  505.                                { bit 2-15 reserved                             }
  506.     Cylinders          : Word; { Number of cylinders                           }
  507.     MediaType          : Byte; { Media type:                                   }
  508.                                { for 1.2Mb drive:                              }
  509.                                {   00h=1.2Mb disk                              }
  510.                                {   01h=320Kb/360Kb disk                        }
  511.                                { always 00h for other drive types              }
  512.     BPB                : TBPB; { 31 bytes reserved for BPB                     }
  513.     Fill31Bytes        : array[1..31-SizeOf(TBPB)] of Byte; { fill up 31 bytes }
  514.     EntriesInTable     : Word; { Number of entries in SectorTable. Should be   }
  515.                                { equal to SectorsPerTrack. (Not used by the    }
  516.                                { get function.)                                }
  517.     SectorTable        : array[0..0] of TSectorEntry; { When planing to use a  }
  518.                                { device parameters structure with calls to set }
  519.                                { function, one should allocate memory for this }
  520.                                { structure (SizeOf(TDeviceParameters)) +       }
  521.                                { SizeOf(TSectoryEntry) * SectorsPerTrack.      }
  522.   end;
  523.  
  524.   PExtDeviceParameters = ^TExtDeviceParameters;
  525.   TExtDeviceParameters = packed record { Extended Device Parameters for FAT32: }
  526.     SpecialFunctions   : Byte; { Special functions:                            }
  527.                                { bit 0 set to use current BPB                  }
  528.                                {       clear to use BPB in this structure      }
  529.                                { bit 1 set to use track layout field only      }
  530.                                {       must be clear for get function          }
  531.                                { bit 2 set if all sectors has the same size    }
  532.                                {       (should be set)                         }
  533.                                { bit 3-7 reserved                              }
  534.     DeviceType         : Byte; { Device type:                                  }
  535.                                { 00h = 5.25" 320Kb/360Kb disk                  }
  536.                                { 01h = 5.25" 1.2Mb disk                        }
  537.                                { 02h = 3.5" 720Kb disk                         }
  538.                                { 03h = 8" low-density disk                     }
  539.                                { 04h = 8" high-density disk                    }
  540.                                { 05h = hard disk                               }
  541.                                { 06h = tape drive                              }
  542.                                { 07h = 3.5" 1.44Mb disk                        }
  543.                                { 08h = optical disk                            }
  544.                                { 09h = 3.5" 2.88Mb disk                        }
  545.     DeviceAttributes   : Word; { Device attributes:                            }
  546.                                { bit 0 set if nonremovable media               }
  547.                                { bit 1 set if door lock supported              }
  548.                                { bit 2-15 reserved                             }
  549.     Cylinders          : Word; { Number of cylinders                           }
  550.     MediaType          : Byte; { Media type:                                   }
  551.                                { for 1.2Mb drive:                              }
  552.                                {   00h=1.2Mb disk                              }
  553.                                {   01h=320Kb/360Kb disk                        }
  554.                                { always 00h for other drive types              }
  555.     BPB                : TExtBPB; { ExtBPB for FAT32                           }
  556.     Reserved           : array[0..31] of Byte;
  557.     EntriesInTable     : Word; { Number of entries in SectorTable. Should be   }
  558.                                { equal to SectorsPerTrack. (Not used by the    }
  559.                                { get function.)                                }
  560.     SectorTable        : array[0..0] of TSectorEntry; { When planing to use a  }
  561.                                { device parameters structure with calls to set }
  562.                                { function, one should allocate memory for this }
  563.                                { structure (SizeOf(TFAT32DeviceParameters)) +  }
  564.                                { SizeOf(TSectoryEntry) * SectorsPerTrack.      }
  565.   end;
  566.  
  567. function  GetDeviceParameters(Drive: Byte; Buffer: Pointer; Size: Word): Boolean;
  568.           { Returnes device parameters for a drive. The device parameters are  }
  569.           { returned in the buffer pointet to by Buffer. The buffer should be  }
  570.           { able to hold a TExtDeviceParameters structure. The size of the     }
  571.           { structure wanted must be given in the Size parameter to identify   }
  572.           { for the function which structure (TDeviceParameters or TExtDevice- }
  573.           { Parameters) is wanted on return. If the function failes geting a   }
  574.           { FAT32 device parameters structure it will get a FAT12/16 structure }
  575.           { In any case it will convert the structure it gets to the structure }
  576.           { that are wanted in the buffer on return.                           }
  577. function  SetDeviceParameters(Drive: Byte; Buffer: Pointer; Size: Word): Boolean;
  578.           { Sets the device parameters for a drive. The buffer pointed to by   }
  579.           { Buffer should hold a correct device parameters structure for the   }
  580.           { current file system (FAT12/16 or FAT32). The size of the structure }
  581.           { must be given in the Size parameter to identify for the function   }
  582.           { which structure (TDeviceParameters or TExtDeviceParameters) is     }
  583.           { pased in the buffer. If the function failes seting a FAT32 device  }
  584.           { parameters structure it will convert to a FAT12/16 structure and   }
  585.           { try to set that. This will not affect the original structure in    }
  586.           { the buffer.                                                        }
  587.  
  588. { Even though these two functions can take and return either FAT12/16 or FAT32 }
  589. { device parameter (intentifying the actual structure by the Size parameter)   }
  590. { it will be wise not to use the FAT12/16 structure, but to only implement the }
  591. { FAT32 structure. For these two functions the FAT32 structure will work fine  }
  592. { on FAT12/16 drives as well as for FAT32. However, the FAT12/16 structure will}
  593. { not be appropriate for working with FAT32 drives. By usin the FAT32 structure}
  594. { in any case there will be no need to match the device parameter structure to }
  595. { the different drives because the functions will temporarily convert a FAT32  }
  596. { structure to FAT12/16 if needed.                                             }
  597.  
  598.  
  599. {- Cylinders, Heads, Sectors --------------------------------------------------}
  600. {                                                                              }
  601. { Sectors are the smallest accessable units on a disk drive, and (usually) are }
  602. { 512 bytes in size. Sectors are organized on a drive in a matrix of cylinders,}
  603. { heads, and sectors. The cylinder/head/sector (CHS) values are referred to as }
  604. { a drive's geometry. Hard disks are made up of several disk plates stacked on }
  605. { top of each other, with tracks defined as concentric circles on both sides   }
  606. { of each plate. The read/write heads are part of an assembly with one head    }
  607. { for each side of each platter. In the CHS system, cylinder refers to the set }
  608. { of tracks for all the plates that line up on top of each other, head refers  }
  609. { to a side of a platter, and a sector is a 512 bytes portion of a track.      }
  610. { The cylinders on a drive is numbered from 0 and up, heads are numbered from  }
  611. { 0 and up, and sectors on each track are numbered from 1 and up.              }
  612.  
  613. { Logical sectors are numbered sequentially from cylinder 0 and up, head 0 and }
  614. { up. Sector 1 on head 0, cylinder 0 is the first logical sector (sector 0) on }
  615. { the drive, and sector 2 on the same head and cylinder is the second logical  }
  616. { sector (sector 1). The formula for calculating logical sector numbers are:   }
  617. {     Cylinder * (BPB.NumberOfHeads * BPB.SectorsPerTrack)                     }
  618. {   + Head * BPB.SectorsPerTrack                                               }
  619. {   + Sector - 1 (-1 because logical sectors on a drive are 0-based)           }
  620.  
  621.  
  622. {- Direct Drive Access --------------------------------------------------------}
  623.  
  624. { Windows 95 OSR2 has a bug that affects interrupt 21h function 440Dh code 61h }
  625. { (read track) and code 41h (write track). The function succeed but no data is }
  626. { read or written. Both functions work on the retail version of Windows 95.    }
  627. { Solutions: (1) Use interrupt 25h and 26h to read and write logical sectors.  }
  628. {                This works on FAT12 and FAT16, but is not compatible with     }
  629. {                FAT32.                                                        }
  630. {            (2) Use interrupt 21h function 7305h to read and write logical    }
  631. {                sectors. This method works on FAT12, FAT16, and FAT32, but    }
  632. {                is only supported on Windows 95 OSR2 and later.               }
  633.  
  634. function  ReadTrack(Drive: Byte; Cylinder,Head,Sector,Count: Word; Buffer: Pointer): Boolean;
  635.           { Reads Count number of sectors from the drive into the buffer. On   }
  636.           { Windows 95 OSR2 this function will return successful but no data   }
  637.           { will be read.                                                      }
  638. function  WriteTrack(Drive: Byte; Cylinder,Head,Sector,Count: Word; Buffer: Pointer): Boolean;
  639.           { Writes Count number of sectors from the buffer onto the drive. On  }
  640.           { Windows 95 OSR2 this function will return successful but no data   }
  641.           { will be writen.                                                    }
  642. function  FormatTrack(Drive: Byte; Cylinder,Head: Word): Boolean;
  643.           { Formats and verifies a track on the drive.                         }
  644. function  VerifyTrack(Drive: Byte; Cylinder,Head: Word): Boolean;
  645.           { Verifies a track on the drive.                                     }
  646.  
  647. const
  648.   { Write modes for WriteSector: }
  649.   WRITE_MODE_UNSPECIFIED_DATA = $0000; { Other/unknown }
  650.   WRITE_MODE_FAT_DATA         = $1000; { FAT data }
  651.   WRITE_MODE_DIRECTORY_DATA   = $2000; { Directory data }
  652.   WRITE_MODE_NORMAL_FILE_DATA = $3000; { Normal file data }
  653.  
  654. function  ReadSector(Drive: Byte; Sector: DWord; Count: Word; Buffer: Pointer): Boolean;
  655.           { Reads Count number of logical sectors from the drive into the      }
  656.           { buffer. The Sector parameter gives the sector number (0 beeing the }
  657.           { first sector on a drive) to start reading from. The buffer must be }
  658.           { able to hold BytesPerSector*Count number of bytes. On Windows 95   }
  659.           { OSR2 and later this function uses interrupt 21h function 7305h.    }
  660. function  WriteSector(Drive: Byte; Sector: DWord; Count: Word; Buffer: Pointer;  Mode: Byte): Boolean;
  661.           { Write Count number of logical sectors from the buffer onto the     }
  662.           { drive. On Windows 95 OSR2 and later this function uses interrupt   }
  663.           { 21h function 7305h. The mode (one of the write modes) is needed in }
  664.           { Windows 95 OSR2 and and later only. This provides information to   }
  665.           { applications (like compression drivers) so that they can write     }
  666.           { data properly based upon the data type specified.                  }
  667.  
  668.  
  669. {- Master Boot Record ---------------------------------------------------------}
  670.  
  671. { The Master Boot Record (MBR) is the first physical sector of a hard disk,    }
  672. { and always contains a partition table. This partition table is 64 bytes long }
  673. { and is followed by a two-byte signature (55AAh), which indicates the end of  }
  674. { the MBR. The 64-byte partition table and the 2-byte signature occupies the   }
  675. { last 66 bytes of the sector.                                                 }
  676.  
  677. type
  678.   PPartitionEntry = ^TPartitionEntry;
  679.   TPartitionEntry = packed record
  680.     BootIndicator      : Byte;  { Boot indicator:                              }
  681.                                 { 80h = active/bootable                        }
  682.                                 { 00h = nonactive/non-bootable                 }
  683.     StartHead          : Byte;  { Starting head of partition.                  }
  684.     StartCylinderSector: Word;  { Starting cylinder and sector of partition:   }
  685.                                 { 10 bits for cylinder, 6 bits for sector.     }
  686.                                 { bits 0-5  6 bits of sector                   }
  687.                                 { bits 6-7  2 high bits of cylinder            }
  688.                                 { bits 8-15 8 low bits of cylinder             }
  689.  
  690.     { Partitions usually start on sector 1, head 0, except the first partition }
  691.     { after the master boot record which may start in sector 2.                }
  692.  
  693.     PartitionType      : Byte;  { Partition type (system flag/indicator):      }
  694.                                 { 00h = unused partition table entry           }
  695.                                 { 01h = FAT12 primary partition <16Mb          }
  696.                                 { 02h = XENIX                                  }
  697.                                 { 04h = FAT16 primary partition 16-32Mb        }
  698.                                 { 05h = FAT12/16 extended partition            }
  699.                                 { 06h = FAT16 primary partition >32Mb          }
  700.                                 { 07h = HPFS, NTFS, Unix, other                }
  701.                                 { 0Ah = OS/2 boot manager                      }
  702.                                 { 0Bh = FAT32                                  }
  703.                                 { 0Ch = FAT32 LBA (ext int 13h required)       }
  704.                                 { 0Eh = FAT16 LBA (ext int 13h required)       }
  705.                                 { 0Fh = FAT16 LBA ext (ext int 13h required)   }
  706.                                 { 64h = Novell                                 }
  707.                                 { 75h = PCIX                                   }
  708.                                 { 83h = Linux EXT2                             }
  709.                                 { A5h = FreeBSD, NetBSD, 386BSD                }
  710.                                 { DBh = CP/M                                   }
  711.                                 { FFh = BBT                                    }
  712.     EndHead            : Byte;  { Ending head of partition.                    }
  713.     EndCylinderSector  : Word;  { Ending cylinder and sector of partition:     }
  714.                                 { 10 bits for cylinder, 6 bits for sector.     }
  715.     SectorOffset       : DWord; { Relative sector offset of partition.         }
  716.                                 { (Number of sectors preceding partition.)     }
  717.     NumberOfSectors    : DWord; { Number of sectors in partition.              }
  718.   end;
  719.  
  720.   PPartitionTable = ^TPartitionTable;
  721.   TPartitionTable = array[1..4] of TPartitionEntry;
  722.  
  723.   PMBR = ^TMBR;
  724.   TMBR = packed record { Master Boot Record: }
  725.     { The first portion (446 bytes on disks with 512 bytes per sector) of a    }
  726.     { master boot record, preceding the partition table and two-byte signature }
  727.     { is occupied by executable bootup code.                                   }
  728.     BootCode           : array[0..445] of Byte; { Bootup program code.         }
  729.  
  730.     PartitionTable     : TPartitionTable; { Partition table occupying the last }
  731.                                           { 64 bytes preceding the two-byte    }
  732.                                           { signature (55h AAh).               }
  733.  
  734.     { The last two bytes in a boot record containes a two-byte signature, and  }
  735.     { must always have the values: 55h AAh                                     }
  736.     SectorSignature    : Word;
  737.   end;
  738.  
  739. {- File System Boot Record ----------------------------------------------------}
  740.  
  741.   PFSBR = ^TFSBR;
  742.   TFSBR = packed record { File System Boot Record for FAT12 and FAT16: }
  743.     BootJump           : array[0..2] of Byte; { Jump instruction to boot code. }
  744.     OEMName            : array[0..7] of Char; { System that formated the drive.}
  745.     BPB                : TBPB;  { BPB for FAT12 and FAT16.                     }
  746.     PhysicalDrive      : Byte;  { Number of physical drive.                    }
  747.     Reserved           : Byte;
  748.     BootSignature      : Byte;  { Boot record signature, usually 29h.          }
  749.     VolumeSerial       : DWord; { Volume serial number.                        }
  750.     VolumeLabel        : array[0..10] of Char; { Volume label.                 }
  751.     SystemType         : array[0..7] of Char; { 'FAT12   ' or 'FAT16   '       }
  752.  
  753.     { The portion of a boot record following the extended BIOS parameter block }
  754.     { (448 bytes on disks with 512 bytes per sector) is occupied by executable }
  755.     { boot code.                                                               }
  756.     BootCode           : array[0..447] of Byte; { Bootup program code.         }
  757.  
  758.     { The last two bytes in a boot record containes a two-byte signature, and  }
  759.     { must always have the values: 55h AAh                                     }
  760.     SectorSignature    : Word;
  761.   end;
  762.  
  763.   PExtFSBR = ^TExtFSBR;
  764.   TExtFSBR = packed record { Extended File System Boot Record for FAT32: }
  765.     BootJump           : array[0..2] of Byte; { Jump instruction to boot code. }
  766.     OEMName            : array[0..7] of Char; { System that formated the drive.}
  767.     BPB                : TExtBPB; { ExtBPB for FAT32.                          }
  768.     PhysicalDrive      : Byte;  { Number of physical drive.                    }
  769.     Reserved           : Byte;
  770.     BootSignature      : Byte;  { Boot record signature, usually 29h.          }
  771.     VolumeSerial       : DWord; { Volume serial number.                        }
  772.     VolumeLabel        : array[0..10] of Char; { Volume label.                 }
  773.     SystemType         : array[0..7] of Char; { 'FAT32   '                     }
  774.  
  775.     { The portion of a boot record following the extended BIOS parameter block }
  776.     { (420 bytes on disks with 512 bytes per sector) is occupied by executable }
  777.     { boot code.                                                               }
  778.     BootCode           : array[0..419] of Byte; { Bootup program code.         }
  779.  
  780.     { The last two bytes in any boot record always have the values: 55h AAh.   }
  781.     SectorSignature    : Word;
  782.   end;
  783.  
  784.  
  785. {- File Allocation Table ------------------------------------------------------}
  786.  
  787. { Although sectors are the smallest addressable units on a disk, the data area }
  788. { (the area used to store files and directories, opposed to the system area    }
  789. { where the boot record and FATs are stored) are organiced into clusters. A    }
  790. { clusters (or allocation units) occupy several sectors grouped together. The  }
  791. { number of sectors for each cluster depends on the partition, and is given in }
  792. { BPB.SectorsPerCluster.                                                       }
  793.  
  794. { The File Allocation Table (FAT) is used to map each cluster in the data eara }
  795. { and will have one entry for each cluster on the drive. Thuse it is possible  }
  796. { to keep track of clusters allocated to each files and directory. The size of }
  797. { the entries in the FAT depends on the FAT-type: FAT12 uses 12-bit entries,   }
  798. { FAT16 uses 16-bit entries, and FAT32 uses 32-bit entries. Entries in a FAT   }
  799. { are indexed from 0 and up. Because the first two entries are reserved, entry }
  800. { cluster 2 (index 2 in the FAT) is the first data cluster on a drive. The     }
  801. { first byte in a FAT must always clontain a copy of the media desriptor byte  }
  802. { (BPB.MediaDescriptor), and the remaining bytes for the first and second FAT  }
  803. { entries (index 0 and 1) must be filled with FFh.                             }
  804.  
  805. { Each entry in a FAT is an integer value. The values [FFFF]F]FF0-[FFFF]F]FFF  }
  806. { are reserved. [FFFF]F]FF7 indicates a bad cluster. [FFFF]F]FFF indicates the }
  807. { end of cluster chain. Values from [FFFF]F]FF8-[FFFF]F]FFFF may also be used  }
  808. { to indicate end of cluster chain. The value [0000]0]000 indicates an unused  }
  809. { cluster. All other value will represent the next cluster in a cluster chain. }
  810.  
  811.  
  812. {- Directory Entries ----------------------------------------------------------}
  813.  
  814.   PDirEntry = ^TDirEntry;
  815.   TDirEntry = packed record
  816.     Name               : array[0..7] of Char; { 8 character name.              }
  817.                          { first byte: 00h = entry never used                  }
  818.                          {             05h = first character of name is E5h    }
  819.                          {             E5h = entry has been deleted            }
  820.                          {             2Eh = subdirectory entry                }
  821.     Extention          : array[0..2] of Char; { 3 character extention.         }
  822.     Attributes         : Byte;  { Bits: 0 = read-only                          }
  823.                                 {       1 = hidden                             }
  824.                                 {       2 = system                             }
  825.                                 {       3 = volume label (Name+Ext=11 label)   }
  826.                                 {       4 = directory                          }
  827.                                 {       5 = archive                            }
  828.     Reserved           : array[0..9] of Char;
  829.     CreationTime       : Word;  { Bits:  0-4  = seconds/2 (0-29)               }
  830.                                 {        5-10 = minutes (0-59)                 }
  831.                                 {       11-15 = hour (0-23)                    }
  832.     CreationDate       : Word;  { Bits:  0-4  = day (0-31)                     }
  833.                                 {        5-8  = month (1-12)                   }
  834.                                 {        9-15 = year-1980                      }
  835.     FirstCluster       : Word;  { First cluster of the file/directory.         }
  836.     FileSize           : DWord; { Size of a file.                              }
  837.   end;
  838.  
  839.   PLongNameDirEntry = ^TLongNameDirEntry;
  840.   TLongNameDirEntry = packed record
  841.     Sequence           : Byte; { Number in the chain of directory entries for  }
  842.                                { this name, 01h,02h, ... 4xh (last entry will  }
  843.                                { have bit 6 set to indicate end of chaine).    }
  844.     Name               : array[0..4] of WideChar; { Charachters for long name. }
  845.     Attributes         : Byte; { OFh (00001111b) a directory entry has the     }
  846.                                { attributes read-only, hidden, system, and     }
  847.                                { volume label set to indicate a long name.     }
  848.     EntryType          : Byte; { 00h                                           }
  849.     Checksum           : Byte; { Checksum for matching short (DOS) name.       }
  850.     Name2              : array[0..5] of WideChar; { Charachters for long name. }
  851.     Reserved           : Word;
  852.     Name3              : array[0..1] of WideChar; { Charachters for long name. }
  853.   end;
  854.  
  855.   PVolumeLabelDirEntry = ^TVolumeLabelDirEntry;
  856.   TVolumeLabelDirEntry = packed record
  857.     VolumeLabel        : array[0..10] of Char; { 11 character volume label.    }
  858.     Attributes         : Byte;  { 00001000b (volume label attribute set)       }
  859.     Reserved           : array[0..9] of Byte;
  860.     CreationTime       : Word;
  861.     CreationDate       : Word;
  862.     Unused             : array[0..5] of Byte;
  863.   end;
  864.  
  865.  
  866. {------------------------------------------------------------------------------}
  867.  
  868. function  GetFirstCluster(Path: String; var Cluster: DWord): Boolean;
  869.           { Retrives the first cluster of a file or directory. Caller must     }
  870.           { a level 3 lock on the drive. It is the callers resposibility to    }
  871.           { check that the returned cluster number is valid.                   }
  872.  
  873. function  MakeSerialNumber: DWord;
  874.           { Generates a volume serial number using the current date and time.  }
  875.           { The current system date and time is converted into DOS date and    }
  876.           { DOS time, with date in the high word and time in the low word.     }
  877.  
  878.  
  879. {------------------------------------------------------------------------------}
  880.  
  881. { Most functions have a boolean return value to indicate success or failiour.  }
  882. { If a function failes an error code in the variable VWIN32Error, and when it  }
  883. { succedes VWIN32Error will be zero.                                           }
  884.  
  885. var
  886.   VWIN32Error: DWord;
  887.  
  888. const
  889.   ERROR_NON                  = $0000; { no error                               }
  890.  
  891.   { MS-DOS/Windows error codes: }
  892.   ERROR_INVALID_FUNCTION     = $0001; { invalid function number                }
  893.   ERROR_FILE_NOT_FOUND       = $0002; { file not found                         }
  894.   ERROR_ACCESS_DENIED        = $0005; { specified access denied on drive       }
  895.   ERROR_INVALID_DRIVE        = $000F; { invalid drive number                   }
  896.   ERROR_MEDIA_NOT_LOCKED     = $00B0; { media is not locked in drive           }
  897.   ERROR_MEDIA_LOCKED         = $00B1; { media is locked in drive               }
  898.   ERROR_MEDIA_NOT_REMOVABLE  = $00B2; { media is not removable                 }
  899.   ERROR_LOCKE_COUNT_EXCEEDED = $00B4; { media locke count exceeded             }
  900.   ERROR_EJECT_REQUEST_FAILED = $00B5; { valid media eject request failed       }
  901.  
  902.   { Interrupt 13h/25h/26h error codes: }
  903.   ERROR_BAD_COMMAND          = $10001; { bad command                           }
  904.   ERROR_BAD_ADDRESS_MARK     = $10002; { bad address mark                      }
  905.   ERROR_WRITE_PROTECTED      = $10003; { write-protected disk                  }
  906.   ERROR_SECTOR_NOT_FOUND     = $10004; { requested sector not found            }
  907.   ERROR_RESET_FAILED         = $10005; { reset failed                          }
  908.   ERROR_DISK_CHANGED         = $10006; { disk changed (floppy disk)            }
  909.   ERROR_PARAMETER_FAILED     = $10007; { drive parameter activity failed       }
  910.   ERROR_DMA_FAILURE          = $10008; { DMA failure/overrun                   }
  911.   ERROR_DMA_SEGMENT_FAULT    = $10009; { attempted DMA across 64K boundary     }
  912.   ERROR_BAD_SECTOR_DETECTED  = $1000A; { bad sector detected                   }
  913.   ERROR_BAD_TRACK_DETECTED   = $1000B; { bad track detected                    }
  914.   ERROR_INVALID_MEDIA        = $1000C; { invalid media or unsupported track    }
  915.   ERROR_INVALID_SECTORS      = $1000D; { invalid number of sectors on format   }
  916.   ERROR_CONTROL_DATA         = $1000E; { control data address mark detected    }
  917.   ERROR_DMA_ARBITRATION      = $1000F; { DMA arbitration level out of range    }
  918.   ERROR_DATA_ERROR           = $10010; { data error (uncorrectable CRC or ECC) }
  919.   ERROR_DATA_ECC_CORRECTED   = $10011; { data ECC corrected                    }
  920.   ERROR_CONTROLLER_FAILED    = $10020; { controller failed                     }
  921.   ERROR_SEEK_FAILED          = $10040; { seek operation failed                 }
  922.   ERROR_DEVICE_FAILED        = $10080; { device failed to respond (timeout)    }
  923.   ERROR_DRIVE_NOT_READY      = $100AA; { drive not ready                       }
  924.   ERROR_UNDEFINED            = $100BB; { undefined error                       }
  925.   ERROR_WRITE_FAULT          = $100CC; { write fault                           }
  926.   ERROR_STATUS_REGISTER      = $100E0; { status register error                 }
  927.   ERROR_SENSE_FAILED         = $100FF; { sense operation failed                }
  928.  
  929.   { VWIN32 custom error codes: }
  930.   ERROR_UNKNOWN              = $00100000; { unknown error                      }
  931.   ERROR_OS_NOT_SUPPORTED     = $00200000; { OS version not supported           }
  932.   ERROR_OPENING_DEVICE       = $00300000; { error trying to open device        }
  933.  
  934. {==============================================================================}
  935. implementation
  936.  
  937. var
  938.   VWIN32Device : THandle;
  939.   OSVersionInfo: TOSVersionInfo;
  940.  
  941. function VWIN32DIOC;
  942. var
  943.   BytesReturned : DWord;
  944.  
  945.   function OpenDevice: Boolean;
  946.   begin
  947.     VWIN32Error := ERROR_NON;
  948.     if VWIN32Device = INVALID_HANDLE_VALUE then begin
  949.       if WindowsVersion(0,0,0,VER_PLATFORM_WIN32_WINDOWS) then begin {supports only Win9x}
  950.         VWIN32Device := CreateFile(VWIN32_DEVICE_NAME,0,0,nil,0,FILE_FLAG_DELETE_ON_CLOSE,0);
  951.         if VWIN32Device = INVALID_HANDLE_VALUE then VWIN32Error := ERROR_OPENING_DEVICE;
  952.       end
  953.       else VWIN32Error := ERROR_OS_NOT_SUPPORTED;
  954.     end;
  955.     Result := VWIN32Error = ERROR_NON;
  956.   end;
  957.  
  958.   procedure CloseDevice;
  959.   begin
  960.     if VWIN32Device <> INVALID_HANDLE_VALUE then CloseHandle(VWIN32Device);
  961.     VWIN32Device := INVALID_HANDLE_VALUE;
  962.     Result := true;
  963.   end;
  964.  
  965. begin
  966.   VWIN32Error := ERROR_NON;
  967.   if ControlCode = VWIN32_DIOC_CLOSE then CloseDevice
  968.   else if OpenDevice then begin
  969.     Result := DeviceIoControl(VWIN32Device,ControlCode,Registers,SizeOf(Registers^),
  970.                               Registers,SizeOf(Registers^),BytesReturned,nil);
  971.     if not result then VWIN32Error := ERROR_UNKNOWN;
  972.   end
  973.   else Result := false;
  974. end;
  975.  
  976. function WindowsVersion;
  977. begin
  978.   with OSVersionInfo do
  979.     Result := (dwMajorVersion >= Major) and
  980.               (dwMinorVersion >= Minor) and
  981.               (Word(dwBuildNumber) >= Word(Build)) and
  982.               (dwPlatformID = Platform);
  983. end;
  984.  
  985. { The device category pased as parameter to most of the following functions    }
  986. { is used to specifie FAT32, FAT16 or FAT12 drives: 08h = FAT16 or FAT12 drive,}
  987. { 48h = FAT32, FAT16 or FAT12 drive. The 48h value is supported on Windows 95  }
  988. { OSR2 and later only. Because function calls may be implemented in the device }
  989. { driver, the 48h form of a call may fail on FAT16 or FAT12 media. The caller  }
  990. { must fall back on the 08h form if the 48h form call fails. Therefore, the    }
  991. { folowing functions first makes a 48h form call, but only on Windows 95 OSR2  }
  992. { and later, and then a 08h form call if the 48h form call failed.             }
  993.  
  994. function DriveIsRemovable;
  995. { int 21h, func 4408h                               }
  996. { in  AX = 4408h                                    }
  997. {     BL = drive number                             }
  998. { out CF set on error                               }
  999. {     AX = status                                   }
  1000. { out CF clear if successful                        }
  1001. {     AX = 0000h=removable 0001h=fixed              }
  1002. var
  1003.   Registers: TDIOC_Registers;
  1004. begin
  1005.   VWIN32Error := ERROR_NON;
  1006.   Result := false;
  1007.   with Registers do begin
  1008.     EAX := $4408;
  1009.     EBX := Drive;
  1010.     Flags := $00000000;
  1011.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1012.       if (Flags and FLAG_CARRY) = 0 then Result := (AX and $0001) = 0
  1013.       else VWIN32Error := AX;
  1014.     end;
  1015.   end;
  1016. end;
  1017.  
  1018. function DriveIsRemote;
  1019. { int 21h, func 4409h                               }
  1020. { in  AX = 4409h                                    }
  1021. {     BL = drive number                             }
  1022. { out CF set on error                               }
  1023. {     AX = status                                   }
  1024. { out CF clear if successful                        }
  1025. {     DX = device attribute                         }
  1026. var
  1027.   Registers: TDIOC_Registers;
  1028. begin
  1029.   VWIN32Error := ERROR_NON;
  1030.   Result := false;
  1031.   with Registers do begin
  1032.     EAX := $4409;
  1033.     EBX := Drive;
  1034.     Flags := $00000000;
  1035.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1036.       if (Flags and FLAG_CARRY) = 0 then Result := (DX and $1000) > 0
  1037.       else VWIN32Error := AX;
  1038.     end;
  1039.   end;
  1040. end;
  1041.  
  1042. function DriveIsSubstitute;
  1043. { int 21h, func 4409h                               }
  1044. { in  AX = 4409h                                    }
  1045. {     BL = drive number                             }
  1046. { out CF set on error                               }
  1047. {     AX = status                                   }
  1048. { out CF clear if successful                        }
  1049. {     DX = device attribute                         }
  1050. var
  1051.   Registers: TDIOC_Registers;
  1052. begin
  1053.   VWIN32Error := ERROR_NON;
  1054.   Result := false;
  1055.   with Registers do begin
  1056.     EAX := $4409;
  1057.     EBX := Drive;
  1058.     Flags := $00000000;
  1059.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1060.       if (Flags and FLAG_CARRY) = 0 then Result := (DX and $8000) > 0
  1061.       else VWIN32Error := AX;
  1062.     end;
  1063.   end;
  1064. end;
  1065.  
  1066. function DirectAccessAllowed;
  1067. { int 21h, func 4409h                               }
  1068. { in  AX = 4409h                                    }
  1069. {     BL = drive number                             }
  1070. { out CF set on error                               }
  1071. {     AX = status                                   }
  1072. { out CF clear if successful                        }
  1073. {     DX = device attribute                         }
  1074. var
  1075.   Registers: TDIOC_Registers;
  1076. begin
  1077.   VWIN32Error := ERROR_NON;
  1078.   Result := false;
  1079.   with Registers do begin
  1080.     EAX := $4409;
  1081.     EBX := Drive;
  1082.     Flags := $00000000;
  1083.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1084.       if (Flags and FLAG_CARRY) = 0 then Result := (DX and $0200) = 0
  1085.       else VWIN32Error := AX;
  1086.     end;
  1087.   end;
  1088. end;
  1089.  
  1090. type
  1091.   TParamBlock = packed record
  1092.     Operation : Byte;
  1093.     NumLocks  : Byte;
  1094.   end;
  1095.  
  1096. function LockRemovableMedia;
  1097. { int 21h, func 440Dh, code 48h                     }
  1098. { in  AX = 440Dh                                    }
  1099. {     BL = drive number                             }
  1100. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1101. {     CL = 48h                                      }
  1102. {     DS:DX -> address of ParamBlock                }
  1103. { out CF set on error                               }
  1104. {     AX = status                                   }
  1105. { out CF clear if successful                        }
  1106. {     ParamBlock.NumLocks = number of pending locks }
  1107. var
  1108.   Registers : TDIOC_Registers;
  1109.   ParamBlock: TParamBlock;
  1110. begin
  1111.   VWIN32Error := ERROR_NON;
  1112.   Result := false;
  1113.   ParamBlock.Operation := 0; {locks the volume in the drive}
  1114.   if Win95OSR2 then with Registers do begin
  1115.     EAX := $440D;
  1116.     EBX := Drive;
  1117.     ECX := $4848;
  1118.     EDX := DWord(@ParamBlock);
  1119.     Flags := $00000000;
  1120.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1121.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1122.   end;
  1123.   if not Result then with Registers do begin
  1124.     EAX := $440D;
  1125.     EBX := Drive;
  1126.     ECX := $0848;
  1127.     EDX := DWord(@ParamBlock);
  1128.     Flags := $00000000;
  1129.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1130.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1131.       else VWIN32Error := AX;
  1132.     end;
  1133.   end;
  1134. end;
  1135.  
  1136. function UnlockRemovableMedia;
  1137. { int 21h, func 440Dh, code 48h                     }
  1138. { in  AX = 440Dh                                    }
  1139. {     BL = drive number                             }
  1140. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1141. {     CL = 48h                                      }
  1142. {     DS:DX -> address of ParamBlock                }
  1143. { out CF set on error                               }
  1144. {     AX = status                                   }
  1145. { out CF clear if successful                        }
  1146. {     ParamBlock.NumLocks = number of pending locks }
  1147. var
  1148.   Registers : TDIOC_Registers;
  1149.   ParamBlock: TParamBlock;
  1150. begin
  1151.   VWIN32Error := ERROR_NON;
  1152.   Result := false;
  1153.   ParamBlock.Operation := 1; {unlocks the volume in the drive}
  1154.   if Win95OSR2 then with Registers do begin
  1155.     EAX := $440D;
  1156.     EBX := Drive;
  1157.     ECX := $4848;
  1158.     EDX := DWord(@ParamBlock);
  1159.     Flags := $00000000;
  1160.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1161.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1162.   end;
  1163.   if not Result then with Registers do begin
  1164.     EAX := $440D;
  1165.     EBX := Drive;
  1166.     ECX := $0848;
  1167.     EDX := DWord(@ParamBlock);
  1168.     Flags := $00000000;
  1169.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1170.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1171.       else VWIN32Error := AX;
  1172.     end;
  1173.   end;
  1174. end;
  1175.  
  1176. function GetRemovableMediaLocks;
  1177. { int 21h, func 440Dh, code 48h                     }
  1178. { in  AX = 440Dh                                    }
  1179. {     BL = drive number                             }
  1180. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1181. {     CL = 48h                                      }
  1182. {     DS:DX -> address of ParamBlock                }
  1183. { out CF set on error                               }
  1184. {     AX = status                                   }
  1185. { out CF clear if successful                        }
  1186. {     ParamBlock.NumLocks = number of pending locks }
  1187. var
  1188.   Registers : TDIOC_Registers;
  1189.   ParamBlock: TParamBlock;
  1190. begin
  1191.   VWIN32Error := ERROR_NON;
  1192.   Result := false;
  1193.   ParamBlock.Operation := 2; {returns the lock or unlock status}
  1194.   if Win95OSR2 then with Registers do begin
  1195.     EAX := $440D;
  1196.     EBX := Drive;
  1197.     ECX := $4848;
  1198.     EDX := DWord(@ParamBlock);
  1199.     Flags := $00000000;
  1200.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1201.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1202.   end;
  1203.   if not Result then with Registers do begin
  1204.     EAX := $440D;
  1205.     EBX := Drive;
  1206.     ECX := $0848;
  1207.     EDX := DWord(@ParamBlock);
  1208.     Flags := $00000000;
  1209.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1210.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1211.       else VWIN32Error := AX;
  1212.     end;
  1213.   end;
  1214.   if Result then Locks := ParamBlock.NumLocks;
  1215. end;
  1216.  
  1217. function EjectRemovableMedia;
  1218. { int 21h, func 440Dh, code 49h                     }
  1219. { in  AX = 440Dh                                    }
  1220. {     BL = drive number                             }
  1221. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1222. {     CL = 49h                                      }
  1223. { out CF set on error                               }
  1224. {     AX = status                                   }
  1225. { out CF clear if successful                        }
  1226. var
  1227.   Registers : TDIOC_Registers;
  1228. begin
  1229.   VWIN32Error := ERROR_NON;
  1230.   Result := false;
  1231.   if Win95OSR2 then with Registers do begin
  1232.     EAX := $440D;
  1233.     EBX := Drive;
  1234.     ECX := $4849;
  1235.     Flags := $00000000;
  1236.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1237.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1238.   end;
  1239.   if not Result then with Registers do begin
  1240.     EAX := $440D;
  1241.     EBX := Drive;
  1242.     ECX := $0849;
  1243.     Flags := $00000000;
  1244.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1245.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1246.       else VWIN32Error := AX;
  1247.     end;
  1248.   end;
  1249. end;
  1250.  
  1251. type
  1252.   TAccessFlag = packed record
  1253.     SpecialFunction: Byte; { must be zero }
  1254.     AccessFlag     : Byte;
  1255.   end;
  1256.  
  1257. function GetAccessFlag;
  1258. { int 21h, func 440Dh, code 67h                     }
  1259. { in  AX = 440Dh                                    }
  1260. {     BL = drive number                             }
  1261. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1262. {     CL = 67h                                      }
  1263. {     DS:DX -> address of buffer                    }
  1264. { out CF set on error                               }
  1265. {     AX = status                                   }
  1266. { out CF clear if successful                        }
  1267. {     buffer = AccessFlag                           }
  1268. var
  1269.   Registers : TDIOC_Registers;
  1270.   AccessFlag: TAccessFlag;
  1271. begin
  1272.   VWIN32Error := ERROR_NON;
  1273.   Result := false;
  1274.   if Win95OSR2 then with Registers do begin
  1275.     EAX := $440D;
  1276.     EBX := Drive;
  1277.     ECX := $4867;
  1278.     AccessFlag.SpecialFunction := 0;
  1279.     EDX := DWord(@AccessFlag);
  1280.     Flags := $00000000;
  1281.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1282.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1283.   end;
  1284.   if not Result then with Registers do begin
  1285.     EAX := $440D;
  1286.     EBX := Drive;
  1287.     ECX := $0867;
  1288.     AccessFlag.SpecialFunction := 0;
  1289.     EDX := DWord(@AccessFlag);
  1290.     Flags := $00000000;
  1291.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1292.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1293.       else VWIN32Error := AX;
  1294.     end;
  1295.   end;
  1296.   if Result then Flag := AccessFlag.AccessFlag;
  1297. end;
  1298.  
  1299. function SetAccessFlag;
  1300. { int 21h, func 440Dh, code 47h                     }
  1301. { in  AX = 440Dh                                    }
  1302. {     BL = drive number                             }
  1303. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1304. {     CL = 47h                                      }
  1305. {     DS:DX -> address of AccessFlag                }
  1306. { out CF set on error                               }
  1307. {     AX = status                                   }
  1308. { out CF clear if successful                        }
  1309. var
  1310.   Registers : TDIOC_Registers;
  1311.   AccessFlag: TAccessFlag;
  1312. begin
  1313.   VWIN32Error := ERROR_NON;
  1314.   Result := false;
  1315.   if Win95OSR2 then with Registers do begin
  1316.     EAX := $440D;
  1317.     EBX := Drive;
  1318.     ECX := $4847;
  1319.     AccessFlag.SpecialFunction := 0;
  1320.     AccessFlag.AccessFlag := Flag;
  1321.     EDX := DWord(@AccessFlag);
  1322.     Flags := $00000000;
  1323.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1324.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1325.   end;
  1326.   if not Result then with Registers do begin
  1327.     EAX := $440D;
  1328.     EBX := Drive;
  1329.     ECX := $0847;
  1330.     AccessFlag.SpecialFunction := 0;
  1331.     AccessFlag.AccessFlag := Flag;
  1332.     EDX := DWord(@AccessFlag);
  1333.     Flags := $00000000;
  1334.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1335.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1336.       else VWIN32Error := AX;
  1337.     end;
  1338.   end;
  1339. end;
  1340.  
  1341. function LockLogicalVolume;
  1342. { int 21h, func 440Dh, code 4Ah                     }
  1343. { in  AX = 440Dh                                    }
  1344. {     BH = lock level (0..3)                        }
  1345. {     BL = drive number                             }
  1346. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1347. {     CL = 4Ah                                      }
  1348. {     DX = permisson                                }
  1349. { out CF set on error                               }
  1350. {     AX = status                                   }
  1351. { out CF clear if successful                        }
  1352. var
  1353.   Registers: TDIOC_Registers;
  1354. begin
  1355.   VWIN32Error := ERROR_NON;
  1356.   Result := false;
  1357.   if Level > 1 then Permission := $00
  1358.   else Permission := Permission and $07;
  1359.   if Win95OSR2 then with Registers do begin
  1360.     EAX := $440D;
  1361.     EBX := (Level shl 8) or Drive;
  1362.     ECX := $484A;
  1363.     EDX := Permission;
  1364.     Flags := $00000000;
  1365.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1366.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1367.   end;
  1368.   if not Result then with Registers do begin
  1369.     EAX := $440D;
  1370.     EBX := (Level shl 8) or Drive;
  1371.     ECX := $084A;
  1372.     EDX := Permission;
  1373.     Flags := $00000000;
  1374.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1375.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1376.       else VWIN32Error := AX;
  1377.     end;
  1378.   end;
  1379. end;
  1380.  
  1381. function LockPhysicalVolume;
  1382. { int 21h, func 440Dh, code 4Bh                     }
  1383. { in  AX = 440Dh                                    }
  1384. {     BH = lock level (0..3)                        }
  1385. {     BL = disk number                              }
  1386. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1387. {     CL = 4Bh                                      }
  1388. {     DX = permisson                                }
  1389. { out CF set on error                               }
  1390. {     AX = status                                   }
  1391. { out CF clear if successful                        }
  1392. var
  1393.   Registers: TDIOC_Registers;
  1394. begin
  1395.   VWIN32Error := ERROR_NON;
  1396.   Result := false;
  1397.   if Level > 1 then Permission := $00
  1398.   else Permission := Permission and $07;
  1399.   if Win95OSR2 then with Registers do begin
  1400.     EAX := $440D;
  1401.     EBX := (Level shl 8) or Disk;
  1402.     ECX := $484B;
  1403.     EDX := Permission;
  1404.     Flags := $00000000;
  1405.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1406.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1407.   end;
  1408.   if not Result then with Registers do begin
  1409.     EAX := $440D;
  1410.     EBX := (Level shl 8) or Disk;
  1411.     ECX := $084B;
  1412.     EDX := Permission;
  1413.     Flags := $00000000;
  1414.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1415.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1416.       else VWIN32Error := AX;
  1417.     end;
  1418.   end;
  1419. end;
  1420.  
  1421. function UnlockLogicalVolume;
  1422. { int 21h, func 440Dh, code 6Ah                     }
  1423. { in  AX = 440Dh                                    }
  1424. {     BL = drive number                             }
  1425. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1426. {     CL = 6Ah                                      }
  1427. { out CF set on error                               }
  1428. {     AX = status                                   }
  1429. { out CF clear if successful                        }
  1430. var
  1431.   Registers: TDIOC_Registers;
  1432. begin
  1433.   VWIN32Error := ERROR_NON;
  1434.   Result := false;
  1435.   if Win95OSR2 then with Registers do begin
  1436.     EAX := $440D;
  1437.     EBX := Drive;
  1438.     ECX := $486A;
  1439.     Flags := $00000000;
  1440.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1441.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1442.   end;
  1443.   if not Result then with Registers do begin
  1444.     EAX := $440D;
  1445.     EBX := Drive;
  1446.     ECX := $086A;
  1447.     Flags := $00000000;
  1448.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1449.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1450.       else VWIN32Error := AX;
  1451.   end;
  1452. end;
  1453.  
  1454. function UnlockPhysicalVolume;
  1455. { int 21h, func 440Dh, code 6Bh                     }
  1456. { in  AX = 440Dh                                    }
  1457. {     BL = disk number                              }
  1458. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1459. {     CL = 6Bh                                      }
  1460. { out CF set on error                               }
  1461. {     AX = status                                   }
  1462. { out CF clear if successful                        }
  1463. var
  1464.   Registers: TDIOC_Registers;
  1465. begin
  1466.   VWIN32Error := ERROR_NON;
  1467.   Result := false;
  1468.   if Win95OSR2 then with Registers do begin
  1469.     EAX := $440D;
  1470.     EBX := Disk;
  1471.     ECX := $486B;
  1472.     Flags := $00000000;
  1473.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1474.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1475.   end;
  1476.   if not Result then with Registers do begin
  1477.     EAX := $440D;
  1478.     EBX := Disk;
  1479.     ECX := $086B;
  1480.     Flags := $00000000;
  1481.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1482.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1483.       else VWIN32Error := AX;
  1484.     end;
  1485.   end;
  1486. end;
  1487.  
  1488. function GetCurrentLockState;
  1489. { int 21h, func 440Dh, code 70h                     }
  1490. { in  AX = 440Dh                                    }
  1491. {     BL = drive number                             }
  1492. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1493. {     CL = 70h                                      }
  1494. { out CF set on error                               }
  1495. {     AX = status                                   }
  1496. { out CF clear if successful                        }
  1497. {     AX = lock level                               }
  1498. {     CX = lock permission                          }
  1499. var
  1500.   Registers: TDIOC_Registers;
  1501. begin
  1502.   VWIN32Error := ERROR_NON;
  1503.   Result := false;
  1504.   if Win95OSR2 then with Registers do begin
  1505.     EAX := $440D;
  1506.     EBX := Drive;
  1507.     ECX := $4870;
  1508.     Flags := $00000000;
  1509.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1510.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1511.   end;
  1512.   if not Result then with Registers do begin
  1513.     EAX := $440D;
  1514.     EBX := Drive;
  1515.     ECX := $0870;
  1516.     Flags := $00000000;
  1517.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1518.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1519.       else VWIN32Error := AX;
  1520.     end;
  1521.   end;
  1522.   if Result then with Registers do begin
  1523.     Level := AX;
  1524.     Permission := CX;
  1525.   end;
  1526. end;
  1527.  
  1528. function GetLockFlagState;
  1529. { int 21h, func 440Dh, 6Ch                          }
  1530. { in  AX = 440Dh                                    }
  1531. {     BL = drive number                             }
  1532. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1533. {     CL = 6Ch                                      }
  1534. { out CF set on error                               }
  1535. {     AX = status                                   }
  1536. { out CF clear if successful                        }
  1537. {     AX = flag state                               }
  1538. var
  1539.   Registers: TDIOC_Registers;
  1540. begin
  1541.   VWIN32Error := ERROR_NON;
  1542.   Result := false;
  1543.   if Win95OSR2 then with Registers do begin
  1544.     EAX := $440D;
  1545.     EBX := Drive;
  1546.     ECX := $486C;
  1547.     Flags := $00000000;
  1548.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1549.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1550.   end;
  1551.   if not Result then with Registers do begin
  1552.     EAX := $440D;
  1553.     EBX := Drive;
  1554.     ECX := $086C;
  1555.     Flags := $00000000;
  1556.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1557.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1558.       else VWIN32Error := AX;
  1559.     end;
  1560.   end;
  1561.   if Result then with Registers do Flags := AX;
  1562. end;
  1563.  
  1564. function EnumerateOpenFiles;
  1565. { int 21h, func 440Dh, code 6Dh                     }
  1566. { in  AX = 440Dh                                    }
  1567. {     BL = drive number                             }
  1568. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1569. {     CL = 6Dh                                      }
  1570. {     DS:DX -> address of buffer                    }
  1571. {     SI = file index                               }
  1572. {     DI = enumeraton type (0=all, 1=unmovable)     }
  1573. { out CF set on error                               }
  1574. {     AX = status                                   }
  1575. { out CF clear if successful                        }
  1576. {     AX = open mode                                }
  1577. {     CX = file type                                }
  1578. {     buffer = file path                            }
  1579. var
  1580.   Registers : TDIOC_Registers;
  1581.   PathBuffer: PChar;
  1582. begin
  1583.   VWIN32Error := ERROR_NON;
  1584.   Result := false;
  1585.   GetMem(PathBuffer,MAX_PATH);
  1586.   if Win95OSR2 then with Registers do begin
  1587.     EAX := $440D;
  1588.     EBX := Drive;
  1589.     ECX := $486D;
  1590.     EDX := DWord(PathBuffer);
  1591.     ESI := FileIndex;
  1592.     EDI := 0;
  1593.     Flags := $00000000;
  1594.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1595.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1596.   end;
  1597.   if not Result then with Registers do begin
  1598.     EAX := $440D;
  1599.     EBX := Drive;
  1600.     ECX := $086D;
  1601.     EDX := DWord(PathBuffer);
  1602.     ESI := FileIndex;
  1603.     EDI := 0;
  1604.     Flags := $00000000;
  1605.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1606.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1607.       else VWIN32Error := AX;
  1608.     end;
  1609.   end;
  1610.   if Result then with Registers do begin
  1611.     FilePath := PathBuffer;
  1612.     OpenMode := AX;
  1613.     FileType := CX;
  1614.   end;
  1615.   FreeMem(PathBuffer,MAX_PATH);
  1616. end;
  1617.  
  1618. function FindSwapFile;
  1619. { int 21h, func 440Dh, code 6Eh                     }
  1620. { in  AX = 440Dh                                    }
  1621. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1622. {     CL = 6Eh                                      }
  1623. {     DS:DX -> address of buffer                    }
  1624. { out CF set on error                               }
  1625. {     AX = status                                   }
  1626. { out CF clear if successful                        }
  1627. {     AX = pager type                               }
  1628. {     CX:BX = file size (in 4Kb pages)              }
  1629. {     buffer = file path                            }
  1630. var
  1631.   Registers : TDIOC_Registers;
  1632.   PathBuffer: PChar;
  1633. begin
  1634.   VWIN32Error := ERROR_NON;
  1635.   Result := false;
  1636.   GetMem(PathBuffer,MAX_PATH);
  1637.   if Win95OSR2 then with Registers do begin
  1638.     EAX := $440D;
  1639.     ECX := $486E;
  1640.     EDX := DWord(PathBuffer);
  1641.     Flags := $00000000;
  1642.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1643.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1644.   end;
  1645.   if not Result then with Registers do begin
  1646.     EAX := $440D;
  1647.     ECX := $086E;
  1648.     EDX := DWord(PathBuffer);
  1649.     Flags := $00000000;
  1650.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1651.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1652.       else VWIN32Error := AX;
  1653.     end;
  1654.   end;
  1655.   if Result then with Registers do begin
  1656.     FilePath := PathBuffer;
  1657.     PagerType := AX;
  1658.     PageCount := (CX shl 16) or BX;
  1659.   end;
  1660.   FreeMem(PathBuffer,MAX_PATH);
  1661. end;
  1662.  
  1663. {function ResetDrive;}
  1664. { don't know how to perform this interrupt in Win9x }
  1665. { int 21h, func 710Dh                               }
  1666. { in  AX = 710Dh                                    }
  1667. {     CX = flag                                     }
  1668. {     DX = drive number                             }
  1669.  
  1670. function GetMediaIdentifier;
  1671. { int 21h, func 440Dh, code 66h                     }
  1672. { in  AX = 440Dh                                    }
  1673. {     BL = drive number                             }
  1674. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1675. {     CL = 66h                                      }
  1676. {     DS:DX -> address of buffer                    }
  1677. { out CF set on error                               }
  1678. {     AX = status                                   }
  1679. { out CF clear if successful                        }
  1680. {     buffer = MediaIdentifier                      }
  1681. var
  1682.   Registers: TDIOC_Registers;
  1683. begin
  1684.   VWIN32Error := ERROR_NON;
  1685.   Result := false;
  1686.   if Win95OSR2 then with Registers do begin
  1687.     EAX := $440D;
  1688.     EBX := Drive;
  1689.     ECX := $4866;
  1690.     EDX := DWord(@Media);
  1691.     Flags := $00000000;
  1692.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1693.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1694.   end;
  1695.   if not Result then with Registers do begin
  1696.     EAX := $440D;
  1697.     EBX := Drive;
  1698.     ECX := $0866;
  1699.     EDX := DWord(@Media);
  1700.     Flags := $00000000;
  1701.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1702.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1703.       else VWIN32Error := AX;
  1704.     end;
  1705.   end;
  1706. end;
  1707.  
  1708. function SetMediaIdentifier;
  1709. { int 21h, func 440Dh, code 46h                     }
  1710. { in  AX = 440Dh                                    }
  1711. {     BL = drive number                             }
  1712. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1713. {     CL = 46h                                      }
  1714. {     DS:DX -> address of MediaIdentifier           }
  1715. { out CF set on error                               }
  1716. {     AX = status                                   }
  1717. { out CF clear if successful                        }
  1718. var
  1719.   Registers: TDIOC_Registers;
  1720. begin
  1721.   VWIN32Error := ERROR_NON;
  1722.   Result := false;
  1723.   if Win95OSR2 then with Registers do begin
  1724.     EAX := $440D;
  1725.     EBX := Drive;
  1726.     ECX := $4846;
  1727.     Media.InfoLevel := 0;
  1728.     EDX := DWord(@Media);
  1729.     Flags := $00000000;
  1730.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1731.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1732.   end;
  1733.   if not Result then with Registers do begin
  1734.     EAX := $440D;
  1735.     EBX := Drive;
  1736.     ECX := $0846;
  1737.     Media.InfoLevel := 0;
  1738.     EDX := DWord(@Media);
  1739.     Flags := $00000000;
  1740.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1741.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1742.       else VWIN32Error := AX;
  1743.     end;
  1744.   end;
  1745. end;
  1746.  
  1747. function SenseMediaType;
  1748. { int 21h, func 440Dh, code 68h                     }
  1749. { in  AX = 440Dh                                    }
  1750. {     BL = drive number                             }
  1751. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1752. {     CL = 68h                                      }
  1753. {     DS:DX -> address of MediaIdentifier           }
  1754. { out CF set on error                               }
  1755. {     AX = status                                   }
  1756. { out CF clear if successful                        }
  1757. var
  1758.   Registers: TDIOC_Registers;
  1759. begin
  1760.   VWIN32Error := ERROR_NON;
  1761.   Result := false;
  1762.   if Win95OSR2 then with Registers do begin
  1763.     EAX := $440D;
  1764.     EBX := Drive;
  1765.     ECX := $4868;
  1766.     EDX := DWord(@Media);
  1767.     Flags := $00000000;
  1768.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1769.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1770.   end;
  1771.   if not Result then with Registers do begin
  1772.     EAX := $440D;
  1773.     EBX := Drive;
  1774.     ECX := $0868;
  1775.     EDX := DWord(@Media);
  1776.     Flags := $00000000;
  1777.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1778.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1779.       else VWIN32Error := AX;
  1780.     end;
  1781.   end;
  1782. end;
  1783.  
  1784. type
  1785.   TDriveMapInfoBuffer = packed record
  1786.     AllocationLength   : Byte; { length of this structure upon call }
  1787.     InfoLength         : Byte; { number of bytes used in the structure }
  1788.     DriveMapInfo       : TDriveMapInfo;
  1789.   end;
  1790.  
  1791. function GetDriveMapInfo;
  1792. { int 21h, func 440Dh, code 6Fh                     }
  1793. { in  AX = 440Dh                                    }
  1794. {     BL = drive number                             }
  1795. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1796. {     CL = 6Fh                                      }
  1797. {     DS:DX -> address of buffer                    }
  1798. { out CF set on error                               }
  1799. {     AX = status                                   }
  1800. { out CF clear if successful                        }
  1801. {     buffer = DriveMapInfo                         }
  1802. var
  1803.   Registers: TDIOC_Registers;
  1804.   Buffer   : TDriveMapInfoBuffer;
  1805. begin
  1806.   VWIN32Error := ERROR_NON;
  1807.   Result := false;
  1808.   if Win95OSR2 then with Registers do begin
  1809.     EAX := $440D;
  1810.     EBX := Drive;
  1811.     ECX := $486F;
  1812.     Buffer.AllocationLength := SizeOf(TDriveMapInfoBuffer);
  1813.     EDX := DWord(@Buffer);
  1814.     Flags := $00000000;
  1815.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1816.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1817.   end;
  1818.   if not Result then with Registers do begin
  1819.     EAX := $440D;
  1820.     EBX := Drive;
  1821.     ECX := $086F;
  1822.     Buffer.AllocationLength := SizeOf(TDriveMapInfoBuffer);
  1823.     EDX := DWord(@Buffer);
  1824.     Flags := $00000000;
  1825.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1826.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1827.       else VWIN32Error := AX;
  1828.     end;
  1829.   end;
  1830.   if Result then Info := Buffer.DriveMapInfo;
  1831. end;
  1832.  
  1833. function GetDeviceParameters;
  1834. { int 21h, func 440Dh, code 60h                     }
  1835. { in  AX = 440Dh                                    }
  1836. {     BL = drive number                             }
  1837. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1838. {     CL = 60h                                      }
  1839. {     DS:DX -> address of buffer                    }
  1840. { out CF set on error                               }
  1841. {     AX = status                                   }
  1842. { out CF clear if successful                        }
  1843. {     buffer = DeviceParameters                     }
  1844. var
  1845.   Registers   : TDIOC_Registers;
  1846.   TmpDevPar   : PDeviceParameters;
  1847.   TmpExtDevPar: PExtDeviceParameters;
  1848. begin
  1849.   VWIN32Error := ERROR_NON;
  1850.   Result := false;
  1851.   if Win95OSR2 then with Registers do begin
  1852.     TmpExtDevPar := nil;
  1853.     EAX := $440D;
  1854.     EBX := Drive;
  1855.     ECX := $4860;
  1856.     if Size = SizeOf(TExtDeviceParameters) then EDX := DWord(Buffer)
  1857.     else begin
  1858.       GetMem(TmpExtDevPar,SizeOf(TExtDeviceParameters));
  1859.       EDX := DWord(TmpExtDevPar)
  1860.     end;
  1861.     Flags := $00000000;
  1862.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1863.       if (Flags and FLAG_CARRY) = 0 then begin
  1864.         Result := true;
  1865.         if Size = SizeOf(TDeviceParameters) then begin
  1866.           PDeviceParameters(Buffer)^ := PDeviceParameters(TmpExtDevPar)^;
  1867.           with PDeviceParameters(Buffer)^ do begin
  1868.             FillChar(Fill31Bytes,SizeOf(Fill31Bytes),0);
  1869.             EntriesInTable := 0;
  1870.           end;
  1871.           ReallocMem(TmpExtDevPar,0);
  1872.         end;
  1873.       end;
  1874.   end;
  1875.   if not Result then with Registers do begin
  1876.     TmpDevPar := nil;
  1877.     EAX := $440D;
  1878.     EBX := Drive;
  1879.     ECX := $0860;
  1880.     if Size = SizeOf(TDeviceParameters) then EDX := DWord(Buffer)
  1881.     else begin
  1882.       GetMem(TmpDevPar,SizeOf(TExtDeviceParameters));
  1883.       EDX := DWord(TmpDevPar)
  1884.     end;
  1885.     Flags := $00000000;
  1886.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1887.       if (Flags and FLAG_CARRY) = 0 then begin
  1888.         Result := true;
  1889.         if Size = SizeOf(TExtDeviceParameters) then begin
  1890.           PDeviceParameters(Buffer)^ := PDeviceParameters(TmpDevPar)^;
  1891.           with PExtDeviceParameters(Buffer)^ do begin
  1892.             BPB.BigSectorsPerFat := 0;
  1893.             BPB.ExtFlags := 0;
  1894.             BPB.FileSysVersion := 0;
  1895.             BPB.RootDirStartCluster := 0;
  1896.             BPB.FileSysInfoSector := $FFFF;
  1897.             BPB.BackupBootSector := $FFFF;
  1898.             FillChar(BPB.Reserved,SizeOf(BPB.Reserved),0);
  1899.             FillChar(Reserved,SizeOf(Reserved),0);
  1900.           end;
  1901.           ReallocMem(TmpDevPar,0);
  1902.         end;
  1903.       end
  1904.       else VWIN32Error := AX;
  1905.     end;
  1906.   end;
  1907. end;
  1908.  
  1909. function SetDeviceParameters;
  1910. { int 21h, func 440Dh, code 40h                     }
  1911. { in  AX = 440Dh                                    }
  1912. {     BL = drive number                             }
  1913. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1914. {     CL = 40h                                      }
  1915. {     DS:DX -> address of DeviceParameters          }
  1916. { out CF set on error                               }
  1917. {     AX = status                                   }
  1918. { out CF clear if successful                        }
  1919. var
  1920.   Registers   : TDIOC_Registers;
  1921.   TmpDevPar   : PDeviceParameters;
  1922.   TmpExtDevPar: PExtDeviceParameters;
  1923. begin
  1924.   VWIN32Error := ERROR_NON;
  1925.   Result := false;
  1926.   if Win95OSR2 and (Size = SizeOf(TExtDeviceParameters)) then with Registers do begin
  1927.     TmpExtDevPar := nil;
  1928.     EAX := $440D;
  1929.     EBX := Drive;
  1930.     ECX := $4840;
  1931.     if Size = SizeOf(TExtDeviceParameters) then EDX := DWord(Buffer)
  1932.     else begin
  1933.       GetMem(TmpExtDevPar,SizeOf(TExtDeviceParameters)
  1934.              +SizeOf(TSectorEntry)*PExtDeviceParameters(Buffer)^.EntriesInTable);
  1935.       PDeviceParameters(TmpExtDevPar)^ := PDeviceParameters(Buffer)^;
  1936.       with TmpExtDevPar^ do begin
  1937.         BPB.BigSectorsPerFat := 0;
  1938.         BPB.ExtFlags := 0;
  1939.         BPB.FileSysVersion := 0;
  1940.         BPB.RootDirStartCluster := 0;
  1941.         BPB.FileSysInfoSector := $FFFF;
  1942.         BPB.BackupBootSector := $FFFF;
  1943.         FillChar(BPB.Reserved,SizeOf(BPB.Reserved),0);
  1944.         FillChar(Reserved,SizeOf(Reserved),0);
  1945.       end;
  1946.       with PDeviceParameters(Buffer)^ do begin
  1947.         TmpExtDevPar^.EntriesInTable := EntriesInTable;
  1948.         CopyMemory(@TmpExtDevPar^.SectorTable,
  1949.                    @SectorTable,EntriesInTable*SizeOf(TSectorEntry));
  1950.       end;
  1951.       EDX := DWord(TmpExtDevPar);
  1952.     end;
  1953.     Flags := $00000000;
  1954.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  1955.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  1956.     if TmpExtDevPar <> nil then ReallocMem(TmpExtDevPar,0);
  1957.   end;
  1958.   if not Result then with Registers do begin
  1959.     TmpDevPar := nil;
  1960.     EAX := $440D;
  1961.     EBX := Drive;
  1962.     ECX := $0840;
  1963.     if Size = SizeOf(TDeviceParameters) then EDX := DWord(Buffer)
  1964.     else begin
  1965.       GetMem(TmpDevPar,SizeOf(TExtDeviceParameters)
  1966.              +SizeOf(TSectorEntry)*PExtDeviceParameters(Buffer)^.EntriesInTable);
  1967.       PDeviceParameters(TmpDevPar)^ := PDeviceParameters(Buffer)^;
  1968.       with PExtDeviceParameters(Buffer)^ do begin
  1969.         TmpDevPar^.EntriesInTable := EntriesInTable;
  1970.         CopyMemory(@TmpDevPar^.SectorTable,
  1971.                    @SectorTable,EntriesInTable*SizeOf(TSectorEntry));
  1972.       end;
  1973.       EDX := DWord(TmpDevPar);
  1974.     end;
  1975.     Flags := $00000000;
  1976.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  1977.       if (Flags and FLAG_CARRY) = 0 then Result := true
  1978.       else VWIN32Error := AX;
  1979.     end;
  1980.     if TmpDevPar <> nil then ReallocMem(TmpDevPar,0);
  1981.   end;
  1982. end;
  1983.  
  1984. type
  1985.   TReadWriteBlock = packed record
  1986.     SpecFunc   : Byte; { must be zero }
  1987.     Head       : Word;
  1988.     Cylinder   : Word;
  1989.     FirstSector: Word;
  1990.     Sectors    : Word;
  1991.     Buffer     : Pointer;
  1992.   end;
  1993.  
  1994. function ReadTrack;
  1995. { int 21h, func 440Dh, code 61h                     }
  1996. { in  AX = 440Dh                                    }
  1997. {     BL = drive number                             }
  1998. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  1999. {     CL = 61h                                      }
  2000. {     DS:DX -> address of ReadWriteBlock            }
  2001. { out CF set on error                               }
  2002. {     AX = status                                   }
  2003. { out CF clear if successful                        }
  2004. var
  2005.   Registers     : TDIOC_Registers;
  2006.   ReadWriteBlock: TReadWriteBlock;
  2007. begin
  2008.   VWIN32Error := ERROR_NON;
  2009.   Result := false;
  2010.   if Win95OSR2 then with Registers do begin
  2011.     EAX := $440D;
  2012.     EBX := Drive;
  2013.     ECX := $4861;
  2014.     ReadWriteBlock.SpecFunc := 0;
  2015.     ReadWriteBlock.Head := Head;
  2016.     ReadWriteBlock.Cylinder := Cylinder;
  2017.     ReadWriteBlock.Firstsector := Sector;
  2018.     ReadWriteBlock.Sectors := Count;
  2019.     ReadWriteBlock.Buffer := Buffer;
  2020.     EDX := DWord(@ReadWriteBlock);
  2021.     Flags := $00000000;
  2022.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  2023.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  2024.   end;
  2025.   if not Result then with Registers do begin
  2026.     EAX := $440D;
  2027.     EBX := Drive;
  2028.     ECX := $0861;
  2029.     ReadWriteBlock.SpecFunc := 0;
  2030.     ReadWriteBlock.Head := Head;
  2031.     ReadWriteBlock.Cylinder := Cylinder;
  2032.     ReadWriteBlock.Firstsector := Sector;
  2033.     ReadWriteBlock.Sectors := Count;
  2034.     ReadWriteBlock.Buffer := Buffer;
  2035.     EDX := DWord(@ReadWriteBlock);
  2036.     Flags := $00000000;
  2037.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  2038.       if (Flags and FLAG_CARRY) = 0 then Result := true
  2039.       else VWIN32Error := AX;
  2040.     end;
  2041.   end;
  2042. end;
  2043.  
  2044. function  WriteTrack;
  2045. { int 21h, func 440Dh, code 41h                     }
  2046. { in  AX = 440Dh                                    }
  2047. {     BL = drive number                             }
  2048. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  2049. {     CL = 41h                                      }
  2050. {     DS:DX -> address of ReadWriteBlock            }
  2051. { out CF set on error                               }
  2052. {     AX = status                                   }
  2053. { out CF clear if successful                        }
  2054. var
  2055.   Registers     : TDIOC_Registers;
  2056.   ReadWriteBlock: TReadWriteBlock;
  2057. begin
  2058.   VWIN32Error := ERROR_NON;
  2059.   Result := false;
  2060.   if Win95OSR2 then with Registers do begin
  2061.     EAX := $440D;
  2062.     EBX := Drive;
  2063.     ECX := $4841;
  2064.     ReadWriteBlock.SpecFunc := 0;
  2065.     ReadWriteBlock.Head := Head;
  2066.     ReadWriteBlock.Cylinder := Cylinder;
  2067.     ReadWriteBlock.Firstsector := Sector;
  2068.     ReadWriteBlock.Sectors := Count;
  2069.     ReadWriteBlock.Buffer := Buffer;
  2070.     EDX := DWord(@ReadWriteBlock);
  2071.     Flags := $00000000;
  2072.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  2073.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  2074.   end;
  2075.   if not Result then with Registers do begin
  2076.     EAX := $440D;
  2077.     EBX := Drive;
  2078.     ECX := $0841;
  2079.     ReadWriteBlock.SpecFunc := 0;
  2080.     ReadWriteBlock.Head := Head;
  2081.     ReadWriteBlock.Cylinder := Cylinder;
  2082.     ReadWriteBlock.Firstsector := Sector;
  2083.     ReadWriteBlock.Sectors := Count;
  2084.     ReadWriteBlock.Buffer := Buffer;
  2085.     EDX := DWord(@ReadWriteBlock);
  2086.     Flags := $00000000;
  2087.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  2088.       if (Flags and FLAG_CARRY) = 0 then Result := true
  2089.       else VWIN32Error := AX;
  2090.     end;
  2091.   end;
  2092. end;
  2093.  
  2094. type
  2095.   TFormatVerifyBlock = packed record
  2096.     SpecFunc: Byte;
  2097.     Head    : Word;
  2098.     Cylinder: Word;
  2099.     Tracks  : Word;
  2100.   end;
  2101.  
  2102. function FormatTrack;
  2103. { int 21h, func 440Dh, code 42h                     }
  2104. { in  AX = 440Dh                                    }
  2105. {     BL = drive number                             }
  2106. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  2107. {     CL = 42h                                      }
  2108. {     DS:DX -> address of FormatVerifyBlock         }
  2109. { out CF set on error                               }
  2110. {     AX = status                                   }
  2111. { out CF clear if successful                        }
  2112. var
  2113.   Registers        : TDIOC_Registers;
  2114.   FormatVerifyBlock: TFormatVerifyBlock;
  2115. begin
  2116.   VWIN32Error := ERROR_NON;
  2117.   Result := false;
  2118.   if Win95OSR2 then with Registers do begin
  2119.     EAX := $440D;
  2120.     EBX := Drive;
  2121.     ECX := $4842;
  2122.     FormatVerifyBlock.SpecFunc := 0;
  2123.     FormatVerifyBlock.Head := Head;
  2124.     FormatVerifyBlock.Cylinder := Cylinder;
  2125.     FormatVerifyBlock.Tracks := 1;
  2126.     EDX := DWord(@FormatVerifyBlock);
  2127.     Flags := $00000000;
  2128.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  2129.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  2130.   end;
  2131.   if not Result then with Registers do begin
  2132.     EAX := $440D;
  2133.     EBX := Drive;
  2134.     ECX := $0842;
  2135.     FormatVerifyBlock.SpecFunc := 0;
  2136.     FormatVerifyBlock.Head := Head;
  2137.     FormatVerifyBlock.Cylinder := Cylinder;
  2138.     FormatVerifyBlock.Tracks := 1;
  2139.     EDX := DWord(@FormatVerifyBlock);
  2140.     Flags := $00000000;
  2141.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  2142.       if (Flags and FLAG_CARRY) = 0 then Result := true
  2143.       else VWIN32Error := AX;
  2144.     end;
  2145.   end;
  2146. end;
  2147.  
  2148. function VerifyTrack;
  2149. { int 21h, func 440Dh, code 62h                     }
  2150. { in  AX = 440Dh                                    }
  2151. {     BL = drive number                             }
  2152. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  2153. {     CL = 62h                                      }
  2154. {     DS:DX -> address of FormatVerifyBlock         }
  2155. { out CF set on error                               }
  2156. {     AX = status                                   }
  2157. { out CF clear if successful                        }
  2158. var
  2159.   Registers        : TDIOC_Registers;
  2160.   FormatVerifyBlock: TFormatVerifyBlock;
  2161. begin
  2162.   VWIN32Error := ERROR_NON;
  2163.   Result := false;
  2164.   if Win95OSR2 then with Registers do begin
  2165.     EAX := $440D;
  2166.     EBX := Drive;
  2167.     ECX := $4862;
  2168.     FormatVerifyBlock.SpecFunc := 0;
  2169.     FormatVerifyBlock.Head := Head;
  2170.     FormatVerifyBlock.Cylinder := Cylinder;
  2171.     FormatVerifyBlock.Tracks := 1;
  2172.     EDX := DWord(@FormatVerifyBlock);
  2173.     Flags := $00000000;
  2174.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  2175.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  2176.   end;
  2177.   if not Result then with Registers do begin
  2178.     EAX := $440D;
  2179.     EBX := Drive;
  2180.     ECX := $0862;
  2181.     FormatVerifyBlock.SpecFunc := 0;
  2182.     FormatVerifyBlock.Head := Head;
  2183.     FormatVerifyBlock.Cylinder := Cylinder;
  2184.     FormatVerifyBlock.Tracks := 1;
  2185.     EDX := DWord(@FormatVerifyBlock);
  2186.     Flags := $00000000;
  2187.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  2188.       if (Flags and FLAG_CARRY) = 0 then Result := true
  2189.       else VWIN32Error := AX;
  2190.     end;
  2191.   end;
  2192. end;
  2193.  
  2194. type
  2195.   TReadWritePacket = packed record
  2196.     StartSector: DWord;
  2197.     Sectors    : Word;
  2198.     Buffer     : Pointer;
  2199.   end;
  2200.  
  2201. function ReadSector;
  2202. { int 21h, func 7305h                               }
  2203. { in  AX = 7305h                                    }
  2204. {     DS:BX -> address of ReadWritePacket           }
  2205. {     CX = must be -1 (FFFFh)                       }
  2206. {     DL = drive number                             }
  2207. {     SI = 0000h (read)                             }
  2208. { out CF set on error                               }
  2209. {     AX = status                                   }
  2210. { out CF clear if successful                        }
  2211. {                                                   }
  2212. { int 25h                                           }
  2213. { in  AL = drive number (0-based)                   }
  2214. {     DS:BX -> address of ReadWritePacket           }
  2215. {     CX = FFFFh (large hard disk partition)        }
  2216. { out CF set on error                               }
  2217. {     AX = status                                   }
  2218. { out CF clear if successful                        }
  2219. var
  2220.   Registers      : TDIOC_Registers;
  2221.   ReadWritePacket: TReadWritePacket;
  2222. begin
  2223.   VWIN32Error := ERROR_NON;
  2224.   Result := false;
  2225.   if Win95OSR2 then with Registers do begin
  2226.     EAX := $7305;
  2227.     ReadWritePacket.StartSector := Sector;
  2228.     ReadWritePacket.Sectors := Count;
  2229.     ReadWritePacket.Buffer := Buffer;
  2230.     EBX := DWord(@ReadWritePacket);
  2231.     ECX := $FFFFFFFF;
  2232.     EDX := Drive;
  2233.     ESI := $0000;
  2234.     Flags := $00000000;
  2235.     if VWIN32DIOC(VWIN32_DIOC_DOS_DRIVEINFO,@Registers) then
  2236.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  2237.   end;
  2238.   if not Result then with Registers do begin
  2239.     EAX := Drive-1;
  2240.     ReadWritePacket.StartSector := Sector;
  2241.     ReadWritePacket.Sectors := Count;
  2242.     ReadWritePacket.Buffer := Buffer;
  2243.     EBX := DWord(@ReadWritePacket);
  2244.     ECX := $FFFFFFFF;
  2245.     Flags := $00000000;
  2246.     if VWIN32DIOC(VWIN32_DIOC_DOS_INT25,@Registers) then begin
  2247.       if (Flags and FLAG_CARRY) = 0 then Result := true
  2248.       else VWIN32Error := $10000 or (AX and $00FF);
  2249.     end;
  2250.   end;
  2251. end;
  2252.  
  2253. function WriteSector;
  2254. { int 21h, func 7305h                               }
  2255. { in  AX = 7305h                                    }
  2256. {     DS:BX -> address of ReadWritePacket           }
  2257. {     CX = must be -1 (FFFFh)                       }
  2258. {     DL = drive number                             }
  2259. {     SI = 0001h (write) or write mode              }
  2260. { out CF set on error                               }
  2261. {     AX = status                                   }
  2262. { out CF clear if successful                        }
  2263. {                                                   }
  2264. { int 26h                                           }
  2265. { in  AL = drive number (0-based)                   }
  2266. {     DS:BX -> address of ReadWritePacket           }
  2267. {     CX = FFFFh (large hard disk partition)        }
  2268. { out CF set on error                               }
  2269. {     AX = status                                   }
  2270. { out CF clear if successful                        }
  2271. var
  2272.   Registers      : TDIOC_Registers;
  2273.   ReadWritePacket: TReadWritePacket;
  2274. begin
  2275.   VWIN32Error := ERROR_NON;
  2276.   Result := false;
  2277.   if Win95OSR2 then with Registers do begin
  2278.     EAX := $7305;
  2279.     ReadWritePacket.StartSector := Sector;
  2280.     ReadWritePacket.Sectors := Count;
  2281.     ReadWritePacket.Buffer := Buffer;
  2282.     EBX := DWord(@ReadWritePacket);
  2283.     ECX := $FFFFFFFF;
  2284.     EDX := Drive;
  2285.     ESI := $0001 or (Mode and $6000);
  2286.     Flags := $00000000;
  2287.     if VWIN32DIOC(VWIN32_DIOC_DOS_DRIVEINFO,@Registers) then
  2288.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  2289.   end;
  2290.   if not Result then with Registers do begin
  2291.     EAX := Drive-1;
  2292.     ReadWritePacket.StartSector := Sector;
  2293.     ReadWritePacket.Sectors := Count;
  2294.     ReadWritePacket.Buffer := Buffer;
  2295.     EBX := DWord(@ReadWritePacket);
  2296.     ECX := $FFFFFFFF;
  2297.     Flags := $00000000;
  2298.     if VWIN32DIOC(VWIN32_DIOC_DOS_INT26,@Registers) then begin
  2299.       if (Flags and FLAG_CARRY) = 0 then Result := true
  2300.       else VWIN32Error := $10000 or (AX and $00FF);
  2301.     end;
  2302.   end;
  2303. end;
  2304.  
  2305. function GetFirstCluster;
  2306. { int 21h, func 440Dh, code 71h                     }
  2307. { in  AX = 440Dh                                    }
  2308. {     BX = character set (0=ANSI, 1=OEM, 2=UNICODE) }
  2309. {     CH = device category (08h=FAT16, 48h=FAT32)   }
  2310. {     CL = 71h                                      }
  2311. {     DS:DX -> address of path                      }
  2312. { out CF set on error                               }
  2313. {     AX = status                                   }
  2314. { out CF clear if successful                        }
  2315. {     DX:AX = cluster number                        }
  2316. var
  2317.   Registers: TDIOC_Registers;
  2318. begin
  2319.   VWIN32Error := ERROR_NON;
  2320.   Result := false;
  2321.   if Win95OSR2 then with Registers do begin
  2322.     EAX := $440D;
  2323.     EBX := 0;
  2324.     ECX := $4871;
  2325.     EDX := DWord(PChar(Path));
  2326.     Flags := $00000000;
  2327.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then
  2328.       if (Flags and FLAG_CARRY) = 0 then Result := true;
  2329.   end;
  2330.   if not Result then with Registers do begin
  2331.     EAX := $440D;
  2332.     EBX := 0;
  2333.     ECX := $0871;
  2334.     EDX := DWord(PChar(Path));
  2335.     Flags := $00000000;
  2336.     if VWIN32DIOC(VWIN32_DIOC_DOS_IOCTL,@Registers) then begin
  2337.       if (Flags and FLAG_CARRY) = 0 then Result := true
  2338.       else VWIN32Error := AX;
  2339.     end;
  2340.   end;
  2341.   if Result then with Registers do Cluster := EAX;
  2342.   {?: if Result then with Registers do Cluster := (DX shl 16) or AX;}
  2343. end;
  2344.  
  2345. function MakeSerialNumber;
  2346. var
  2347.   SystemTime: TSystemTime;
  2348.   FileTime  : TFileTime;
  2349.   DateTime  : array[0..1] of Word;
  2350. begin
  2351.   GetSystemTime(SystemTime);
  2352.   SystemTimeToFileTime(SystemTime,FileTime);
  2353.   FileTimeToDosDateTime(FileTime,DateTime[1],DateTime[0]);
  2354.   Result := DWord(DateTime);
  2355. end;
  2356.  
  2357. {==============================================================================}
  2358. Initialization
  2359.   VWIN32Error := ERROR_NON;
  2360.   VWIN32Device := INVALID_HANDLE_VALUE;
  2361.   OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
  2362.   GetVersionEx(OSVersionInfo);
  2363.   Win95OSR2 := WindowsVersion(0,0,1081,VER_PLATFORM_WIN32_WINDOWS);
  2364.  
  2365. finalization
  2366.   VWIN32DIOC(VWIN32_DIOC_CLOSE,nil);
  2367.  
  2368. end.
  2369.