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.

333 line
13 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. shlwapi = 'shlwapi.dll';
  13. {%REGION System }
  14. const
  15. SECURITY_NT_AUTHORITY: SID_IDENTIFIER_AUTHORITY = (Value: (0, 0, 0, 0, 0, 5));
  16. function CheckTokenMembership(TokenHandle: HANDLE; SidToCheck: PSID; var IsMember: BOOL): BOOL; stdcall; external advapi32;
  17. {%ENDREGION}
  18. {%REGION Filesystem }
  19. //function GetVolumePathNameA(lpszFileName: LPCSTR; lpszVolumePathName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall; external kernel32 name 'GetVolumePathNameA';
  20. //function GetVolumePathNameW(lpszFileName: LPCWSTR; lpszVolumePathName: LPWSTR; cchBufferLength: DWORD): BOOL; stdcall; external kernel32 name 'GetVolumePathNameW';
  21. function GetVolumePathName(lpszFileName: LPCTSTR; lpszVolumePathName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall; external kernel32 name 'GetVolumePathNameA';
  22. {%ENDREGION}
  23. {%REGION IOCTL }
  24. const
  25. FILE_DEVICE_DISK = $00000007;
  26. FILE_DEVICE_MASS_STORAGE = $0000002D;
  27. METHOD_BUFFERED = 0;
  28. FILE_ANY_ACCESS = 0;
  29. FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS;
  30. FILE_READ_ACCESS = $0001;
  31. FILE_WRITE_ACCESS = $0002;
  32. FILE_RW_ACCESS = FILE_READ_ACCESS or FILE_WRITE_ACCESS;
  33. IOCTL_DISK_BASE = FILE_DEVICE_DISK;
  34. IOCTL_DISK_GET_DRIVE_GEOMETRY = ((IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0000 shl 2) or METHOD_BUFFERED);
  35. IOCTL_DISK_FORMAT_TRACKS = ((IOCTL_DISK_BASE shl 16) or (FILE_RW_ACCESS shl 14) or ($0006 shl 2) or METHOD_BUFFERED);
  36. IOCTL_DISK_GET_LENGTH_INFO = ((IOCTL_DISK_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0017 shl 2) or METHOD_BUFFERED);
  37. IOCTL_DISK_GET_MEDIA_TYPES = ((IOCTL_DISK_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0300 shl 2) or METHOD_BUFFERED);
  38. IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE;
  39. IOCTL_STORAGE_CHECK_VERIFY = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0200 shl 2) or METHOD_BUFFERED);
  40. IOCTL_STORAGE_CHECK_VERIFY2 = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0200 shl 2) or METHOD_BUFFERED);
  41. IOCTL_STORAGE_MEDIA_REMOVAL = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0201 shl 2) or METHOD_BUFFERED);
  42. IOCTL_STORAGE_EJECT_MEDIA = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0202 shl 2) or METHOD_BUFFERED);
  43. IOCTL_STORAGE_LOAD_MEDIA = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0203 shl 2) or METHOD_BUFFERED);
  44. IOCTL_STORAGE_LOAD_MEDIA2 = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0203 shl 2) or METHOD_BUFFERED);
  45. IOCTL_STORAGE_RESERVE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0204 shl 2) or METHOD_BUFFERED);
  46. IOCTL_STORAGE_RELEASE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0205 shl 2) or METHOD_BUFFERED);
  47. IOCTL_STORAGE_FIND_NEW_DEVICES = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0206 shl 2) or METHOD_BUFFERED);
  48. IOCTL_STORAGE_EJECTION_CONTROL = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0250 shl 2) or METHOD_BUFFERED);
  49. IOCTL_STORAGE_MCN_CONTROL = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0251 shl 2) or METHOD_BUFFERED);
  50. IOCTL_STORAGE_GET_MEDIA_TYPES = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0300 shl 2) or METHOD_BUFFERED);
  51. IOCTL_STORAGE_GET_MEDIA_TYPES_EX = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0301 shl 2) or METHOD_BUFFERED);
  52. IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER= ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0304 shl 2) or METHOD_BUFFERED);
  53. IOCTL_STORAGE_GET_HOTPLUG_INFO = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0305 shl 2) or METHOD_BUFFERED);
  54. IOCTL_STORAGE_SET_HOTPLUG_INFO = ((IOCTL_STORAGE_BASE shl 16) or (FILE_RW_ACCESS shl 14) or ($0306 shl 2) or METHOD_BUFFERED);
  55. IOCTL_STORAGE_RESET_BUS = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0400 shl 2) or METHOD_BUFFERED);
  56. IOCTL_STORAGE_RESET_DEVICE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0401 shl 2) or METHOD_BUFFERED);
  57. IOCTL_STORAGE_BREAK_RESERVATION = ((IOCTL_STORAGE_BASE shl 16) or (FILE_READ_ACCESS shl 14) or ($0405 shl 2) or METHOD_BUFFERED);
  58. IOCTL_STORAGE_GET_DEVICE_NUMBER = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0420 shl 2) or METHOD_BUFFERED);
  59. IOCTL_STORAGE_PREDICT_FAILURE = ((IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or ($0440 shl 2) or METHOD_BUFFERED);
  60. {%ENDREGION}
  61. {%REGION ShellAPI }
  62. {$if FPC_FULLVERSION < 030101}
  63. // only needed in versions where 0029036 is not fixed (before r32452)
  64. type LPPCITEMIDLIST = ^LPCITEMIDLIST;
  65. function SHOpenFolderAndSelectItems(pidlFolder:LPCITEMIDLIST;cidl:UINT; apidl: LPPCITEMIDLIST; dwflags: DWORD):HResult;StdCall; external shell32 name 'SHOpenFolderAndSelectItems';
  66. {$ifend}
  67. // FIXME: temporary until 0028760 is fixed in FPC
  68. function SHBindToParent2(pidl:LPCITEMIDLIST; constref riid:TREFIID; var ppv:Pointer; var ppidlLast:LPCITEMIDLIST):HRESULT;StdCall;external External_library name 'SHBindToParent';
  69. type
  70. PHICON = ^HICON;
  71. function ExtractIconEx(lpszFile: LPCSTR; nIconIndex: Integer; phIconLarge, phIconSmall: PHICON; nIcons: UINT):UINT; external shell32 name 'ExtractIconExA';
  72. function ExtractIconExW(lpszFile: LPCWSTR; nIconIndex: Integer; phIconLarge, phIconSmall: PHICON; nIcons: UINT):UINT; external shell32 name 'ExtractIconExW';
  73. function PathUnExpandEnvStrings(lpSrc:LPCSTR; lpDst:LPSTR; nSize:DWORD):BOOL; external shlwapi name 'PathUnExpandEnvStringsA';
  74. {%ENDREGION}
  75. {%REGION Helper - System }
  76. (*
  77. Routine Description: This routine returns TRUE if the caller's
  78. process is a member of the Administrators local group. Caller is NOT
  79. expected to be impersonating anyone and is expected to be able to
  80. open its own process and process token.
  81. Arguments: None.
  82. Return Value:
  83. TRUE - Caller has Administrators local group.
  84. FALSE - Caller does not have Administrators local group. --
  85. *)
  86. function IsUserAdmin: BOOL;
  87. function IsWow64: Boolean;
  88. {%ENDREGION}
  89. {%REGION Helper - Filesystem }
  90. function GetVolumePathName(const aFileName: string): string;
  91. function GetVolumeSpace(const aDisk: string; out Total, Free: QWord): Boolean;
  92. function GetVolumeSizeIoCtl(const aDisk: string; out Total: QWord): Boolean;
  93. function GetDiskGeometry(hDisk: THandle; var Geometry: DISK_GEOMETRY): Boolean;
  94. function GetDriveGeometry(DriveLetter: char; var Geometry: DISK_GEOMETRY): Boolean;
  95. function GetVolumeInformation(const aDisk: string; out DriveLabel, Filesystem: string): boolean;
  96. function GetFileCompressedSize(const aFileName: string; out FSize: QWord): Boolean;
  97. function GetFileIndex(const aFilename: string; out FIndex: QWORD): boolean;
  98. {%ENDREGION}
  99. {%REGION Helper - ShellAPI }
  100. function GetConfigLocation(const aPortable, aRoaming: boolean; aProgramSubdir: String): string;
  101. function OpenFolderAndSelectFile(const FileName: string): boolean;
  102. {%ENDREGION}
  103. implementation
  104. uses
  105. windirs;
  106. function IsWow64: Boolean;
  107. type
  108. TIsWow64Process = function( // Type of IsWow64Process API fn
  109. Handle: Windows.THandle; var Res: Windows.BOOL
  110. ): Windows.BOOL; stdcall;
  111. var
  112. IsWow64Result: Windows.BOOL; // Result from IsWow64Process
  113. IsWow64Process: TIsWow64Process; // IsWow64Process fn reference
  114. begin
  115. IsWow64Result:= false;
  116. // Try to load required function from kernel32
  117. IsWow64Process := TIsWow64Process(Windows.GetProcAddress(
  118. Windows.GetModuleHandle(kernel32), 'IsWow64Process'
  119. ));
  120. if Assigned(IsWow64Process) then
  121. begin
  122. // Function is implemented: call it
  123. if not IsWow64Process(
  124. Windows.GetCurrentProcess, IsWow64Result
  125. ) then
  126. raise SysUtils.Exception.Create('IsWow64: bad process handle');
  127. // Return result of function
  128. Result := IsWow64Result;
  129. end
  130. else
  131. // Function not implemented: can't be running on Wow64
  132. Result := False;
  133. end;
  134. function IsUserAdmin: BOOL;
  135. var
  136. NTAuthority: SID_IDENTIFIER_AUTHORITY;
  137. AdministratorsGroup: PSID;
  138. begin
  139. Result:= false;
  140. NTAuthority:= SECURITY_NT_AUTHORITY;
  141. AdministratorsGroup:= nil;
  142. Result:= AllocateAndInitializeSid(@NTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, AdministratorsGroup);
  143. if Result then begin
  144. if not CheckTokenMembership(0, AdministratorsGroup, Result) then
  145. Result:= false;
  146. FreeSid(AdministratorsGroup);
  147. end;
  148. end;
  149. function GetVolumePathName(const aFileName: string): string;
  150. begin
  151. SetLength(Result, MAX_PATH + 2);
  152. if not uwinImports.GetVolumePathName(LPCTSTR(aFileName), LPCTSTR(Result),MAX_PATH) then
  153. exit;
  154. SetLength(Result, strlen(PChar(Result)));
  155. end;
  156. function GetVolumeSpace(const aDisk: string; out Total, Free: QWord): Boolean;
  157. var
  158. freequota: QWord;
  159. begin
  160. Result:= GetDiskFreeSpaceEx(PChar(aDisk), @freequota, @Total,@Free);
  161. end;
  162. function GetVolumeSizeIoCtl(const aDisk: string; out Total: QWord): Boolean;
  163. var
  164. dn: string;
  165. fh: THANDLE;
  166. gio: GET_LENGTH_INFORMATION;
  167. ret: dword;
  168. begin
  169. Result:= false;
  170. dn:= '\\.\'+ExcludeTrailingPathDelimiter(aDisk);
  171. fh:= CreateFile(PChar(dn), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  172. if fh = INVALID_HANDLE_VALUE then
  173. exit;
  174. try
  175. if DeviceIoControl(fh, IOCTL_DISK_GET_LENGTH_INFO, nil, 0, @gio, sizeof(gio), @ret, nil) then begin
  176. Total:= gio.Length.QuadPart;
  177. Result:= true;
  178. end;
  179. finally
  180. CloseHandle(fh);
  181. end;
  182. end;
  183. ////////////////////////////////////////////////////////////////////////////////
  184. // Comment : gets the geometry of the disk
  185. // Arguments : hDisk: THandle; var Geometry: DISK_GEOMETRY
  186. // Result : Boolean
  187. function GetDiskGeometry(hDisk: THandle; var Geometry: DISK_GEOMETRY): Boolean;
  188. var
  189. ReturnedBytesCount: DWORD;
  190. begin
  191. result := DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0, @Geometry, sizeof(Geometry), ReturnedBytesCount, nil);
  192. end;
  193. function GetDriveGeometry(DriveLetter: char; var Geometry: DISK_GEOMETRY): Boolean;
  194. var
  195. SrcDrive : string;
  196. hDrive : THandle;
  197. begin
  198. Result:= false;
  199. SrcDrive := '\\.\' + DriveLetter + ':';
  200. // open floppy drive
  201. hDrive := CreateFile(@SrcDrive[1], GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE , nil, OPEN_EXISTING, 0, 0);
  202. if hDrive <> INVALID_HANDLE_VALUE then try
  203. Result:= GetDiskGeometry(hDrive, Geometry);
  204. finally
  205. CloseHandle(hDrive);
  206. end;
  207. end;
  208. function GetVolumeInformation(const aDisk: string; out DriveLabel, Filesystem: string): boolean;
  209. var
  210. dn, fs: array[0..MAX_PATH] of Char;
  211. begin
  212. ZeroMemory(@dn[0], Length(dn));
  213. ZeroMemory(@fs[0], Length(fs));
  214. Result:= Windows.GetVolumeInformation(PChar(aDisk), @dn[0], High(dn), nil, nil, nil, @fs[0], high(fs));
  215. if Result then begin
  216. DriveLabel:= StrPas(dn);
  217. Filesystem:= StrPas(fs);
  218. end;
  219. end;
  220. function GetFileCompressedSize(const aFileName: string; out FSize: QWord): Boolean;
  221. var
  222. li: LARGE_INTEGER;
  223. begin
  224. SetLastError(0);
  225. li.LowPart:= GetCompressedFileSize(LPCSTR(aFileName), @li.HighPart);
  226. Result:= GetLastError = NOERROR;
  227. if Result then
  228. FSize:= li.QuadPart;
  229. end;
  230. function GetFileIndex(const aFilename: string; out FIndex: QWORD): boolean;
  231. var
  232. fh: THANDLE;
  233. bhfi: TBYHANDLEFILEINFORMATION;
  234. fi: LARGE_INTEGER;
  235. begin
  236. Result:= false;
  237. fh:= FileOpen(aFilename, fmOpenRead or fmShareDenyNone);
  238. if fh <> feInvalidHandle then begin
  239. if GetFileInformationByHandle(fh, bhfi) then begin
  240. fi.LowPart:= bhfi.nFileIndexLow;
  241. fi.HighPart:= bhfi.nFileIndexHigh;
  242. FIndex:= fi.QuadPart;
  243. Result:= true;
  244. end;
  245. FileClose(fh);
  246. end;
  247. end;
  248. function GetConfigLocation(const aPortable, aRoaming: boolean; aProgramSubdir: String): string;
  249. begin
  250. if aPortable then
  251. Result:= ExtractFilePath(ParamStr(0))
  252. else begin
  253. if aRoaming then
  254. Result:= IncludeTrailingPathDelimiter(GetWindowsSpecialDir(CSIDL_APPDATA))
  255. else
  256. Result:= IncludeTrailingPathDelimiter(GetWindowsSpecialDir(CSIDL_LOCAL_APPDATA));
  257. if aProgramSubdir > '' then
  258. Result += aProgramSubdir + PathDelim;
  259. end;
  260. end;
  261. function OpenFolderAndSelectFile(const FileName: string): boolean;
  262. {$IFNDEF UTL_WINSUPP_NT50}
  263. var
  264. IIDL: PItemIDList;
  265. begin
  266. result := false;
  267. IIDL := ILCreateFromPath(PChar(FileName));
  268. if IIDL <> nil then
  269. try
  270. result := SHOpenFolderAndSelectItems(IIDL, 0, LPPCITEMIDLIST(nil), 0) = S_OK;
  271. finally
  272. ILFree(IIDL);
  273. end;
  274. {$ELSE}
  275. begin
  276. ShellExecute(0, 'explore', PChar(ExtractFilePath(FileName)), nil, nil, SW_SHOWNORMAL);
  277. {$ENDIF}
  278. end;
  279. end.