Use home brown file format for exporting and importing registry settings, as used for portable_settings.txt. Registry dumps cannot be imported into a separate registry key for a portable instance, which is hereby fixed, see http://www.heidisql.com/forum.php?t=10503 .

This commit is contained in:
Ansgar Becker
2012-04-09 17:40:12 +00:00
parent 8bc905b02f
commit 6ef3d17042
4 changed files with 111 additions and 72 deletions

View File

@ -17,6 +17,9 @@ const
REGKEY_QUERYHISTORY = 'QueryHistory';
// Some unique char, used to separate e.g. selected columns in registry
DELIM = '|';
CHR10REPLACEMENT = '<}}}>';
CHR13REPLACEMENT = '<{{{>';
DELIMITER = '<|||>';
// Used by maskSQL and fixSQL:
SQL_VERSION_ANSI = -1;

View File

@ -192,6 +192,8 @@ type
function GeneratePassword(Len: Integer): String;
procedure InvalidateVT(VT: TVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean);
procedure HandlePortableSettings(StartupMode: Boolean);
procedure ImportSettings(Filename: String);
procedure ExportSettings(Filename: String);
function CharAtPos(Str: String; Pos: Integer): Char;
function CompareAnyNode(Text1, Text2: String): Integer;
function StringListCompareAnythingAsc(List: TStringList; Index1, Index2: Integer): Integer;
@ -2192,20 +2194,51 @@ begin
end;
procedure HandlePortableSettings(StartupMode: Boolean);
procedure ImportSettings(Filename: String);
var
Content, FileName, Name, Value, KeyPath: String;
Lines, Segments, AllKeys: TStringList;
Content, Name, Value, KeyPath: String;
Lines, Segments: TStringList;
i: Integer;
DataType: TRegDataType;
Proc: TProcessEntry32;
ProcRuns: Boolean;
SnapShot: THandle;
rx: TRegExpr;
const
Chr10Replacement = '<}}}>';
Chr13Replacement = '<{{{>';
Delimiter = '<|||>';
begin
// Load registry settings from file
Content := ReadTextfile(FileName, nil);
Lines := Explode(CRLF, Content);
for i:=0 to Lines.Count-1 do begin
// Each line has 3 segments: reg path | data type | value. Continue if explode finds less or more than 3.
Segments := Explode(DELIMITER, Lines[i]);
if Segments.Count <> 3 then
continue;
KeyPath := RegPath + ExtractFilePath(Segments[0]);
Name := ExtractFileName(Segments[0]);
DataType := TRegDataType(StrToInt(Segments[1]));
MainReg.OpenKey(KeyPath, True);
if MainReg.ValueExists(Name) then
Continue; // Don't touch value if already there
Value := '';
if Segments.Count >= 3 then
Value := Segments[2];
case DataType of
rdString: begin
Value := StringReplace(Value, CHR13REPLACEMENT, #13, [rfReplaceAll]);
Value := StringReplace(Value, CHR10REPLACEMENT, #10, [rfReplaceAll]);
MainReg.WriteString(Name, Value);
end;
rdInteger:
MainReg.WriteInteger(Name, MakeInt(Value));
rdBinary, rdUnknown, rdExpandString:
ErrorDialog(Name+' has an unsupported data type.');
end;
Segments.Free;
end;
Lines.Free;
end;
procedure ExportSettings(Filename: String);
var
Content, Value: String;
DataType: TRegDataType;
procedure ReadKeyToContent(Path: String);
var
@ -2213,20 +2246,21 @@ const
i: Integer;
SubPath: String;
begin
MainReg.OpenKeyReadOnly(Path);
// Recursively read values in keys and their subkeys into "content" variable
MainReg.OpenKey(Path, True);
SubPath := Copy(Path, Length(RegPath)+1, MaxInt);
Names := TStringList.Create;
MainReg.GetValueNames(Names);
for i:=0 to Names.Count-1 do begin
DataType := MainReg.GetDataType(Names[i]);
Content := Content +
SubPath + Names[i] + Delimiter +
IntToStr(Integer(DataType)) + Delimiter;
SubPath + Names[i] + DELIMITER +
IntToStr(Integer(DataType)) + DELIMITER;
case DataType of
rdString: begin
Value := MainReg.ReadString(Names[i]);
Value := StringReplace(Value, #13, Chr13Replacement, [rfReplaceAll]);
Value := StringReplace(Value, #10, Chr10Replacement, [rfReplaceAll]);
Value := StringReplace(Value, #13, CHR13REPLACEMENT, [rfReplaceAll]);
Value := StringReplace(Value, #10, CHR10REPLACEMENT, [rfReplaceAll]);
end;
rdInteger:
Value := IntToStr(MainReg.ReadInteger(Names[i]));
@ -2241,6 +2275,24 @@ const
ReadKeyToContent(Path + Names[i] + '\');
Names.Free;
end;
begin
// Save registry settings to file
Content := '';
ReadKeyToContent(RegPath);
SaveUnicodeFile(FileName, Content);
end;
procedure HandlePortableSettings(StartupMode: Boolean);
var
FileName: String;
AllKeys: TStringList;
i: Integer;
Proc: TProcessEntry32;
ProcRuns: Boolean;
SnapShot: THandle;
rx: TRegExpr;
begin
// Export registry keys and values into textfile, for portable reasons
@ -2270,41 +2322,12 @@ begin
Screen.Cursor := crHourGlass;
try
// Both ImportSettings and ExportSettings rely on RegPath pointing to the right reg key
if StartupMode then begin
Content := ReadTextfile(FileName, nil);
Lines := Explode(CRLF, Content);
for i:=0 to Lines.Count-1 do begin
// Each line has 3 segments: reg path | data type | value. Continue if explode finds less or more than 3.
Segments := Explode(Delimiter, Lines[i]);
if Segments.Count <> 3 then
continue;
KeyPath := RegPath + ExtractFilePath(Segments[0]);
Name := ExtractFileName(Segments[0]);
DataType := TRegDataType(StrToInt(Segments[1]));
MainReg.OpenKey(KeyPath, True);
if MainReg.ValueExists(Name) then
Continue; // Don't touch value if already there
Value := '';
if Segments.Count >= 3 then
Value := Segments[2];
case DataType of
rdString: begin
Value := StringReplace(Value, Chr13Replacement, #13, [rfReplaceAll]);
Value := StringReplace(Value, Chr10Replacement, #10, [rfReplaceAll]);
MainReg.WriteString(Name, Value);
end;
rdInteger:
MainReg.WriteInteger(Name, MakeInt(Value));
rdBinary, rdUnknown, rdExpandString:
ErrorDialog(Name+' has an unsupported data type.');
end;
Segments.Free;
end;
Lines.Free;
ImportSettings(Filename);
end else begin
// Application closes: Recursively read values in keys and their subkeys into textfile
ReadKeyToContent(RegPath);
SaveUnicodeFile(FileName, Content);
// Application closes
ExportSettings(Filename);
MainReg.CloseKey;
MainReg.DeleteKey(RegPath);

View File

@ -2577,21 +2577,6 @@ object MainForm: TMainForm
OnExecute = actLaunchCommandlineExecute
end
end
object SaveDialog2: TSaveDialog
DefaultExt = 'reg'
Filter = 'Registry-files (*.reg)|*.reg|All files (*.*)|*.*'
Options = [ofOverwritePrompt, ofHideReadOnly, ofEnableSizing]
Title = 'Export settings from registry...'
Left = 8
Top = 128
end
object OpenDialog2: TOpenDialog
DefaultExt = 'reg'
Filter = 'Registry-files (*.reg)|*.reg|All files (*.*)|*.*'
Title = 'Import settings to registry...'
Left = 72
Top = 160
end
object menuConnections: TPopupMenu
AutoHotkeys = maManual
Images = ImageListMain

View File

@ -171,10 +171,8 @@ type
ToolButton14: TToolButton;
actExecuteQuery: TAction;
actExecuteSelection: TAction;
SaveDialog2: TSaveDialog;
ExportSettings1: TMenuItem;
Importsettings1: TMenuItem;
OpenDialog2: TOpenDialog;
menuSupportForum: TMenuItem;
actExportData: TAction;
actExecuteCurrentQuery: TAction;
@ -2203,18 +2201,48 @@ end;
procedure TMainForm.actExportSettingsExecute(Sender: TObject);
var
Dialog: TSaveDialog;
begin
// Export settings to .reg-file
if SaveDialog2.Execute then
ShellExec('regedit.exe', '', '/e "'+SaveDialog2.FileName+'" HKEY_CURRENT_USER'+REGPATH);
// Export settings to .txt file
Dialog := TSaveDialog.Create(Self);
Dialog.Title := 'Export '+APPNAME+' settings to file ...';
Dialog.DefaultExt := 'txt';
Dialog.Filter := 'Textfiles (*.txt)|*.txt|All files (*.*)|*.*';
Dialog.Options := Dialog.Options + [ofOverwritePrompt];
if Dialog.Execute then try
ExportSettings(Dialog.FileName);
MessageDialog('Settings successfully exported to '+Dialog.FileName, mtInformation, [mbOK]);
except
on E:Exception do
ErrorDialog(E.Message);
end;
Dialog.Free;
end;
procedure TMainForm.actImportSettingsExecute(Sender: TObject);
var
Dialog: TOpenDialog;
begin
// Import settings from .reg-file
if OpenDialog2.Execute then
ShellExec('regedit.exe', '', '"'+OpenDialog2.FileName+'"');
// Import settings from .txt or .reg file
Dialog := TOpenDialog.Create(Self);
Dialog.Title := 'Import '+APPNAME+' settings from file ...';
Dialog.Filter := 'Textfiles (*.txt)|*.txt|Registry dump, deprecated (*.reg)|*.reg|All files (*.*)|*.*';
if Dialog.Execute then try
if LowerCase(ExtractFileExt(Dialog.FileName)) = 'reg' then
ShellExec('regedit.exe', '', '"'+Dialog.FileName+'"')
else begin
ImportSettings(Dialog.FileName);
MessageDialog('Settings successfully restored from '+Dialog.FileName, mtInformation, [mbOK]);
end;
except
on E:Exception do
ErrorDialog(E.Message);
end;
Dialog.Free;
end;
procedure TMainForm.actExecuteQueryExecute(Sender: TObject);
var