You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 line
10 KiB

  1. unit uwinImports;
  2. {$mode objfpc}{$H+}
  3. {
  4. Accepts the following defines (pass to package in project's Additions and Overrides):
  5. UTL_WINSUPP_NT50 => Code should work/compile/start on NT5.0 (Windows 2000)
  6. }
  7. interface
  8. uses
  9. Classes, SysUtils, windows, activex, shlobj;
  10. const
  11. shell32 = 'shell32.dll';
  12. {%REGION Filesystem }
  13. //function GetVolumePathNameA(lpszFileName: LPCSTR; lpszVolumePathName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall; external kernel32 name 'GetVolumePathNameA';
  14. //function GetVolumePathNameW(lpszFileName: LPCWSTR; lpszVolumePathName: LPWSTR; cchBufferLength: DWORD): BOOL; stdcall; external kernel32 name 'GetVolumePathNameW';
  15. function GetVolumePathName(lpszFileName: LPCTSTR; lpszVolumePathName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall; external kernel32 name 'GetVolumePathNameA';
  16. {%ENDREGION}
  17. {%REGION IOCTL }
  18. const
  19. FILE_DEVICE_DISK = $00000007;
  20. FILE_DEVICE_MASS_STORAGE = $0000002D;
  21. METHOD_BUFFERED = 0;
  22. FILE_ANY_ACCESS = 0;
  23. FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS;
  24. FILE_READ_ACCESS = $0001;
  25. FILE_WRITE_ACCESS = $0002;
  26. FILE_RW_ACCESS = FILE_READ_ACCESS or FILE_WRITE_ACCESS;
  27. IOCTL_DISK_BASE = FILE_DEVICE_DISK;
  28. IOCTL_DISK_GET_DRIVE_GEOMETRY = ((IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0000 shl 2) or METHOD_BUFFERED);
  29. IOCTL_DISK_FORMAT_TRACKS = ((IOCTL_DISK_BASE shl 16) or (FILE_RW_ACCESS shl 14) or ($0006 shl 2) or METHOD_BUFFERED);
  30. IOCTL_DISK_GET_LENGTH_INFO = ((IOCTL_DISK_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0017 shl 2) or METHOD_BUFFERED);
  31. IOCTL_DISK_GET_MEDIA_TYPES = ((IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0300 shl 2) or METHOD_BUFFERED);
  32. IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
  33. IOCTL_STORAGE_CHECK_VERIFY = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0200 shl 2) or METHOD_BUFFERED);
  34. IOCTL_STORAGE_CHECK_VERIFY2 = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0200 shl 2) or METHOD_BUFFERED);
  35. IOCTL_STORAGE_MEDIA_REMOVAL = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0201 shl 2) or METHOD_BUFFERED);
  36. IOCTL_STORAGE_EJECT_MEDIA = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0202 shl 2) or METHOD_BUFFERED);
  37. IOCTL_STORAGE_LOAD_MEDIA = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0203 shl 2) or METHOD_BUFFERED);
  38. IOCTL_STORAGE_LOAD_MEDIA2 = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0203 shl 2) or METHOD_BUFFERED);
  39. IOCTL_STORAGE_RESERVE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0204 shl 2) or METHOD_BUFFERED);
  40. IOCTL_STORAGE_RELEASE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0205 shl 2) or METHOD_BUFFERED);
  41. IOCTL_STORAGE_FIND_NEW_DEVICES = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0206 shl 2) or METHOD_BUFFERED);
  42. IOCTL_STORAGE_EJECTION_CONTROL = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0250 shl 2) or METHOD_BUFFERED);
  43. IOCTL_STORAGE_MCN_CONTROL = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0251 shl 2) or METHOD_BUFFERED);
  44. IOCTL_STORAGE_GET_MEDIA_TYPES = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0300 shl 2) or METHOD_BUFFERED);
  45. IOCTL_STORAGE_GET_MEDIA_TYPES_EX = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0301 shl 2) or METHOD_BUFFERED);
  46. IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER= ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0304 shl 2) or METHOD_BUFFERED);
  47. IOCTL_STORAGE_GET_HOTPLUG_INFO = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0305 shl 2) or METHOD_BUFFERED);
  48. IOCTL_STORAGE_SET_HOTPLUG_INFO = ((IOCTL_STORAGE_BASE shl 16) or (FILE_RW_ACCESS shl 14) or ($0306 shl 2) or METHOD_BUFFERED);
  49. IOCTL_STORAGE_RESET_BUS = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0400 shl 2) or METHOD_BUFFERED);
  50. IOCTL_STORAGE_RESET_DEVICE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0401 shl 2) or METHOD_BUFFERED);
  51. IOCTL_STORAGE_BREAK_RESERVATION = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0405 shl 2) or METHOD_BUFFERED);
  52. IOCTL_STORAGE_GET_DEVICE_NUMBER = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0420 shl 2) or METHOD_BUFFERED);
  53. IOCTL_STORAGE_PREDICT_FAILURE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0440 shl 2) or METHOD_BUFFERED);
  54. {%ENDREGION}
  55. {%REGION ShellAPI }
  56. {$if FPC_FULLVERSION < 030101}
  57. // only needed in versions where 0029036 is not fixed (before r32452)
  58. type LPPCITEMIDLIST = ^LPCITEMIDLIST;
  59. function SHOpenFolderAndSelectItems(pidlFolder:LPCITEMIDLIST;cidl:UINT; apidl: LPPCITEMIDLIST; dwflags: DWORD):HResult;StdCall; external shell32 name 'SHOpenFolderAndSelectItems';
  60. {$ifend}
  61. // FIXME: temporary until 0028760 is fixed in FPC
  62. function SHBindToParent2(pidl:LPCITEMIDLIST; constref riid:TREFIID; var ppv:Pointer; var ppidlLast:LPCITEMIDLIST):HRESULT;StdCall;external External_library name 'SHBindToParent';
  63. {%ENDREGION}
  64. {%REGION Helper - Filesystem }
  65. function GetVolumePathName(const aFileName: string): string;
  66. function GetVolumeSpace(const aDisk: string; out Total, Free: QWord): Boolean;
  67. function GetVolumeSizeIoCtl(const aDisk: string; out Total: QWord): Boolean;
  68. function GetDiskGeometry(hDisk: THandle; var Geometry: DISK_GEOMETRY): Boolean;
  69. function GetDriveGeometry(DriveLetter: char; var Geometry: DISK_GEOMETRY): Boolean;
  70. function GetVolumeInformation(const aDisk: string; out DriveLabel, Filesystem: string): boolean;
  71. function GetFileCompressedSize(const aFileName: string; out FSize: QWord): Boolean;
  72. function GetFileIndex(const aFilename: string; out FIndex: QWORD): boolean;
  73. {%ENDREGION}
  74. {%REGION Helpr - ShellAPI }
  75. function GetConfigLocation(const aPortable, aRoaming: boolean; aProgramSubdir: String): string;
  76. function OpenFolderAndSelectFile(const FileName: string): boolean;
  77. {%ENDREGION}
  78. implementation
  79. uses
  80. windirs;
  81. function GetVolumePathName(const aFileName: string): string;
  82. begin
  83. SetLength(Result, MAX_PATH + 2);
  84. if not uwinImports.GetVolumePathName(LPCTSTR(aFileName), LPCTSTR(Result),MAX_PATH) then
  85. exit;
  86. SetLength(Result, strlen(PChar(Result)));
  87. end;
  88. function GetVolumeSpace(const aDisk: string; out Total, Free: QWord): Boolean;
  89. var
  90. freequota: QWord;
  91. begin
  92. Result:= GetDiskFreeSpaceEx(PChar(aDisk), @freequota, @Total,@Free);
  93. end;
  94. function GetVolumeSizeIoCtl(const aDisk: string; out Total: QWord): Boolean;
  95. var
  96. dn: string;
  97. fh: THANDLE;
  98. gio: GET_LENGTH_INFORMATION;
  99. ret: dword;
  100. begin
  101. Result:= false;
  102. dn:= '\\.\'+ExcludeTrailingPathDelimiter(aDisk);
  103. fh:= CreateFile(PChar(dn), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  104. if fh = INVALID_HANDLE_VALUE then
  105. exit;
  106. try
  107. if DeviceIoControl(fh, IOCTL_DISK_GET_LENGTH_INFO, nil, 0, @gio, sizeof(gio), @ret, nil) then begin
  108. Total:= gio.Length.QuadPart;
  109. Result:= true;
  110. end;
  111. finally
  112. CloseHandle(fh);
  113. end;
  114. end;
  115. ////////////////////////////////////////////////////////////////////////////////
  116. // Comment : gets the geometry of the disk
  117. // Arguments : hDisk: THandle; var Geometry: DISK_GEOMETRY
  118. // Result : Boolean
  119. function GetDiskGeometry(hDisk: THandle; var Geometry: DISK_GEOMETRY): Boolean;
  120. var
  121. ReturnedBytesCount: DWORD;
  122. begin
  123. result := DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0, @Geometry, sizeof(Geometry), ReturnedBytesCount, nil);
  124. end;
  125. function GetDriveGeometry(DriveLetter: char; var Geometry: DISK_GEOMETRY): Boolean;
  126. var
  127. SrcDrive : string;
  128. hDrive : THandle;
  129. begin
  130. Result:= false;
  131. SrcDrive := '\\.\' + DriveLetter + ':';
  132. // open floppy drive
  133. hDrive := CreateFile(@SrcDrive[1], GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE , nil, OPEN_EXISTING, 0, 0);
  134. if hDrive <> INVALID_HANDLE_VALUE then try
  135. Result:= GetDiskGeometry(hDrive, Geometry);
  136. finally
  137. CloseHandle(hDrive);
  138. end;
  139. end;
  140. function GetVolumeInformation(const aDisk: string; out DriveLabel, Filesystem: string): boolean;
  141. var
  142. dn, fs: array[0..MAX_PATH] of Char;
  143. begin
  144. ZeroMemory(@dn[0], Length(dn));
  145. ZeroMemory(@fs[0], Length(fs));
  146. Result:= Windows.GetVolumeInformation(PChar(aDisk), @dn[0], High(dn), nil, nil, nil, @fs[0], high(fs));
  147. if Result then begin
  148. DriveLabel:= StrPas(dn);
  149. Filesystem:= StrPas(fs);
  150. end;
  151. end;
  152. function GetFileCompressedSize(const aFileName: string; out FSize: QWord): Boolean;
  153. var
  154. li: LARGE_INTEGER;
  155. begin
  156. SetLastError(0);
  157. li.LowPart:= GetCompressedFileSize(LPCSTR(aFileName), @li.HighPart);
  158. Result:= GetLastError = NOERROR;
  159. if Result then
  160. FSize:= li.QuadPart;
  161. end;
  162. function GetFileIndex(const aFilename: string; out FIndex: QWORD): boolean;
  163. var
  164. fh: THANDLE;
  165. bhfi: TBYHANDLEFILEINFORMATION;
  166. fi: LARGE_INTEGER;
  167. begin
  168. Result:= false;
  169. fh:= FileOpen(aFilename, fmOpenRead or fmShareDenyNone);
  170. if fh <> feInvalidHandle then begin
  171. if GetFileInformationByHandle(fh, bhfi) then begin
  172. fi.LowPart:= bhfi.nFileIndexLow;
  173. fi.HighPart:= bhfi.nFileIndexHigh;
  174. FIndex:= fi.QuadPart;
  175. Result:= true;
  176. end;
  177. FileClose(fh);
  178. end;
  179. end;
  180. function GetConfigLocation(const aPortable, aRoaming: boolean; aProgramSubdir: String): string;
  181. begin
  182. if aPortable then
  183. Result:= ExtractFilePath(ParamStr(0))
  184. else begin
  185. if aRoaming then
  186. Result:= IncludeTrailingPathDelimiter(GetWindowsSpecialDir(CSIDL_APPDATA))
  187. else
  188. Result:= IncludeTrailingPathDelimiter(GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA));
  189. if aProgramSubdir > '' then
  190. Result += aProgramSubdir + PathDelim;
  191. end;
  192. end;
  193. function OpenFolderAndSelectFile(const FileName: string): boolean;
  194. {$IFNDEF UTL_WINSUPP_NT50}
  195. var
  196. IIDL: PItemIDList;
  197. begin
  198. result := false;
  199. IIDL := ILCreateFromPath(PChar(FileName));
  200. if IIDL <> nil then
  201. try
  202. result := SHOpenFolderAndSelectItems(IIDL, 0, LPPCITEMIDLIST(nil), 0) = S_OK;
  203. finally
  204. ILFree(IIDL);
  205. end;
  206. {$ELSE}
  207. begin
  208. ShellExecute(0, 'explore', PChar(ExtractFilePath(FileName)), nil, nil, SW_SHOWNORMAL);
  209. {$ENDIF}
  210. end;
  211. end.