winreg.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2022 by Michael van Canneyt and other members of the
  4. Free Pascal development team
  5. Winapi Registry support
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. Const
  13. RegDataWords : Array [TRegDataType] of DWORD
  14. = (REG_NONE,REG_SZ,REG_EXPAND_SZ,REG_BINARY,REG_DWORD,REG_DWORD_BIG_ENDIAN,
  15. REG_LINK,REG_MULTI_SZ,REG_RESOURCE_LIST,REG_FULL_RESOURCE_DESCRIPTOR,REG_RESOURCE_REQUIREMENTS_LIST,REG_QWORD);
  16. type
  17. TWinRegData = record
  18. RootKeyOwned: Boolean;
  19. end;
  20. PWinRegData = ^TWinRegData;
  21. {******************************************************************************
  22. TRegistry
  23. ******************************************************************************}
  24. Procedure TRegistry.SysRegCreate;
  25. begin
  26. FStringSizeIncludesNull:=True;
  27. New(PWinRegData(FSysData));
  28. PWinRegData(FSysData)^.RootKeyOwned := False;
  29. end;
  30. Procedure TRegistry.SysRegfree;
  31. begin
  32. if PWinRegData(FSysData)^.RootKeyOwned and (RootKey <> 0) then
  33. RegCloseKey(RootKey);
  34. Dispose(PWinRegData(FSysData));
  35. end;
  36. Function PrepKey(Const S : UnicodeString) : UnicodeString;
  37. begin
  38. Result := S;
  39. if (Result <> '') and (Result[1] = '\') then
  40. System.Delete(Result, 1, 1);
  41. end;
  42. Function RelativeKey(Const S : UnicodeString) : Boolean;
  43. begin
  44. Result:=(S='') or (S[1]<>'\')
  45. end;
  46. function RegDataWordToRegDataType(RD: DWORD): TRegDataType;
  47. begin
  48. // Test in ascending because rdString is most commonly used
  49. Result := Succ(Low(RegDataWords));
  50. repeat
  51. if RegDataWords[Result] = RD then
  52. Exit;
  53. Inc(Result);
  54. until Result > High(Result);
  55. Result := Low(RegDataWords);
  56. end;
  57. function TRegistry.sysCreateKey(Key: UnicodeString): Boolean;
  58. Var
  59. Disposition: Dword;
  60. Handle: HKEY;
  61. SecurityAttributes: Pointer; //LPSECURITY_ATTRIBUTES;
  62. U: UnicodeString;
  63. begin
  64. SecurityAttributes := Nil;
  65. U:=PrepKey(Key);
  66. FLastError:=RegCreateKeyExW(GetBaseKey(RelativeKey(Key)),
  67. PWideChar(U),
  68. 0,
  69. '',
  70. REG_OPTION_NON_VOLATILE,
  71. FACCESS,
  72. SecurityAttributes,
  73. Handle,
  74. @Disposition);
  75. Result:=FLastError=ERROR_SUCCESS;
  76. RegCloseKey(Handle);
  77. end;
  78. function TRegistry.DeleteKey(const Key: UnicodeString): Boolean;
  79. Var
  80. u: UnicodeString;
  81. subkeys: TUnicodeStringArray;
  82. k, old: HKEY;
  83. i: integer;
  84. begin
  85. old:=fCurrentKey;
  86. k:=GetKey(Key);
  87. if k <> 0 then
  88. begin
  89. fCurrentKey:=k;
  90. try
  91. subkeys:=GetKeyNames;
  92. for i:=0 to High(subkeys) do
  93. begin
  94. Result:=DeleteKey(subkeys[i]);
  95. if not Result then
  96. exit;
  97. end;
  98. finally
  99. fCurrentKey:=old;
  100. CloseKey(k);
  101. end;
  102. end;
  103. u:=PRepKey(Key);
  104. FLastError:=RegDeleteKeyW(GetBaseKey(RelativeKey(Key)),PWideChar(u));
  105. Result:=FLastError=ERROR_SUCCESS;
  106. end;
  107. function TRegistry.DeleteValue(const Name: UnicodeString): Boolean;
  108. begin
  109. FLastError:= RegDeleteValueW(fCurrentKey, PWideChar(Name));
  110. Result:=FLastError=ERROR_SUCCESS;
  111. end;
  112. function TRegistry.SysGetData(const Name: UnicodeString; Buffer: Pointer;
  113. BufSize: Integer; Out RegData: TRegDataType): Integer;
  114. Var
  115. RD : DWord;
  116. begin
  117. FLastError:=RegQueryValueExW(fCurrentKey,PWideChar(Name),Nil,
  118. @RD,Buffer,lpdword(@BufSize));
  119. if (FLastError<>ERROR_SUCCESS) Then
  120. Result:=-1
  121. else
  122. begin
  123. RegData:=RegDataWordToRegDataType(RD);
  124. Result:=BufSize;
  125. end;
  126. end;
  127. function TRegistry.GetDataInfo(const ValueName: UnicodeString; out Value: TRegDataInfo): Boolean;
  128. Var
  129. RD : DWord;
  130. begin
  131. With Value do
  132. begin
  133. FLastError:=RegQueryValueExW(fCurrentKey,PWideChar(ValueName),Nil,@RD,Nil,lpdword(@DataSize));
  134. Result:=FLastError=ERROR_SUCCESS;
  135. if Result then
  136. RegData:=RegDataWordToRegDataType(RD);
  137. end;
  138. If Not Result Then
  139. begin
  140. Value.RegData := rdUnknown;
  141. Value.DataSize := 0
  142. end
  143. end;
  144. function TRegistry.GetKey(Key: UnicodeString): HKEY;
  145. var
  146. Rel : Boolean;
  147. begin
  148. Result:=0;
  149. Rel:=RelativeKey(Key);
  150. if not(Rel) then
  151. Delete(Key,1,1);
  152. {$ifdef WinCE}
  153. FLastError:=RegOpenKeyEx(GetBaseKey(Rel),PWideChar(Key),0,FAccess,Result);
  154. {$else WinCE}
  155. FLastError:=RegOpenKeyExW(GetBaseKey(Rel),PWideChar(Key),0,FAccess,Result);
  156. {$endif WinCE}
  157. end;
  158. function TRegistry.GetKeyInfo(out Value: TRegKeyInfo): Boolean;
  159. var
  160. winFileTime: Windows.FILETIME;
  161. sysTime: TSystemTime;
  162. LocalFileTime: Windows.FILETIME;
  163. begin
  164. FillChar(Value, SizeOf(Value), 0);
  165. With Value do
  166. begin
  167. FLastError:=RegQueryInfoKeyA(CurrentKey,nil,nil,nil,lpdword(@NumSubKeys),
  168. lpdword(@MaxSubKeyLen),nil,lpdword(@NumValues),lpdword(@MaxValueLen),
  169. lpdword(@MaxDataLen),nil,@winFileTime);
  170. Result:=FLastError=ERROR_SUCCESS;
  171. end;
  172. if Result and FileTimeToLocalFileTime(@winFileTime, @LocalFileTime) and
  173. FileTimeToSystemTime(@LocalFileTime, @sysTime) then
  174. begin
  175. Value.FileTime := SystemTimeToDateTime(sysTime);
  176. end;
  177. end;
  178. function TRegistry.KeyExists(const Key: UnicodeString): Boolean;
  179. var
  180. KeyHandle : HKEY;
  181. OldAccess : LONG;
  182. begin
  183. Result:=false;
  184. OldAccess:=FAccess;
  185. try
  186. FAccess:=KEY_QUERY_VALUE or KEY_ENUMERATE_SUB_KEYS or STANDARD_RIGHTS_READ
  187. {$ifndef WinCE} or (OldAccess and (KEY_WOW64_64KEY or KEY_WOW64_32KEY)) {$endif};
  188. KeyHandle:=GetKey(Key);
  189. if KeyHandle<>0 then
  190. begin
  191. RegCloseKey(KeyHandle);
  192. Result:=true;
  193. end;
  194. finally
  195. FAccess:=OldAccess;
  196. end;
  197. end;
  198. function TRegistry.LoadKey(const Key, FileName: UnicodeString): Boolean;
  199. begin
  200. Result := False;
  201. end;
  202. function TRegistry.OpenKey(const Key: UnicodeString; CanCreate: Boolean): Boolean;
  203. Var
  204. u, S: UnicodeString;
  205. Handle: HKEY;
  206. Disposition: Integer;
  207. SecurityAttributes: Pointer; //LPSECURITY_ATTRIBUTES;
  208. begin
  209. SecurityAttributes := Nil;
  210. u:=PrepKey(Key);
  211. If CanCreate then
  212. begin
  213. Handle:=0;
  214. FLastError:=RegCreateKeyExW(GetBaseKey(RelativeKey(Key)),PWideChar(u),0,'',
  215. REG_OPTION_NON_VOLATILE,
  216. fAccess,SecurityAttributes,Handle,
  217. pdword(@Disposition));
  218. Result:=FLastError=ERROR_SUCCESS;
  219. end
  220. else
  221. begin
  222. FLastError:=RegOpenKeyExW(GetBaseKey(RelativeKey(Key)),
  223. PWideChar(u),0,fAccess,Handle);
  224. Result:=FLastError=ERROR_SUCCESS;
  225. end;
  226. If Result then begin
  227. if RelativeKey(Key) then
  228. begin
  229. if (Key>'') and (CurrentPath>'') and (CurrentPath[Length(CurrentPath)]<>'\') then
  230. S:=CurrentPath + '\' + Key
  231. else
  232. S:=CurrentPath + Key;
  233. end else
  234. S:=u;
  235. ChangeKey(Handle, S);
  236. end;
  237. end;
  238. function TRegistry.OpenKeyReadOnly(const Key: UnicodeString): Boolean;
  239. Var
  240. OldAccess: LongWord;
  241. begin
  242. OldAccess:=fAccess;
  243. fAccess:=KEY_READ {$ifndef WinCE} or (OldAccess and (KEY_WOW64_64KEY or KEY_WOW64_32KEY)) {$endif};
  244. try
  245. Result:=OpenKey(Key, False);
  246. finally
  247. fAccess:=OldAccess;
  248. end;
  249. end;
  250. function TRegistry.RegistryConnect(const UNCName: UnicodeString): Boolean;
  251. {$ifndef WinCE}
  252. var
  253. newroot: HKEY;
  254. {$endif}
  255. begin
  256. {$ifdef WinCE}
  257. Result:=False;
  258. {$else}
  259. FLastError:=RegConnectRegistryW(PWideChar(UNCName),RootKey,newroot);
  260. Result:=FLastError=ERROR_SUCCESS;
  261. if Result then begin
  262. RootKey:=newroot;
  263. PWinRegData(FSysData)^.RootKeyOwned:=True;
  264. end;
  265. {$endif}
  266. end;
  267. function TRegistry.ReplaceKey(const Key, FileName, BackUpFileName: UnicodeString): Boolean;
  268. begin
  269. Result := False;
  270. end;
  271. function TRegistry.RestoreKey(const Key, FileName: UnicodeString): Boolean;
  272. begin
  273. Result := False;
  274. end;
  275. function TRegistry.SaveKey(const Key, FileName: UnicodeString): Boolean;
  276. begin
  277. Result := False;
  278. end;
  279. function TRegistry.UnLoadKey(const Key: UnicodeString): Boolean;
  280. begin
  281. Result := false;
  282. end;
  283. function TRegistry.ValueExists(const Name: UnicodeString): Boolean;
  284. var
  285. Info : TRegDataInfo;
  286. begin
  287. Result:=GetDataInfo(Name,Info);
  288. end;
  289. procedure TRegistry.CloseKey;
  290. begin
  291. If (CurrentKey<>0) then
  292. begin
  293. if LazyWrite then
  294. RegCloseKey(CurrentKey)
  295. else
  296. RegFlushKey(CurrentKey);
  297. fCurrentKey:=0;
  298. end;
  299. fCurrentPath:='';
  300. end;
  301. procedure TRegistry.CloseKey(key:HKEY);
  302. begin
  303. RegCloseKey(key);
  304. end;
  305. procedure TRegistry.ChangeKey(Value: HKey; const Path: UnicodeString);
  306. begin
  307. CloseKey;
  308. FCurrentKey:=Value;
  309. FCurrentPath:=FixPath(Path);
  310. end;
  311. function TRegistry.GetKeyNames: TUnicodeStringArray;
  312. var
  313. Info: TRegKeyInfo;
  314. dwLen: DWORD;
  315. lpName: LPWSTR;
  316. dwIndex: DWORD;
  317. lResult: LONGINT;
  318. u: UnicodeString;
  319. begin
  320. Result:=nil;
  321. if GetKeyInfo(Info) and (Info.NumSubKeys > 0) then
  322. begin
  323. dwLen:=Info.MaxSubKeyLen+1;
  324. GetMem(lpName,dwLen*SizeOf(WideChar));
  325. try
  326. //writeln('TRegistry.GetKeyNames: Info.NumSubKeys=',Info.NumSubKeys);
  327. SetLength(Result, Info.NumSubKeys);
  328. for dwIndex:=0 to Info.NumSubKeys-1 do
  329. begin
  330. dwLen:=Info.MaxSubKeyLen+1;
  331. lResult:=RegEnumKeyExW(CurrentKey,dwIndex,lpName,dwLen,Nil,Nil,Nil,Nil);
  332. if lResult=ERROR_NO_MORE_ITEMS then
  333. Break;
  334. if lResult<>ERROR_SUCCESS then
  335. raise ERegistryException.Create(SysErrorMessage(lResult));
  336. if dwLen=0 then
  337. u:=''
  338. else
  339. begin // dwLen>0
  340. u:=lpName;
  341. end; // if dwLen=0
  342. Result[dwIndex]:=u;
  343. end; // for dwIndex:=0 ...
  344. finally
  345. FreeMem(lpName);
  346. end;
  347. end;
  348. end;
  349. Function TRegistry.GetValueNames: TUnicodeStringArray;
  350. var
  351. Info: TRegKeyInfo;
  352. dwLen: DWORD;
  353. lpName: LPWSTR;
  354. dwIndex: DWORD;
  355. lResult: LONGINT;
  356. u: UnicodeString;
  357. begin
  358. Result:=nil;
  359. if GetKeyInfo(Info) and (Info.NumValues > 0) then
  360. begin
  361. dwLen:=Info.MaxValueLen+1;
  362. GetMem(lpName,dwLen*SizeOf(WideChar));
  363. try
  364. SetLength(Result, Info.NumValues);
  365. for dwIndex:=0 to Info.NumValues-1 do
  366. begin
  367. dwLen:=Info.MaxValueLen+1;
  368. lResult:=RegEnumValueW(CurrentKey,dwIndex,lpName,dwLen,Nil,Nil,Nil,Nil);
  369. if lResult=ERROR_NO_MORE_ITEMS then
  370. Break;
  371. if lResult<>ERROR_SUCCESS then
  372. raise ERegistryException.Create(SysErrorMessage(lResult));
  373. if dwLen=0 then
  374. u:=''
  375. else
  376. begin // dwLen>0
  377. u:=lpName;
  378. end; // if dwLen=0
  379. Result[dwIndex]:=u;
  380. end; // for dwIndex:=0 ...
  381. finally
  382. FreeMem(lpName);
  383. end;
  384. end;
  385. end;
  386. Function TRegistry.SysPutData(const Name: UnicodeString; Buffer: Pointer;
  387. BufSize: Integer; RegData: TRegDataType) : Boolean;
  388. Var
  389. RegDataType: DWORD;
  390. begin
  391. RegDataType:=RegDataWords[RegData];
  392. FLastError:=RegSetValueExW(fCurrentKey,PWideChar(Name),0,RegDataType,Buffer,BufSize);
  393. Result:=FLastError=ERROR_SUCCESS;
  394. end;
  395. procedure TRegistry.RenameValue(const OldName, NewName: UnicodeString);
  396. var
  397. L: Integer;
  398. InfoO,InfoN : TRegDataInfo;
  399. D : TRegDataType;
  400. P: PChar;
  401. begin
  402. If GetDataInfo(OldName,InfoO) and Not GetDataInfo(NewName,InfoN) then
  403. begin
  404. L:=InfoO.DataSize;
  405. if L>0 then
  406. begin
  407. GetMem(P,L);
  408. try
  409. L:=GetData(OldName,P,L,D);
  410. If SysPutData(NewName,P,L,D) then
  411. DeleteValue(OldName);
  412. finally
  413. FreeMem(P);
  414. end;
  415. end;
  416. end;
  417. end;
  418. procedure TRegistry.SetCurrentKey(Value: HKEY);
  419. begin
  420. fCurrentKey := Value;
  421. end;
  422. procedure TRegistry.SetRootKey(Value: HKEY);
  423. begin
  424. if fRootKey = Value then
  425. Exit;
  426. { close a root key that was opened using RegistryConnect }
  427. if PWinRegData(FSysData)^.RootKeyOwned and (fRootKey <> 0) then begin
  428. RegCloseKey(fRootKey);
  429. PWinRegData(FSysData)^.RootKeyOwned := False;
  430. end;
  431. fRootKey := Value;
  432. end;
  433. function TRegistry.GetLastErrorMsg: string;
  434. begin
  435. if FLastError <> ERROR_SUCCESS then
  436. Result:=SysErrorMessage(FLastError)
  437. else
  438. Result:='';
  439. end;