28

I am dealing with an application that still uses INI files for configuration. I wanted to make a temporary change to an INI file, but the result was not what I expected.

Let's say the original INI file is

[mysection]
mykey=myvalue

and I wanted to make a revertable change for testing purposes. From my (maybe incomplete or wrong) memories, I recalled that a lot of programs used batch files to modify INI files like so:

echo [mysection]>>test.ini
echo mykey=anothervalue>>test.ini

resulting in an INI file like

[mysection]
mykey=myvalue
[mysection]
mykey=anothervalue

The "revertable" part of this would be that I could simply delete the last 2 lines.

I don't recall any utilities which would have taken care about duplicate sections or keys. Obviously, "echoing" the section is needed to make sure that the section exists in case it did not exist before.

For the last 30 years or so, I believed that the last entry of an INI file wins, exactly for the reason to support these "echoing" changes.

Now, as I said, this change did not work out for the application I am using today. My first thought was that they used an incompatible INI file parser. So I conducted the following test myself, just relying on the Windows API:

// C#
static void Main()
{
    var sb = new StringBuilder(500);
    GetPrivateProfileString(
        "mysection", "mykey","", sb, (uint)sb.Capacity, "e:\\test.ini");
    if (sb.ToString() != "anothervalue")
        throw new ApplicationException("Not what I expected");
}

Guess what: the result is not what I expected.

Could someone confirm (or disprove) that I was wrong for 30 years? Did Windows 3.x and Windows 95 consider the first section and first key of INI files only?

(I am only interested in the "official" way of reading INI files using the Windows API GetPrivateProfileString())

15
  • 8
    @Alex the parser algorithm doesn’t vary here, the question is specifically about GetPrivateProfileString. Dec 16, 2021 at 11:05
  • 10
    @Alex given Microsoft’s focus on backwards compatibility, I suspect that they would be unlikely to change the function’s behaviour (even if its implementation changed). Dec 16, 2021 at 11:09
  • 4
    @StephenKitt: the implementation definitely has changed. E.g. INI files can now be mapped to the Registry, so you may not get a value from the file at all. That's also the reason why I asked the question here. Maybe there was a breaking change - but obviously not so breaking Dec 16, 2021 at 11:41
  • 1
    @selbie: it's unlikely that a mistake in the P/Invoke declaration would change whether the implementation reads the first or the last entry. The major thing that could be declared in a wrong way is the encoding of the buffer. But with ASCII content, that will not make much of a difference. But yes, I'm considering Encoding issues ... Dec 17, 2021 at 8:09
  • 2
    FYI, at least on UNIX, echo [mysection]>>test.ini may not do what you expect. If you have a file named m (or y, s, e, c, ...etc...) in your current directory, for example, [mysection] can be treated as a glob expansion matching that filename, and thus write only the name of said file instead of the string [mysection]. Quoting it as echo "[mysection]" will prevent this. Dec 17, 2021 at 17:23

2 Answers 2

57

You have been wrong for 30 years.

I wrote the test program below and compiled it with Borland Pascal 7:

uses WinTypes, WinProcs, WinCrt;

var
  buffer: string;
  len: Integer;
begin
  len := GetPrivateProfileString(
    'mysection', 'mykey', '', @buffer[1], 255, 'C:\TEST.INI');
  buffer[0] := Chr(len);
  WriteLn(buffer);
end.

Then I ran it with the INI file from the question saved to C:\TEST.INI. It output myvalue both in Windows 3.10:

Test program run in Windows 3.10

and in Windows 95:

Test program run in Windows 95

Whatever INI-modifying utilities you were speaking of were simply not doing their job right. Sorry, old software was made of duct tape, smoke and mirrors, just like today. Where did you think we inherited this from?

10
  • 3
    Another interesting test would be to show the result of GetPrivateProfileString without specifying a section or key — does it return the duplicate sections, or just the first one? Dec 16, 2021 at 11:10
  • 17
    There was no duct tape and no special magic. It always has been a simple loop scanning for headers and entries in sequential order. It's all about space. There is no space to hold multiple ini files which are usually only needed during startup or a few special times. It's more efficient when applications keep whatever they need long term in private structures. Similar there is no space for file system watching code to synchronize potential updates. 16 bit Windows is about delivering function at all, not doing it the most sophisticated way.
    – Raffzahn
    Dec 16, 2021 at 12:30
  • 17
    I am impressed that you were able to build a test in less than an hour. You must have had a dev environment ready to go.
    – Joshua
    Dec 16, 2021 at 19:07
  • 11
    @Joshua Pretty much. I already had BP7 installed in a Windows 3.1 VM, the rest is a mere matter of typing. Dec 16, 2021 at 19:41
  • 5
    Back in the day we often used to write our own minimal, inflexible, ini-file handlers. That's actually a hard habit to shift. Behaviour from duplicate keys was all-but undefined as it depended on the implementation (to put what @Raffzahn say a bit differently)
    – Chris H
    Dec 17, 2021 at 9:08
0

Note that this - embedding multiple apparently-valid entries in a configuration file - is an awful approach to troubleshooting for a whole bunch of reasons, hence the need for INI files to allow comments or, as Microsoft themselves put it,

"You can include comments in initialization files. You must begin each line of a comment with a semicolon (;)."

I took this quote from the embedded documentation already present in WfW 3.11:

 64128  11-01-1993 03:11   WIN311/SYSINI.WRI
 22272  11-01-1993 03:11   WIN311/WININI.WRI
 76400  11-11-1993 03:11   WIN311/SYSTEM/KRNL386.EXE
7
  • What exactly is "awful" and what are the "whole bunch of reasons" that you consider it as awful? How does this relate to my question, which was about the precedence of duplicate entries and not about comments? Feb 21 at 12:37
  • > what are the "whole bunch of reasons... You don't know which value is being used by which application reading the file; there's no record of which was the original and which is the working modified version; if you append to the end of a longer file the second instance may not be visible in the editor (sysedit in EGA mode?); how does anyone else looking at the same file know what's going on...
    – Lou Knee
    Feb 21 at 13:24
  • But the question in big letters at the top is Did INI files work in a different way on Windows 3.x than today? and my answer is that semicolon comments have been working since at least WfW3.11, with reference.
    – Lou Knee
    Feb 21 at 13:28
  • And yet you don't answer the question whether they worked differently or not. Comments were supported in WfW 3.11 and they are supported today. So is your answer "They work the same way"? Feb 21 at 14:51
  • 1
    Why did you choose to answer specifically on comments in INI files and not e.g. on Unicode support of INI files, which could also be a topic? Or about Registry mapping? A lot of things actually have changed regarding INI files. Feb 21 at 14:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.