I've modified Martin's code slightly, so it's possible to delete all the notes (lines prefixed with ;
) that precede the key, and it's also possible to add multiple lines of notes before each key.
const
CommentPrefix = ';';
function DeleteIniComments(
FileName: string; Section: string; Key: string): Boolean;
// #######################################################################################
// Deletes all comment lines preceding the Key in Section
// #######################################################################################
var
Lines: TArrayOfString;
Line: string;
InSection: string;
I, J, K, I2, P: Integer;
begin
Result := False;
InSection := '';
// load INI file lines
if LoadStringsFromFile(FileName, Lines) then
begin
Log(Format('INI: Delete all comments before the Key '+Key+', Read %d lines', [GetArrayLength(Lines)]));
// iterate lines to look for the section and key
for I := 0 to GetArrayLength(Lines) - 1 do
begin
Line := Lines[I];
{ is it a start of a section? }
if (Length(Line) > 0) and (Line[1] = '[') then
begin
P := Pos(']', Line);
if P > 0 then
begin
InSection := Trim(Copy(Line, 2, P - 2));
end;
end else
// are we in "our" section
if CompareText(InSection, Section) = 0 then
begin
P := Pos('=', Line);
// is it "our" key?
if (P > 0) and
(CompareText(Trim(Copy(Line, 1, P - 1)), Key) = 0) then
begin
// For all previous lines
for J := I-1 downto 0 do
begin
// If line is nonempty and starting with comment prefix
if (Length(Lines[J]) > 0) and (Lines[J][1] = CommentPrefix) then
begin
continue;
end
else begin
K := I - J - 1;
if (K > 0) then
begin
for I2 := I to GetArrayLength(Lines) - 1 do
begin
Lines[I2-K] := Lines[I2];
end;
SetArrayLength(Lines, GetArrayLength(Lines) - K);
Result := SaveStringsToFile(FileName, Lines, False);
end;
exit;
end;
end;
end;
end;
end;
end;
end;
function InsertIniComment(
FileName: string; Section: string; Key: string; Comment: string): Boolean;
// #######################################################################################
// Inserts one line of Comment just before Key in Section
// #######################################################################################
var
Lines: TArrayOfString;
Line: string;
InSection: string;
I, I2, P: Integer;
begin
Result := False;
InSection := '';
// load INI file lines
if LoadStringsFromFile(FileName, Lines) then
begin
Log(Format('INI: Insert comment before the Key'+Key+', Read %d lines', [GetArrayLength(Lines)]));
// iterate lines to look for the section and key
for I := 0 to GetArrayLength(Lines) - 1 do
begin
Line := Lines[I];
{ is it a start of a section? }
if (Length(Line) > 0) and (Line[1] = '[') then
begin
P := Pos(']', Line);
if P > 0 then
begin
InSection := Trim(Copy(Line, 2, P - 2));
end;
end
else
// are we in "our" section?
if CompareText(InSection, Section) = 0 then
begin
P := Pos('=', Line);
// is it "our" key?
if (P > 0) and
(CompareText(Trim(Copy(Line, 1, P - 1)), Key) = 0) then
begin
// we are on the line with the Key in Section
// we will insert new empty line before Key
SetArrayLength(Lines, GetArrayLength(Lines) + 1);
for I2 := GetArrayLength(Lines) - 1 downto I + 1 do
begin
Lines[I2] := Lines[I2 - 1];
end;
// and writing new comment into empty line
Lines[I] := CommentPrefix + ' ' + Comment;
Result := SaveStringsToFile(FileName, Lines, False);
break;
end;
end;
end;
end;
if not Result then
begin
Log('Section/Key not found');
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
FileName: string;
begin
if CurStep = ssPostInstall then
begin
FileName := ExpandConstant('{app}\{#AppName}.ini');
DeleteIniComments(FileName, 'Main', 'OldLogin');
InsertIniComment(FileName, 'Main', 'OldLogin', '');
InsertIniComment(FileName, 'Main', 'OldLogin', 'OldLogin=1 will cause a standard ODBC login window to be invoked.');
InsertIniComment(FileName, 'Main', 'OldLogin', 'This is useful in cases where it is not possible to log in with an internal name and password.');
DeleteIniComments(FileName, 'Main', 'BufForeground');
InsertIniComment(FileName, 'Main', 'BufForeground', '');
InsertIniComment(FileName, 'Main', 'BufForeground', 'Max buffer memory size in MB. Do not use more than 512 MB buffer size!');
InsertIniComment(FileName, 'Main', 'BufForeground', 'You can set different buffer sizes for foreground and background processes.');
DeleteIniComments(FileName, 'Devices', 'EluxGenID');
InsertIniComment(FileName, 'Devices', 'EluxGenID', '');
InsertIniComment(FileName, 'Devices', 'EluxGenID', 'EluxGenID=1 it finds the device type using a general query.');
end;
end;
This will create INI file that looks like this:
[Main]
;
; OldLogin=1 will cause a standard ODBC login window to be invoked.
; This is useful in cases where it is not possible to log in with an internal name and password.
OldLogin = 0
;
; Max buffer memory size in MB. Do not use more than 512 MB buffer size!
; You can set different buffer sizes for foreground and background processes.
BufForeground=512
BufBackground=512
[Devices]
;
; EluxGenID=1 it finds the device type using a general query.
EluxGenID=0
And you can use it repeatedly (e.g. at every software update). This code will add comments where these does not exist (to new keys) or replace (changed) comments with standard comments.
All keys remain unchanged, where user modified them yet.