xregreg.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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. XML Registry aux 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. { ---------------------------------------------------------------------
  13. System dependent Registry implementation - using XML file.
  14. ---------------------------------------------------------------------}
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. uses System.TypInfo, System.Xmlreg;
  17. {$ELSE FPC_DOTTEDUNITS}
  18. uses typinfo, xmlreg;
  19. {$ENDIF FPC_DOTTEDUNITS}
  20. Const
  21. XFileName = 'reg.xml';
  22. Resourcestring
  23. SErrTypeNotSupported = 'Registry data type not supported on this platform: %s';
  24. Function RegDataTypeToXmlDataType(RegData : TRegDataType) : TDataType;
  25. begin
  26. Case RegData of
  27. rdUnknown : Result := dtUnknown;
  28. rdString,rdExpandString : Result := dtString;
  29. rdInteger : Result := dtDword;
  30. rdBinary : Result := dtBinary;
  31. rdMultiString : Result := dtStrings;
  32. rdInt64 : Result := dtQword;
  33. else
  34. Raise ERegistryException.CreateFmt(SErrTypeNotSupported,[GetEnumName(TypeInfo(TRegDataType),Ord(RegData))]);
  35. end;
  36. end;
  37. Function DataTypeToRegDataType(DataType : TDataType) : TRegDataType;
  38. begin
  39. Case DataType of
  40. dtUnknown: Result:=rdUnknown;
  41. dtDword : Result:=rdInteger;
  42. dtQword : Result:=rdInt64;
  43. dtString : Result:=rdString;
  44. dtBinary : Result:=rdBinary;
  45. dtStrings : Result:=rdMultiString;
  46. end;
  47. end;
  48. Function RootKeyToRootKeyStr(Value: HKEY): UnicodeString;
  49. begin
  50. Case Value of
  51. HKEY_CLASSES_ROOT : Result := 'HKEY_CLASSES_ROOT';
  52. HKEY_CURRENT_USER : Result := 'HKEY_CURRENT_USER';
  53. HKEY_LOCAL_MACHINE : Result := 'HKEY_LOCAL_MACHINE';
  54. HKEY_USERS : Result := 'HKEY_USERS';
  55. HKEY_PERFORMANCE_DATA : Result := 'HKEY_PERFORMANCE_DATA';
  56. HKEY_CURRENT_CONFIG : Result := 'HKEY_CURRENT_CONFIG';
  57. HKEY_DYN_DATA : Result := 'HKEY_DYN_DATA';
  58. else
  59. Result:=Format('Key%d',[Value]);
  60. end;
  61. end;
  62. type
  63. { TXMLRegistryInstance }
  64. TXMLRegistryInstance = class(TXMLRegistry)
  65. private
  66. FRefCount: integer;
  67. Class Var XMLRegistryCache: Tlist;
  68. Class procedure FreeXMLRegistryCache;
  69. public
  70. constructor Create(AFileName : String);
  71. Class Function GetXMLRegistry(aFileName: string): TXMLRegistry;
  72. Class Procedure FreeXMLRegistry(XMLRegistry: TXMLRegistry);
  73. procedure IncRefCount;
  74. procedure DecRefCount;
  75. property RefCount: integer read FRefCount;
  76. end;
  77. Class function TXMLRegistryInstance.GetXMLRegistry(aFileName: string): TXMLRegistry;
  78. var i: integer;
  79. begin
  80. if not assigned(XMLRegistryCache) then
  81. XMLRegistryCache := TList.Create;
  82. for i := 0 to XMLRegistryCache.Count - 1 do
  83. if TXMLRegistryInstance(XMLRegistryCache[i]).FileName = aFileName then
  84. begin
  85. TXMLRegistryInstance(XMLRegistryCache[i]).IncRefCount;
  86. Result := TXMLRegistry(XMLRegistryCache[i]);
  87. Exit;
  88. end;
  89. Result := TXMLRegistryInstance.Create(aFileName);
  90. XMLRegistryCache.Add(Result);
  91. end;
  92. Class procedure TXMLRegistryInstance.FreeXMLRegistry(XMLRegistry: TXMLRegistry);
  93. begin
  94. TXMLRegistryInstance(XMLRegistry).DecRefCount;
  95. if TXMLRegistryInstance(XMLRegistry).RefCount = 0 then
  96. begin
  97. XMLRegistryCache.Remove(XMLRegistry);
  98. XMLRegistry.Free;
  99. end;
  100. end;
  101. class procedure TXMLRegistryInstance.FreeXMLRegistryCache;
  102. var i: integer;
  103. begin
  104. if not Assigned(XMLRegistryCache) then
  105. exit;
  106. for i := 0 to XMLRegistryCache.Count - 1 do
  107. TXMLRegistryInstance(XMLRegistryCache[i]).Free;
  108. FreeAndNil(XMLRegistryCache);
  109. end;
  110. { TXMLRegistryInstance }
  111. constructor TXMLRegistryInstance.Create(AFileName: String);
  112. begin
  113. inherited;
  114. FRefCount := 1;
  115. end;
  116. procedure TXMLRegistryInstance.IncRefCount;
  117. begin
  118. Inc(FRefCount);
  119. end;
  120. procedure TXMLRegistryInstance.DecRefCount;
  121. begin
  122. Dec(FRefCount);
  123. end;
  124. procedure useKeyFromTRegistryInstance(reg: TRegistry);
  125. var XmlRegistry: TXMLRegistry;
  126. RootKeyStr: UnicodeString;
  127. begin
  128. XmlRegistry:=TXMLRegistry(reg.FSysData);
  129. RootKeyStr:=RootKeyToRootKeyStr(reg.RootKey);
  130. // '/' at the end when comparing
  131. if (reg.CurrentKey=0) and (UnicodeCompareText(XmlRegistry.RootKey, RootKeyStr + '/')<>0) then
  132. XmlRegistry.SetRootKey(RootKeyStr)
  133. else
  134. begin
  135. if UnicodeCompareText(XmlRegistry.CurrentKey, RootKeyStr+'/'+reg.CurrentPath + '/')<>0 then
  136. begin
  137. XmlRegistry.SetRootKey(RootKeyStr);
  138. XmlRegistry.SetKey(reg.CurrentPath, false);
  139. end;
  140. end;
  141. end;
  142. procedure TRegistry.SysRegCreate;
  143. var s : string;
  144. begin
  145. FStringSizeIncludesNull:=False;
  146. s:=includetrailingpathdelimiter(GetAppConfigDir(GlobalXMLFile));
  147. if VendorXMLFile and (VendorName <> '') and (ApplicationName <> '') then
  148. s:= Copy(s, 1, Length(s)-Length(ApplicationName)-1);
  149. {$ifdef XMLRegfile_in_CurDir}
  150. s:='.' + PathDelim;
  151. {$endif}
  152. ForceDirectories(s);
  153. FSysData:=TXMLRegistryInstance.GetXMLRegistry(s+XFileName);
  154. TXmlRegistry(FSysData).AutoFlush:=False;
  155. end;
  156. procedure TRegistry.SysRegFree;
  157. begin
  158. if Assigned(FSysData) then
  159. begin
  160. TXMLRegistry(FSysData).Flush;
  161. TXMLRegistryInstance.FreeXMLRegistry(TXMLRegistry(FSysData));
  162. end;
  163. end;
  164. function TRegistry.SysCreateKey(Key: UnicodeString): Boolean;
  165. begin
  166. useKeyFromTRegistryInstance(self);
  167. Result:=TXmlRegistry(FSysData).CreateKey(Key);
  168. end;
  169. function TRegistry.DeleteKey(const Key: UnicodeString): Boolean;
  170. begin
  171. useKeyFromTRegistryInstance(self);
  172. Result:=TXMLRegistry(FSysData).DeleteKey(Key);
  173. end;
  174. function TRegistry.DeleteValue(const Name: UnicodeString): Boolean;
  175. begin
  176. useKeyFromTRegistryInstance(self);
  177. Result:=TXmlRegistry(FSysData).DeleteValue(Name);
  178. end;
  179. function TRegistry.SysGetData(const Name: UnicodeString; Buffer: Pointer;
  180. BufSize: Integer; Out RegData: TRegDataType): Integer;
  181. Var
  182. DataType : TDataType;
  183. begin
  184. useKeyFromTRegistryInstance(self);
  185. Result:=BufSize;
  186. If TXmlregistry(FSysData).GetValueDataUnicode(Name,DataType,Buffer^,Result) then
  187. RegData:=DataTypeToRegDataType(DataType)
  188. else
  189. Result:=-1;
  190. end;
  191. function TRegistry.GetDataInfo(const ValueName: UnicodeString; out Value: TRegDataInfo): Boolean;
  192. Var
  193. Info : TDataInfo;
  194. begin
  195. useKeyFromTRegistryInstance(self);
  196. Result := TXmlRegistry(FSysData).GetValueInfo(ValueName,Info,True);
  197. If Not Result then
  198. With Value do
  199. begin
  200. RegData:=rdunknown;
  201. DataSize:=0;
  202. end
  203. else
  204. With Value do
  205. begin
  206. RegData:=DataTypeToRegDataType(Info.DataType);
  207. DataSize:=Info.DataSize;
  208. end;
  209. end;
  210. function TRegistry.GetKey(Key: UnicodeString): HKEY;
  211. begin
  212. Result := 0;
  213. end;
  214. function TRegistry.GetKeyInfo(Out Value: TRegKeyInfo): Boolean;
  215. Var
  216. Info : TKeyInfo;
  217. begin
  218. useKeyFromTRegistryInstance(self);
  219. Result:=TXmlRegistry(FSysData).GetKeyInfo(info);
  220. If Result then
  221. With Value,Info do
  222. begin
  223. NumSubKeys:=SubKeys;
  224. MaxSubKeyLen:=SubKeyLen;
  225. NumValues:= Values;
  226. MaxValueLen:=ValueLen;
  227. MaxDataLen:=DataLen;
  228. FileTime:=FTime;
  229. end;
  230. end;
  231. function TRegistry.KeyExists(const Key: UnicodeString): Boolean;
  232. begin
  233. useKeyFromTRegistryInstance(self);
  234. Result:=TXmlRegistry(FSysData).KeyExists(Key);
  235. end;
  236. function TRegistry.LoadKey(const Key, FileName: UnicodeString): Boolean;
  237. begin
  238. Result := False;
  239. end;
  240. function TRegistry.OpenKey(const Key: UnicodeString; CanCreate: Boolean): Boolean;
  241. var
  242. S: UnicodeString;
  243. P: SizeInt;
  244. begin
  245. useKeyFromTRegistryInstance(self);
  246. Result:=TXmlRegistry(FSysData).SetKey(Key,CanCreate);
  247. If Result then begin
  248. fCurrentKey:=1;
  249. S:=TXmlRegistry(FSysData).CurrentKey;
  250. if (S>'') then begin
  251. //S starts with RootKey+'/'
  252. P:=Pos('/',S);
  253. if (P>0) then
  254. System.Delete(S,1,P);
  255. end;
  256. ChangeKey(fCurrentKey, S);
  257. end;
  258. end;
  259. function TRegistry.OpenKeyReadOnly(const Key: UnicodeString): Boolean;
  260. begin
  261. Result:=OpenKey(Key,False);
  262. end;
  263. function TRegistry.RegistryConnect(const UNCName: UnicodeString): Boolean;
  264. begin
  265. Result := True;
  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. begin
  285. useKeyFromTRegistryInstance(self);
  286. Result := TXmlRegistry(FSysData).ValueExists(Name);
  287. end;
  288. procedure TRegistry.ChangeKey(Value: HKey; const Path: UnicodeString);
  289. begin
  290. FCurrentPath:=FixPath(Path);
  291. end;
  292. function TRegistry.GetKeyNames: TUnicodeStringArray;
  293. begin
  294. useKeyFromTRegistryInstance(self);
  295. Result:=TXmlRegistry(FSysData).EnumSubKeys;
  296. end;
  297. function TRegistry.GetValueNames: TUnicodeStringArray;
  298. begin
  299. useKeyFromTRegistryInstance(self);
  300. Result := TXmlRegistry(FSysData).EnumValues;
  301. end;
  302. function TRegistry.SysPutData(const Name: UnicodeString; Buffer: Pointer;
  303. BufSize: Integer; RegData: TRegDataType): Boolean;
  304. Var
  305. DataType : TDataType;
  306. begin
  307. useKeyFromTRegistryInstance(self);
  308. //writeln('TRegistry.SysPutData: Name=',Name,', RegData=',RegData,', BufSize=',BufSize);
  309. DataType:=RegDataTypeToXmlDataType(RegData);
  310. Result:=TXMLRegistry(FSysData).SetValueDataUnicode(Name,DataType,Buffer^,BufSize);
  311. end;
  312. procedure TRegistry.RenameValue(const OldName, NewName: UnicodeString);
  313. begin
  314. useKeyFromTRegistryInstance(self);
  315. TXMLRegistry(FSysData).RenameValue(OldName,NewName);
  316. end;
  317. procedure TRegistry.SetCurrentKey(Value: HKEY);
  318. begin
  319. fCurrentKey := Value;
  320. end;
  321. procedure TRegistry.SetRootKey(Value: HKEY);
  322. Var
  323. S: UnicodeString;
  324. begin
  325. S:=RootKeyToRootKeyStr(Value);
  326. TXmlRegistry(FSysData).SetRootKey(S);
  327. fRootKey := Value;
  328. fCurrentKey:=0;
  329. FCurrentPath:='';
  330. end;
  331. function TRegistry.GetLastErrorMsg: string;
  332. begin
  333. Result:='';
  334. end;
  335. procedure TRegistry.CloseKey;
  336. begin
  337. // CloseKey is called from destructor, which includes cases of failed construction.
  338. // FSysData may be unassigned at this point.
  339. if Assigned(FSysData) then
  340. begin
  341. TXMLRegistry(FSysData).Flush;
  342. TXMLRegistry(FSysData).SetRootKey(TXMLRegistry(FSysData).RootKey);
  343. fCurrentKey:=0;
  344. FCurrentPath:='';
  345. end;
  346. end;
  347. procedure TRegistry.CloseKey(key:HKEY);
  348. begin
  349. if Assigned(FSysData) then
  350. begin
  351. TXMLRegistry(FSysData).Flush;
  352. TXMLRegistry(FSysData).SetRootKey(TXMLRegistry(FSysData).RootKey);
  353. fCurrentKey:=0;
  354. FCurrentPath:='';
  355. end;
  356. end;