1Unit Registry;
2
3{$mode objfpc}
4{$H+}
5
6interface
7
8{$ifndef windows}
9{$define XMLREG}
10{$endif}
11
12Uses
13  {$ifndef XMLREG}
14    Windows,
15  {$endif XMLREG}
16    Classes,
17    SysUtils,
18    inifiles;
19
20{$I regdef.inc}
21
22type
23  ERegistryException = class(Exception);
24
25  TRegKeyInfo = record
26    NumSubKeys: Integer;
27    MaxSubKeyLen: Integer;
28    NumValues: Integer;
29    MaxValueLen: Integer;
30    MaxDataLen: Integer;
31    FileTime: TDateTime;
32  end;
33
34  TRegDataType = (rdUnknown, rdString, rdExpandString, rdBinary, rdInteger, rdIntegerBigEndian,
35                  rdLink, rdMultiString, rdResourceList, rdFullResourceDescriptor,  rdResourceRequirementList, rdInt64);
36
37  TRegDataInfo = record
38    RegData: TRegDataType;
39    DataSize: Integer;
40  end;
41
42  TUnicodeStringArray = Array of UnicodeString;
43
44{ ---------------------------------------------------------------------
45    TRegistry
46  ---------------------------------------------------------------------}
47
48  { TRegistry }
49
50  TRegistry = class(TObject)
51  private
52    FLastError: Longint;
53    FStringSizeIncludesNull : Boolean;
54    FSysData : Pointer;
55    fAccess: LongWord;
56    fCurrentKey: HKEY;
57    fRootKey: HKEY;
58    fLazyWrite: Boolean;
59    fCurrentPath: UnicodeString;
60    function FixPath(APath: UnicodeString): UnicodeString;
61    function GetLastErrorMsg: string;
62    function RegMultiSzDataToUnicodeStringArray(U: UnicodeString): TUnicodeStringArray;
63    function ListToArray(List: TStrings; IsUtf8: Boolean): TUnicodeStringArray;
64    procedure ArrayToList(const Arr: TUnicodeStringArray; List: TStrings; ForceUtf8: Boolean);
65    procedure SetRootKey(Value: HKEY);
66    Procedure SysRegCreate;
67    Procedure SysRegFree;
68    Function  SysGetData(const Name: UnicodeString; Buffer: Pointer; BufSize: Integer; Out RegData: TRegDataType): Integer;
69    Function  SysPutData(const Name: UnicodeString; Buffer: Pointer; BufSize: Integer; RegData: TRegDataType) : Boolean;
70    Function  SysCreateKey(Key: UnicodeString): Boolean;
71  protected
72    function GetBaseKey(Relative: Boolean): HKey;
73    function GetData(const Name: UnicodeString; Buffer: Pointer;
74                  BufSize: Integer; Out RegData: TRegDataType): Integer;
75    function GetData(const Name: String; Buffer: Pointer;
76                  BufSize: Integer; Out RegData: TRegDataType): Integer;
77    function GetKey(Key: UnicodeString): HKEY;
78    function GetKey(Key: String): HKEY;
79    procedure ChangeKey(Value: HKey; const Path: UnicodeString);
80    procedure ChangeKey(Value: HKey; const Path: String);
81    procedure PutData(const Name: UnicodeString; Buffer: Pointer;
82                  BufSize: Integer; RegData: TRegDataType);
83    procedure PutData(const Name: String; Buffer: Pointer;
84                  BufSize: Integer; RegData: TRegDataType);
85    procedure SetCurrentKey(Value: HKEY);
86  public
87    constructor Create; overload;
88    constructor Create(aaccess:longword); overload;
89    destructor Destroy; override;
90
91    function CreateKey(const Key: UnicodeString): Boolean;
92    function CreateKey(const Key: String): Boolean;
93    function DeleteKey(const Key: UnicodeString): Boolean;
94    function DeleteKey(const Key: String): Boolean;
95    function DeleteValue(const Name: UnicodeString): Boolean;
96    function DeleteValue(const Name: String): Boolean;
97    function GetDataInfo(const ValueName: UnicodeString; Out Value: TRegDataInfo): Boolean;
98    function GetDataInfo(const ValueName: String; Out Value: TRegDataInfo): Boolean;
99    function GetDataSize(const ValueName: UnicodeString): Integer;
100    function GetDataSize(const ValueName: String): Integer;
101    function GetDataType(const ValueName: UnicodeString): TRegDataType;
102    function GetDataType(const ValueName: String): TRegDataType;
103    function GetKeyInfo(Out Value: TRegKeyInfo): Boolean;
104    function HasSubKeys: Boolean;
105    function KeyExists(const Key: UnicodeString): Boolean;
106    function KeyExists(const Key: String): Boolean;
107    function LoadKey(const Key, FileName: UnicodeString): Boolean;  unimplemented;
108    function LoadKey(const Key, FileName: String): Boolean;  unimplemented;
109    function OpenKey(const Key: UnicodeString; CanCreate: Boolean): Boolean;
110    function OpenKey(const Key: String; CanCreate: Boolean): Boolean;
111    function OpenKeyReadOnly(const Key: UnicodeString): Boolean;
112    function OpenKeyReadOnly(const Key: String): Boolean;
113    function ReadCurrency(const Name: UnicodeString): Currency;
114    function ReadCurrency(const Name: String): Currency;
115    function ReadBinaryData(const Name: UnicodeString; var Buffer; BufSize: Integer): Integer;
116    function ReadBinaryData(const Name: String; var Buffer; BufSize: Integer): Integer;
117    function ReadBool(const Name: UnicodeString): Boolean;
118    function ReadBool(const Name: String): Boolean;
119    function ReadDate(const Name: UnicodeString): TDateTime;
120    function ReadDate(const Name: String): TDateTime;
121    function ReadDateTime(const Name: UnicodeString): TDateTime;
122    function ReadDateTime(const Name: String): TDateTime;
123    function ReadFloat(const Name: UnicodeString): Double;
124    function ReadFloat(const Name: String): Double;
125    function ReadInteger(const Name: UnicodeString): Integer;
126    function ReadInteger(const Name: String): Integer;
127    function ReadInt64(const Name: UnicodeString): Int64;
128    function ReadInt64(const Name: String): Int64;
129    function ReadString(const Name: UnicodeString): UnicodeString;
130    function ReadString(const Name: String): string;
131    procedure ReadStringList(const Name: UnicodeString; AList: TStrings; ForceUtf8: Boolean=False);
132    procedure ReadStringList(const Name: String; AList: TStrings);
133    function ReadStringArray(const Name: UnicodeString): TUnicodeStringArray;
134    function ReadStringArray(const Name: String): TStringArray;
135    function ReadTime(const Name: UnicodeString): TDateTime;
136    function ReadTime(const Name: String): TDateTime;
137    function RegistryConnect(const UNCName: UnicodeString): Boolean;
138    function RegistryConnect(const UNCName: String): Boolean;
139    function ReplaceKey(const Key, FileName, BackUpFileName: UnicodeString): Boolean; unimplemented;
140    function ReplaceKey(const Key, FileName, BackUpFileName: String): Boolean;  unimplemented;
141    function RestoreKey(const Key, FileName: UnicodeString): Boolean;  unimplemented;
142    function RestoreKey(const Key, FileName: String): Boolean;  unimplemented;
143    function SaveKey(const Key, FileName: UnicodeString): Boolean;
144    function SaveKey(const Key, FileName: String): Boolean;
145    function UnLoadKey(const Key: UnicodeString): Boolean;
146    function UnLoadKey(const Key: String): Boolean;
147    function ValueExists(const Name: UnicodeString): Boolean;
148    function ValueExists(const Name: String): Boolean;
149
150    procedure CloseKey;
151    procedure CloseKey(key:HKEY);
152    procedure GetKeyNames(Strings: TStrings);
153    function GetKeyNames: TUnicodeStringArray;
154    procedure GetValueNames(Strings: TStrings);
155    //ToDo
156    function GetValueNames: TUnicodeStringArray;
157    procedure MoveKey(const OldName, NewName: UnicodeString; Delete: Boolean);  unimplemented;
158    procedure MoveKey(const OldName, NewName: String; Delete: Boolean);  unimplemented;
159    procedure RenameValue(const OldName, NewName: UnicodeString);
160    procedure RenameValue(const OldName, NewName: String);
161    procedure WriteCurrency(const Name: UnicodeString; Value: Currency);
162    procedure WriteCurrency(const Name: String; Value: Currency);
163    procedure WriteBinaryData(const Name: UnicodeString; const Buffer; BufSize: Integer);
164    procedure WriteBinaryData(const Name: String; const Buffer; BufSize: Integer);
165    procedure WriteBool(const Name: UnicodeString; Value: Boolean);
166    procedure WriteBool(const Name: String; Value: Boolean);
167    procedure WriteDate(const Name: UnicodeString; Value: TDateTime);
168    procedure WriteDate(const Name: String; Value: TDateTime);
169    procedure WriteDateTime(const Name: UnicodeString; Value: TDateTime);
170    procedure WriteDateTime(const Name: String; Value: TDateTime);
171    procedure WriteFloat(const Name: UnicodeString; Value: Double);
172    procedure WriteFloat(const Name: String; Value: Double);
173    procedure WriteInteger(const Name: UnicodeString; Value: Integer);
174    procedure WriteInteger(const Name: String; Value: Integer);
175    procedure WriteInt64(const Name: UnicodeString; Value: Int64);
176    procedure WriteInt64(const Name: String; Value: Int64);
177    procedure WriteString(const Name, Value: UnicodeString);
178    procedure WriteString(const Name, Value: String);
179    procedure WriteExpandString(const Name, Value: UnicodeString);
180    procedure WriteExpandString(const Name, Value: String);
181    procedure WriteStringList(const Name: UnicodeString; List: TStrings; IsUtf8: Boolean=False);
182    procedure WriteStringArray(const Name: UnicodeString; const Arr: TUnicodeStringArray);
183    procedure WriteStringArray(const Name: String; const Arr: TStringArray);
184    procedure WriteTime(const Name: UnicodeString; Value: TDateTime);
185    procedure WriteTime(const Name: String; Value: TDateTime);
186
187    property Access: LongWord read fAccess write fAccess;
188    property CurrentKey: HKEY read fCurrentKey;
189    property CurrentPath: UnicodeString read fCurrentPath;
190    property LazyWrite: Boolean read fLazyWrite write fLazyWrite;
191    property RootKey: HKEY read fRootKey write SetRootKey;
192    Property StringSizeIncludesNull : Boolean read FStringSizeIncludesNull;
193    property LastError: Longint read FLastError; platform;
194    property LastErrorMsg: string read GetLastErrorMsg; platform;
195  end;
196
197{ ---------------------------------------------------------------------
198    TRegIniFile
199  ---------------------------------------------------------------------}
200  TRegIniFile = class(TRegistry)
201  private
202    fFileName          : String;
203    fPath              : String;
204    fPreferStringValues: Boolean;
205    function OpenSection(const Section: string; CreateSection : Boolean = false): boolean;
206    procedure CloseSection;
207  public
208    constructor Create(const FN: string); overload;
209    constructor Create(const FN: string;aaccess:longword); overload;
210    function ReadString(const Section, Ident, Default: string): string;
211    function ReadInteger(const Section, Ident: string; Default: Longint): Longint;
212    function ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
213    function ReadDate(const Section, Ident: string; Default: TDateTime):TDateTime;
214    function ReadDateTime(const Section, Ident: string; Default: TDateTime):TDateTime;
215    function ReadTime(const Section, Ident: string; Default: TDateTime):TDateTime;
216    function ReadFloat(const Section, Ident: string; Default: Double): Double;
217
218    procedure WriteString(const Section, Ident, Value: String);
219    procedure WriteInteger(const Section, Ident: string; Value: Longint);
220    procedure WriteBool(const Section, Ident: string; Value: Boolean);
221    procedure WriteDate(const Section, Ident: string; Value: TDateTime);
222    procedure WriteDateTime(const Section, Ident: string; Value: TDateTime);
223    procedure WriteTime(const Section, Ident: string; Value: TDateTime);
224    procedure WriteFloat(const Section, Ident: string; Value: Double);
225    procedure ReadSection(const Section: string; Strings: TStrings);
226    procedure ReadSections(Strings: TStrings);
227    procedure ReadSectionValues(const Section: string; Strings: TStrings);
228    procedure EraseSection(const Section: string);
229    procedure DeleteKey(const Section, Ident: String);
230
231    property FileName: String read fFileName;
232    property PreferStringValues: Boolean read fPreferStringValues
233                write fPreferStringValues;
234  end{$ifdef XMLREG}deprecated 'Use TRegistry instead. Will be removed in 4.0'{$endif} platform;
235
236{ ---------------------------------------------------------------------
237    TRegIniFile
238  ---------------------------------------------------------------------}
239
240
241  TRegistryIniFile = class(TCustomIniFile)
242  private
243    FRegIniFile: TRegIniFile;
244  public
245    constructor Create(const AFileName: string); overload;
246    constructor Create(const AFileName: string; AAccess: LongWord); overload;
247    destructor destroy; override;
248    function ReadDate(const Section, Name: string; Default: TDateTime): TDateTime; override;
249    function ReadDateTime(const Section, Name: string; Default: TDateTime): TDateTime; override;
250    function ReadInteger(const Section, Name: string; Default: Longint): Longint; override;
251    function ReadFloat(const Section, Name: string; Default: Double): Double; override;
252    function ReadString(const Section, Name, Default: string): string; override;
253    function ReadTime(const Section, Name: string; Default: TDateTime): TDateTime; override;
254    function ReadBinaryStream(const Section, Name: string; Value: TStream): Integer; override; unimplemented;
255    procedure WriteDate(const Section, Name: string; Value: TDateTime); override;
256    procedure WriteDateTime(const Section, Name: string; Value: TDateTime); override;
257    procedure WriteFloat(const Section, Name: string; Value: Double); override;
258    procedure WriteInteger(const Section, Name: string; Value: Longint); override;
259    procedure WriteString(const Section, Name, Value: String); override;
260    procedure WriteTime(const Section, Name: string; Value: TDateTime); override;
261    procedure WriteBinaryStream(const Section, Name: string; Value: TStream); override;
262    procedure ReadSection(const Section: string; Strings: TStrings); override;
263    procedure ReadSections(Strings: TStrings); override;
264    procedure ReadSectionValues(const Section: string; Strings: TStrings); override;
265    procedure EraseSection(const Section: string); override;
266    procedure DeleteKey(const Section, Name: String); override;
267    procedure UpdateFile; override;
268    function ValueExists(const Section, Ident: string): Boolean; override;
269    property RegIniFile: TRegIniFile read FRegIniFile;
270  end{$ifdef XMLREG}deprecated 'Use TRegistry instead. Will be removed in 4.0'{$endif} platform;
271
272ResourceString
273  SInvalidRegType   = 'Invalid registry data type: "%s"';
274  SRegCreateFailed  = 'Failed to create key: "%s"';
275  SRegSetDataFailed = 'Failed to set data for value "%s"';
276  SRegGetDataFailed = 'Failed to get data for value "%s"';
277
278var
279  GlobalXMLFile : Boolean = False;
280
281implementation
282
283{ ---------------------------------------------------------------------
284    Include implementation-dependent code
285  ---------------------------------------------------------------------}
286
287
288{$ifdef XMLREG}
289{$i xregreg.inc}
290{$else}
291{$i winreg.inc}
292{$endif}
293
294{ ---------------------------------------------------------------------
295    Generic, implementation-independent code.
296  ---------------------------------------------------------------------}
297
298{$ifdef DebugRegistry}
299function DbgS(const S: UnicodeString): String;
300var
301  C: WideChar;
302begin
303  Result := '';
304  for C in S do Result := Result + IntToHex(Word(C),4) + #32;
305  Result := TrimRight(Result);
306end;
307{$endif}
308
309constructor TRegistry.Create;
310
311begin
312  inherited Create;
313  FAccess     := KEY_ALL_ACCESS;
314  FRootKey    := HKEY_CURRENT_USER;
315  FLazyWrite  := True;
316  FCurrentKey := 0;
317  SysRegCreate;
318end;
319
320constructor TRegistry.Create(aaccess: longword);
321
322begin
323  Create;
324  FAccess     := aaccess;
325end;
326
327destructor TRegistry.Destroy;
328begin
329  CloseKey;
330  SysRegFree;
331  inherited Destroy;
332end;
333
334function TRegistry.CreateKey(const Key: UnicodeString): Boolean;
335
336begin
337  Result:=SysCreateKey(Key);
338  If Not Result Then
339    Raise ERegistryException.CreateFmt(SRegCreateFailed, [Key]);
340end;
341
342function TRegistry.CreateKey(const Key: String): Boolean;
343begin
344  Result:=CreateKey(UnicodeString(Key));
345end;
346
347function TRegistry.DeleteKey(const Key: String): Boolean;
348begin
349  Result:=DeleteKey(UnicodeString(Key));
350end;
351
352function TRegistry.DeleteValue(const Name: String): Boolean;
353begin
354  Result:=DeleteValue(UnicodeString(Name));
355end;
356
357function TRegistry.GetDataInfo(const ValueName: String; out Value: TRegDataInfo
358  ): Boolean;
359begin
360  Result:=GetDataInfo(UnicodeString(ValueName), Value);
361end;
362
363function TRegistry.GetBaseKey(Relative: Boolean): HKey;
364begin
365  If Relative and (CurrentKey<>0) Then
366    Result := CurrentKey
367  else
368    Result := RootKey;
369end;
370
371function TRegistry.GetData(const Name: UnicodeString; Buffer: Pointer; BufSize: Integer; out RegData: TRegDataType): Integer;
372begin
373  Result:=SysGetData(Name,Buffer,BufSize,RegData);
374  If (Result=-1) then
375    Raise ERegistryException.CreateFmt(SRegGetDataFailed, [Name]);
376end;
377
378function TRegistry.GetData(const Name: String; Buffer: Pointer;
379  BufSize: Integer; out RegData: TRegDataType): Integer;
380begin
381  Result:=GetData(UnicodeString(Name), Buffer, BufSize, RegData);
382end;
383
384function TRegistry.GetKey(Key: String): HKEY;
385begin
386  Result:=GetKey(UnicodeString(Key));
387end;
388
389procedure TRegistry.ChangeKey(Value: HKey; const Path: String);
390begin
391  ChangeKey(Value, UnicodeString(Path));
392end;
393
394
395procedure TRegistry.PutData(const Name: UnicodeString; Buffer: Pointer;
396  BufSize: Integer; RegData: TRegDataType);
397
398begin
399  If Not SysPutData(Name,Buffer,BufSize,RegData) then
400    Raise ERegistryException.CreateFmt(SRegSetDataFailed, [Name]);
401end;
402
403procedure TRegistry.PutData(const Name: String; Buffer: Pointer;
404  BufSize: Integer; RegData: TRegDataType);
405begin
406  PutData(UnicodeString(Name), Buffer, BufSize, RegData);
407end;
408
409
410function TRegistry.GetDataSize(const ValueName: UnicodeString): Integer;
411
412Var
413  Info: TRegDataInfo;
414
415begin
416  If GetDataInfo(ValueName,Info) Then
417    Result := Info.DataSize
418  else
419    Result := -1;
420end;
421
422function TRegistry.GetDataSize(const ValueName: String): Integer;
423begin
424  Result:=GetDataSize(UnicodeString(ValueName));
425end;
426
427function TRegistry.GetDataType(const ValueName: UnicodeString): TRegDataType;
428
429Var
430  Info: TRegDataInfo;
431
432begin
433  GetDataInfo(ValueName, Info);
434  Result:=Info.RegData;
435end;
436
437function TRegistry.GetDataType(const ValueName: String): TRegDataType;
438begin
439  Result:=GetDataType(UnicodeString(ValueName));
440end;
441
442
443function TRegistry.KeyExists(const Key: String): Boolean;
444begin
445  Result:=KeyExists(UnicodeString(Key));
446end;
447
448function TRegistry.LoadKey(const Key, FileName: String): Boolean;
449begin
450  Result:=LoadKey(UnicodeString(Key), UnicodeString(FileName));
451end;
452
453function TRegistry.OpenKey(const Key: String; CanCreate: Boolean): Boolean;
454begin
455  Result:=OpenKey(UnicodeString(Key), CanCreate);
456end;
457
458function TRegistry.OpenKeyReadOnly(const Key: String): Boolean;
459begin
460  Result:=OpenKeyReadOnly(UnicodeString(Key));
461end;
462
463function TRegistry.HasSubKeys: Boolean;
464
465Var
466  Info : TRegKeyInfo;
467
468begin
469  Result:=GetKeyInfo(Info);
470  If Result then
471    Result:=(Info.NumSubKeys>0);
472end;
473
474function TRegistry.ReadBinaryData(const Name: UnicodeString; var Buffer; BufSize: Integer): Integer;
475
476Var
477  RegDataType: TRegDataType;
478
479begin
480  Result := GetData(Name, @Buffer, BufSize, RegDataType);
481end;
482
483function TRegistry.ReadBinaryData(const Name: String; var Buffer;
484  BufSize: Integer): Integer;
485begin
486  Result:=ReadBinaryData(UnicodeString(Name), Buffer, BufSize);
487end;
488
489function TRegistry.ReadInteger(const Name: UnicodeString): Integer;
490
491Var
492  RegDataType: TRegDataType;
493
494begin
495  GetData(Name, @Result, SizeOf(Integer), RegDataType);
496  If RegDataType<>rdInteger Then
497    Raise ERegistryException.CreateFmt(SInvalidRegType, [Name]);
498end;
499
500function TRegistry.ReadInteger(const Name: String): Integer;
501begin
502  Result:=ReadInteger(UnicodeString(Name));
503end;
504
505function TRegistry.ReadInt64(const Name: UnicodeString): Int64;
506
507Var
508  RegDataType: TRegDataType;
509
510begin
511  GetData(Name, @Result, SizeOf(Int64), RegDataType);
512  If RegDataType<>rdInt64 Then
513    Raise ERegistryException.CreateFmt(SInvalidRegType, [Name]);
514end;
515
516function TRegistry.ReadInt64(const Name: String): Int64;
517begin
518  Result:=ReadInt64(UnicodeString(Name));
519end;
520
521function TRegistry.ReadBool(const Name: UnicodeString): Boolean;
522
523begin
524  Result:=ReadInteger(Name)<>0;
525end;
526
527function TRegistry.ReadBool(const Name: String): Boolean;
528begin
529  Result:=ReadBool(UnicodeString(Name));
530end;
531
532function TRegistry.ReadCurrency(const Name: UnicodeString): Currency;
533
534begin
535  Result:=Default(Currency);
536  ReadBinaryData(Name, Result, SizeOf(Currency));
537end;
538
539function TRegistry.ReadCurrency(const Name: String): Currency;
540begin
541  Result:=ReadCurrency(UnicodeString(Name));
542end;
543
544function TRegistry.ReadDate(const Name: UnicodeString): TDateTime;
545
546begin
547  Result:=Trunc(ReadDateTime(Name));
548end;
549
550function TRegistry.ReadDate(const Name: String): TDateTime;
551begin
552  Result:=ReadDate(UnicodeString(Name));
553end;
554
555function TRegistry.ReadDateTime(const Name: UnicodeString): TDateTime;
556
557begin
558  Result:=Default(TDateTime);
559  ReadBinaryData(Name, Result, SizeOf(TDateTime));
560end;
561
562function TRegistry.ReadDateTime(const Name: String): TDateTime;
563begin
564  Result:=ReadDateTime(UnicodeString(Name));
565end;
566
567function TRegistry.ReadFloat(const Name: UnicodeString): Double;
568
569begin
570  Result:=Default(Double);
571  ReadBinaryData(Name,Result,SizeOf(Double));
572end;
573
574function TRegistry.ReadFloat(const Name: String): Double;
575begin
576  Result:=ReadFloat(UnicodeString(Name));
577end;
578
579function TRegistry.ReadString(const Name: UnicodeString): UnicodeString;
580
581Var
582  Info : TRegDataInfo;
583  ReadDataSize: Integer;
584  u: UnicodeString;
585
586begin
587  Result:='';
588  GetDataInfo(Name,Info);
589  if info.datasize>0 then
590  begin
591    if Not (Info.RegData in [rdString,rdExpandString]) then
592      Raise ERegistryException.CreateFmt(SInvalidRegType, [Name]);
593    if Odd(Info.DataSize) then
594      SetLength(u,round((Info.DataSize+1)/SizeOf(UnicodeChar)))
595    else
596      SetLength(u,round(Info.DataSize/SizeOf(UnicodeChar)));
597    ReadDataSize := GetData(Name,@u[1],Info.DataSize,Info.RegData);
598    if ReadDataSize > 0 then
599    begin
600      // If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type,
601      // the size includes any terminating null character or characters
602      // unless the data was stored without them! (RegQueryValueEx @ MSDN)
603      if StringSizeIncludesNull and
604         (u[Length(u)] = WideChar(0)) then
605        SetLength(u,Length(u)-1);
606      Result:=u;
607    end;
608  end;
609end;
610
611function TRegistry.ReadString(const Name: String): string;
612begin
613  Result:=ReadString(UnicodeString(Name));
614end;
615
616
617procedure TRegistry.ReadStringList(const Name: UnicodeString; AList: TStrings; ForceUtf8: Boolean=False);
618
619Var
620  UArr: TUnicodeStringArray;
621
622begin
623  UArr := ReadStringArray(Name);
624  ArrayToList(UArr, AList, ForceUtf8);
625end;
626
627procedure TRegistry.ReadStringList(const Name: String; AList: TStrings);
628begin
629  ReadStringList(UnicodeString(Name), AList);
630end;
631
632function TRegistry.FixPath(APath: UnicodeString): UnicodeString;
633const
634  Delim={$ifdef XMLREG}'/'{$else}'\'{$endif};
635begin
636  //At this point we know the path is valid, since this is only called after OpenKey succeeded
637  //Just sanitize it
638  while (Pos(Delim+Delim,APath) > 0) do
639    APath := UnicodeStringReplace(APath, Delim+Delim,Delim,[rfReplaceAll]);
640  if (Length(APath) > 1) and (APath[Length(APath)] = Delim) then
641    System.Delete(APath, Length(APath), 1);
642  Result := APath;
643end;
644
645function TRegistry.RegMultiSzDataToUnicodeStringArray(U: UnicodeString): TUnicodeStringArray;
646var
647  Len, i, p: Integer;
648  Sub: UnicodeString;
649begin
650  Result := nil;
651  if (U = '') then Exit;
652  Len := 1;
653  for i := 1 to Length(U) do if (U[i] = #0) then Inc(Len);
654  SetLength(Result, Len);
655  i := 0;
656
657  while (U <> '') and (i < Length(Result)) do
658  begin
659    p := Pos(#0, U);
660    if (p = 0) then p := Length(U) + 1;
661    Sub := Copy(U, 1, p - 1);
662    Result[i] := Sub;
663    System.Delete(U, 1, p);
664    Inc(i);
665  end;
666end;
667
668function TRegistry.ListToArray(List: TStrings; IsUtf8: Boolean): TUnicodeStringArray;
669var
670  i, curr, Len: Integer;
671  u: UnicodeString;
672begin
673  Result := nil;
674  Len := List.Count;
675  SetLength(Result, Len);
676  //REG_MULTI_SZ data cannot contain empty strings
677  curr := 0;
678  for i := 0 to List.Count - 1 do
679  begin
680    if IsUtf8 then
681      u := Utf8Decode(List[i])
682    else
683      u := List[i];
684    if (u>'') then
685    begin
686      Result[curr] := u;
687      inc(curr);
688    end
689    else
690      Dec(Len);
691  end;
692  if (Len <> List.Count) then SetLength(Result, Len);
693end;
694
695procedure TRegistry.ArrayToList(const Arr: TUnicodeStringArray; List: TStrings; ForceUtf8: Boolean);
696var
697  i: Integer;
698begin
699  List.Clear;
700  for i := Low(Arr) to High(Arr) do
701  begin
702    if ForceUtf8 then
703      List.Add(Utf8Encode(Arr[i]))
704    else
705      List.Add(String(Arr[i]));
706  end;
707end;
708
709function TRegistry.ReadStringArray(const Name: UnicodeString): TUnicodeStringArray;
710Var
711  Info : TRegDataInfo;
712  ReadDataSize: Integer;
713  Data: UnicodeString;
714
715begin
716  Result := nil;
717  GetDataInfo(Name,Info);
718  //writeln('TRegistry.ReadStringArray: datasize=',info.datasize);
719  if info.datasize>0 then
720    begin
721     If Not (Info.RegData in [rdMultiString]) then
722       Raise ERegistryException.CreateFmt(SInvalidRegType, [Name]);
723     SetLength(Data,Info.DataSize);
724     ReadDataSize := GetData(Name,PWideChar(Data),Info.DataSize,Info.RegData) div SizeOf(WideChar);
725     //writeln('TRegistry.ReadStringArray: ReadDataSize=',ReadDataSize);
726     if ReadDataSize > 0 then
727     begin
728       // Windows returns the data with or without trailing zero's, so just strip all trailing null characters
729        while (Data[ReadDataSize] = #0) do Dec(ReadDataSize);
730       SetLength(Data, ReadDataSize);
731       //writeln('Data=',dbgs(data));
732       //Data := UnicodeStringReplace(Data, #0, AList.LineBreak, [rfReplaceAll]);
733       //AList.Text := Data;
734       Result := RegMultiSzDataToUnicodeStringArray(Data);
735     end
736   end
737end;
738
739function TRegistry.ReadStringArray(const Name: String): TStringArray;
740var
741  UArr: TUnicodeStringArray;
742  i: Integer;
743begin
744  Result := nil;
745  UArr := ReadStringArray(UnicodeString(Name));
746  SetLength(Result, Length(UArr));
747  for i := Low(UArr) to High(UArr) do Result[i] := UArr[i];
748end;
749
750function TRegistry.ReadTime(const Name: UnicodeString): TDateTime;
751
752begin
753  Result:=Frac(ReadDateTime(Name));
754end;
755
756function TRegistry.ReadTime(const Name: String): TDateTime;
757begin
758  Result:=ReadTime(UnicodeString(Name));
759end;
760
761function TRegistry.RegistryConnect(const UNCName: String): Boolean;
762begin
763  Result:=RegistryConnect(UnicodeString(UNCName));
764end;
765
766function TRegistry.ReplaceKey(const Key, FileName, BackUpFileName: String): Boolean;
767begin
768  Result:=ReplaceKey(UnicodeString(Key), UnicodeString(FileName), UnicodeString(BackUpFileName))
769end;
770
771function TRegistry.RestoreKey(const Key, FileName: String): Boolean;
772begin
773  Result:=RestoreKey(UnicodeString(Key), UnicodeString(FileName));
774end;
775
776function TRegistry.SaveKey(const Key, FileName: String): Boolean;
777begin
778  Result:=SaveKey(UnicodeString(Key), UnicodeString(FileName));
779end;
780
781function TRegistry.UnLoadKey(const Key: String): Boolean;
782begin
783  Result:=UnloadKey(UnicodeString(Key));
784end;
785
786function TRegistry.ValueExists(const Name: String): Boolean;
787begin
788  Result:=ValueExists(UnicodeString(Name));
789end;
790
791procedure TRegistry.WriteBinaryData(const Name: UnicodeString; const Buffer; BufSize: Integer);
792begin
793  PutData(Name, @Buffer, BufSize, rdBinary);
794end;
795
796procedure TRegistry.WriteBinaryData(const Name: String; const Buffer;
797  BufSize: Integer);
798begin
799  WriteBinaryData(UnicodeString(Name), Buffer, BufSize);
800end;
801
802procedure TRegistry.WriteBool(const Name: UnicodeString; Value: Boolean);
803
804begin
805  WriteInteger(Name,Ord(Value));
806end;
807
808procedure TRegistry.WriteBool(const Name: String; Value: Boolean);
809begin
810  WriteBool(UnicodeString(Name), Value);
811end;
812
813procedure TRegistry.WriteCurrency(const Name: UnicodeString; Value: Currency);
814begin
815  WriteBinaryData(Name, Value, SizeOf(Currency));
816end;
817
818procedure TRegistry.WriteCurrency(const Name: String; Value: Currency);
819begin
820  WriteCurrency(UnicodeString(Name), Value);
821end;
822
823procedure TRegistry.WriteDate(const Name: UnicodeString; Value: TDateTime);
824begin
825  WriteBinarydata(Name, Value, SizeOf(TDateTime));
826end;
827
828procedure TRegistry.WriteDate(const Name: String; Value: TDateTime);
829begin
830  WriteDate(UnicodeString(Name), Value);
831end;
832
833procedure TRegistry.WriteTime(const Name: UnicodeString; Value: TDateTime);
834begin
835  WriteBinaryData(Name, Value, SizeOf(TDateTime));
836end;
837
838procedure TRegistry.WriteTime(const Name: String; Value: TDateTime);
839begin
840  WriteTime(UnicodeString(Name), Value);
841end;
842
843procedure TRegistry.WriteDateTime(const Name: UnicodeString; Value: TDateTime);
844begin
845  WriteBinaryData(Name, Value, SizeOf(TDateTime));
846end;
847
848procedure TRegistry.WriteDateTime(const Name: String; Value: TDateTime);
849begin
850  WriteDateTime(UnicodeString(Name), Value);
851end;
852
853procedure TRegistry.WriteExpandString(const Name, Value: UnicodeString);
854begin
855  PutData(Name, PWideChar(Value), ByteLength(Value), rdExpandString);
856end;
857
858procedure TRegistry.WriteExpandString(const Name, Value: String);
859begin
860  WriteExpandString(UnicodeString(Name), UnicodeString(Value));
861end;
862
863
864procedure TRegistry.WriteStringList(const Name: UnicodeString; List: TStrings; IsUtf8: Boolean=False);
865
866Var
867  UArr: TUnicodeStringArray;
868begin
869  UArr := ListToArray(List, IsUtf8);
870  WriteStringArray(Name, UArr);
871end;
872
873procedure TRegistry.WriteStringArray(const Name: UnicodeString; const Arr: TUnicodeStringArray);
874Var
875  Data: UnicodeString;
876  u: UnicodeString;
877  i: Integer;
878begin
879  Data := '';
880  //REG_MULTI_SZ data cannot contain empty strings
881  for i := Low(Arr) to High(Arr) do
882  begin
883    u := Arr[i];
884    if (u>'') then
885    begin
886      if (Data>'') then
887        Data := Data + #0 + u
888      else
889        Data := Data + u;
890    end;
891  end;
892  if StringSizeIncludesNull then
893    Data := Data + #0#0;
894  //writeln('Data=',Dbgs(Data));
895  PutData(Name, PWideChar(Data), ByteLength(Data), rdMultiString);
896end;
897
898procedure TRegistry.WriteStringArray(const Name: String; const Arr: TStringArray);
899var
900  UArr: TUnicodeStringArray;
901  i: Integer;
902begin
903  UArr := nil;
904  SetLength(UArr, Length(Arr));
905  for i := Low(Arr) to High(Arr) do UArr[i] := Arr[i];
906  WriteStringArray(UnicodeString(Name), UArr);
907end;
908
909procedure TRegistry.WriteFloat(const Name: UnicodeString; Value: Double);
910begin
911  WriteBinaryData(Name, Value, SizeOf(Double));
912end;
913
914procedure TRegistry.WriteFloat(const Name: String; Value: Double);
915begin
916  WriteFloat(UnicodeString(Name), Value);
917end;
918
919procedure TRegistry.WriteInteger(const Name: UnicodeString; Value: Integer);
920begin
921  PutData(Name, @Value, SizeOf(Integer), rdInteger);
922end;
923
924procedure TRegistry.WriteInteger(const Name: String; Value: Integer);
925begin
926  WriteInteger(UnicodeString(Name), Value);
927end;
928
929procedure TRegistry.WriteInt64(const Name: UnicodeString; Value: Int64);
930begin
931  PutData(Name, @Value, SizeOf(Int64), rdInt64);
932end;
933
934procedure TRegistry.WriteInt64(const Name: String; Value: Int64);
935begin
936  WriteInt64(UnicodeString(Name), Value);
937end;
938
939procedure TRegistry.WriteString(const Name, Value: UnicodeString);
940begin
941  PutData(Name, PWideChar(Value), ByteLength(Value), rdString);
942end;
943
944procedure TRegistry.WriteString(const Name, Value: String);
945begin
946  WriteString(UnicodeString(Name), UnicodeString(Value));
947end;
948
949procedure TRegistry.GetKeyNames(Strings: TStrings);
950var
951  UArr: TUnicodeStringArray;
952begin
953  UArr := GetKeyNames;
954  ArrayToList(UArr, Strings, True);
955end;
956
957procedure TRegistry.GetValueNames(Strings: TStrings);
958var
959  UArr: TUnicodeStringArray;
960begin
961  UArr := GetValueNames;
962  ArrayToList(UArr, Strings, True);
963end;
964
965procedure TRegistry.MoveKey(const OldName, NewName: UnicodeString; Delete: Boolean);
966begin
967
968end;
969
970procedure TRegistry.MoveKey(const OldName, NewName: String; Delete: Boolean);
971begin
972  MoveKey(UnicodeString(OldName), UnicodeString(NewName), Delete);
973end;
974
975procedure TRegistry.RenameValue(const OldName, NewName: String);
976begin
977  RenameValue(UnicodeString(OldName), UnicodeString(NewName));
978end;
979
980{ ---------------------------------------------------------------------
981    Include TRegIniFile implementation
982  ---------------------------------------------------------------------}
983
984{$i regini.inc}
985
986{ TRegistryIniFile }
987
988// interface from
989// http://www.koders.com/delphi/fid65C1FFAEF89B0CDC4B93FF94C1819686CA6141FC.aspx
990constructor TRegistryIniFile.Create(const AFileName: string;
991  AAccess: LongWord);
992begin
993  inherited create(AFilename);
994  FRegInifile:=TreginiFile.Create(AFileName,AAccess);
995end;
996
997constructor TRegistryIniFile.Create(const AFileName: string);
998begin
999  Create(AFileName,KEY_ALL_ACCESS);
1000end;
1001
1002destructor TRegistryIniFile.destroy;
1003
1004begin
1005  FreeAndNil(FRegInifile);
1006  Inherited;
1007end;
1008
1009procedure TRegistryIniFile.DeleteKey(const Section, Name: String);
1010begin
1011  FRegIniFile.Deletekey(section,name);
1012end;
1013
1014procedure TRegistryIniFile.EraseSection(const Section: string);
1015begin
1016  FRegIniFile.EraseSection(section);
1017end;
1018
1019function TRegistryIniFile.ReadBinaryStream(const Section, Name: string;
1020  Value: TStream): Integer;
1021begin
1022  result:=-1; // unimplemented
1023 //
1024end;
1025
1026function TRegistryIniFile.ReadDate(const Section, Name: string;
1027  Default: TDateTime): TDateTime;
1028begin
1029  Result:=FRegInifile.ReadDate(Section,Name,Default);
1030end;
1031
1032function TRegistryIniFile.ReadDateTime(const Section, Name: string;
1033  Default: TDateTime): TDateTime;
1034begin
1035  Result:=FRegInifile.ReadDateTime(Section,Name,Default);
1036end;
1037
1038function TRegistryIniFile.ReadFloat(const Section, Name: string;
1039  Default: Double): Double;
1040begin
1041  Result:=FRegInifile.ReadFloat(Section,Name,Default);
1042end;
1043
1044function TRegistryIniFile.ReadInteger(const Section, Name: string;
1045  Default: Integer): Longint;
1046begin
1047  Result:=FRegInifile.ReadInteger(Section, Name, Default);
1048end;
1049
1050procedure TRegistryIniFile.ReadSection(const Section: string; Strings: TStrings);
1051begin
1052  FRegIniFile.ReadSection(Section,strings);
1053end;
1054
1055procedure TRegistryIniFile.ReadSections(Strings: TStrings);
1056begin
1057  FRegIniFile.ReadSections(strings);
1058end;
1059
1060procedure TRegistryIniFile.ReadSectionValues(const Section: string;
1061  Strings: TStrings);
1062begin
1063  FRegIniFile.ReadSectionValues(Section,strings);
1064end;
1065
1066function TRegistryIniFile.ReadString(const Section, Name,
1067  Default: string): string;
1068begin
1069  Result:=FRegInifile.ReadString(Section, Name, Default);
1070end;
1071
1072function TRegistryIniFile.ReadTime(const Section, Name: string;
1073  Default: TDateTime): TDateTime;
1074begin
1075  Result:=FRegInifile.ReadTime(Section,Name,Default);
1076end;
1077
1078procedure TRegistryIniFile.UpdateFile;
1079begin
1080//  FRegIniFile.UpdateFile; ??
1081end;
1082
1083procedure TRegistryIniFile.WriteBinaryStream(const Section, Name: string;
1084  Value: TStream);
1085begin
1086 // ??
1087end;
1088
1089procedure TRegistryIniFile.WriteDate(const Section, Name: string;
1090  Value: TDateTime);
1091begin
1092  FRegInifile.WriteDate(Section,Name, Value);
1093end;
1094
1095procedure TRegistryIniFile.WriteDateTime(const Section, Name: string;
1096  Value: TDateTime);
1097begin
1098  FRegInifile.WriteDateTime(Section,Name, Value);
1099end;
1100
1101procedure TRegistryIniFile.WriteFloat(const Section, Name: string;
1102  Value: Double);
1103begin
1104  FRegInifile.WriteFloat(Section,Name, Value);
1105end;
1106
1107procedure TRegistryIniFile.WriteInteger(const Section, Name: string;
1108  Value: Integer);
1109begin
1110  FRegInifile.WriteInteger(Section, Name, Value);
1111end;
1112
1113procedure TRegistryIniFile.WriteString(const Section, Name, Value: String);
1114begin
1115  FRegInifile.WriteString(Section, Name, Value);
1116end;
1117
1118procedure TRegistryIniFile.WriteTime(const Section, Name: string;
1119  Value: TDateTime);
1120begin
1121  FRegInifile.WriteTime(Section,Name, Value);
1122end;
1123
1124function TRegistryIniFile.ValueExists(const Section, Ident: string): Boolean;
1125begin
1126  with FRegInifile do
1127    if OpenSection(Section) then
1128      try
1129        Result:=FRegInifile.ValueExists(Ident);
1130      finally
1131        CloseSection;
1132      end;
1133end;
1134
1135{$ifdef XMLREG}
1136finalization
1137  TXMLRegistryInstance.FreeXMLRegistryCache;
1138{$endif}
1139
1140end.
1141