Angesprochen habe ich es bereits: es gibt einen Grund, warum die INI-Datei so aufgebaut ist:
[names] Paul=Paul Johannes=Johannes ...
Natürlich wäre es einfacher, wenn man eine Nummerierung hätte, die man der Reihe nach durchgehen könnte:
[names] 1=Paul 2=Johannes
Hier könnte man z.B. eine Art Endlosschleife benutzen, die erst verlassen wird, wenn kein zum Schleifenwert passender Topic gefunden wurde.
i := 1; while(true) do begin if(GetPrivateProfileString('names',pchar(inttostr(i)), nil,buf,BUFSIZE,'userdata.ini') = 0) or (buf = nil) then break;
{ ... }
inc(i); end;
Dies birgt allerdings die Gefahr, dass bei Manipulationen der INI-Datei die Schleife vorzeitig oder evtl. auch nie verlassen wird. Besser ist es daher, wenn man sich nicht darum kümmern muss, wie die Topics der Sektion heißen. Von der Unit "IniFiles.pas" kennen Sie das als Funktion "ReadSection", mit der Sie alle Topicnamen einer Sektion in eine Stringliste eintragen können.
Ohne diese Unit lässt sich die gleiche Funktionalität natürlich auch erreichen. Wir benötigen hierfür einen Puffer. Das Beispiel verwendet dazu eine Größe von 65k. Das sollte eigentlich ausreichen; im Zweifelsfall können Sie ihn auch einen höheren Wert benutzen.
const
BUFSIZE = 65535;
Denken Sie daran, dass wir nur die Namen der Topics auslesen wollen; also jeweils die Strings vor dem Gleichheitszeichen:
Paul=Paul
Des Weiteren brauchen wir eine Art Stringliste, die alle Sektionsnamen aufnehmen soll. Ich denke, ein dynamisches String-Array ist eine gute Wahl.
Zuerst reservieren wir also den Platz für unseren Puffer und setzen das String-Array auf Null:
SetLength(kl,0);
GetMem(buf,BUFSIZE);
try
Beim Aufruf von "GetPrivateProfileString" ist es nun wichtig, dass wir keinen Topicnamen angeben:
if(GetPrivateProfileString(szNameKey,nil,nil,buf,BUFSIZE,
pchar(ExtractFilePath(paramstr(0)) + szIniFile)) <> 0) then
begin
Damit befinden sich die Namen aller Topics in unserem Puffer. Sie sind durch das Zeichen #0 voneinander getrennt. Der letzte Name endet mit zwei #0-Zeichen.
Mit Hilfe einer zweiten pchar-Variablen lesen wir nun die einzelnen Namen aus und tragen Sie in unser String-Array ein, das vorher immer entsprechend vergrößert wird:
p := buf;
while(p^ <> #0) do
begin
SetLength(kl,length(kl)+1);
kl[length(kl)-1] := p;
inc(p,lstrlen(p)+1);
end;
end;
Wie funktioniert es? Die Variable "p" wird auf den Beginn des ermittelten Puffers gesetzt und liefert natürlich nur den ersten String zurück, da das erste #0-Trennzeichen als dessen Ende interpretiert wird. Durch den Aufruf von
inc(p,lstrlen(p)+1);
wird die Länge des ersten Strings benutzt, um die pchar-Variable innerhalb des Puffers zu verschieben. Durch das "+1" wird auch das Trennzeichen übersprungen, so dass sich die Variable nun auf dem ersten Zeichen des zweiten Strings befindet. Und so geht es dann weiter bis alle Strings ausgelesen sind.
Danach kann der Puffer dann auch wieder freigegeben werden
finally FreeMem(buf,BUFSIZE); end;
denn nun steht uns ja unsere Stringliste zur Verfügung:
for i := 0 to length(kl) - 1 do MessageBox(0,pchar(kl[i]),pchar(inttostr(i+1)),0);
Die Topicnamen in dieser Liste benutzen wir nun zum Auslesen der Strings, die uns eigentlich interessieren. Benötigen wir auch die Stringliste nicht mehr, geben wir ihren Speicher ebenfalls wieder frei:
SetLength(kl,0);
Wenn wir schon dabei sind, dann wollen wir uns auch noch ansehen, wie wir sowohl Topicnamen als auch den dazu gehörenden Wert auf einmal lesen können. Dazu benutzen wir die Funktion "GetPrivateProfileSection".
Problematisch dabei ist, dass der Puffer unter Windows 95/98/ME nur max. 32k (32.767) groß sein darf, während es unter den NT-Systemen keine Beschränkung gibt (obwohl unser Beispiel dort auch "nur" einen 65k großen Puffer verwendet).
Gehen wir also davon aus, wir haben unseren Puffer entsprechend reserviert und initialisiert, dann können wir nun die Funktion aufrufen:
GetPrivateProfileSection(szNameKey,
buf,
dwLen,
pchar(ExtractFilePath(paramstr(0)) + szIniFile))
Wenn der Puffer nicht ausreicht, um alle Werte aufzunehmen, dann ist das Rückgabeergebnis der Funktion identisch mit der Puffergröße minus Zwei. Sie sollten also darauf achten! Andernfalls enthält der Puffer die Namen und Werte, die durch das Zeichen #0 voneinander getrennt sind.
Das Auslesen der einzelnen Strings kann wie oben beschrieben durchgeführt werden. Sie benötigen nur eine zusätzliche pchar-Variable, um von einem null-terminierten Strings zum nächsten zu gelangen. Angezeigt wird Ihnen dann sowohl der Topicname als auch der Wert, also z.B.
Paul=Paul
Wenn Sie alle Topics und Werte einer Sektion ermitteln können, dann können Sie natürlich auch die Namen aller Sektionen in einer INI-Datei herausfinden. Das entspricht der Funktion "ReadSections", die Sie vielleicht von der Unit "IniFiles.pas" kennen.
Wie gehabt: wir brauchen auch hier einen Puffer, der die Namen aufnehmen soll. Eine Maximalgröße wird im PSDK nicht genannt. Das Beispiel verwendet den üblichen 65k-Puffer; Sie können im Zweifelsfall einen größeren benutzen.
Mit Hilfe der Funktion "GetPrivateProfileSectionNames" lassen sich dann die Namen aller Sektionen in den Puffer schreiben:
GetPrivateProfileSectionNames(buf,BUFSIZE,
pchar(ExtractFilePath(paramstr(0)) + szIniFile));
Auch hier sind die einzelnen Namen wieder durch #0 voneinander getrennt, so dass Sie eine zusätzliche pchar-Variable benutzen können, um sie der Reihe nach in eine Stringliste o.ä. einzulesen:
p := buf; while(p^ <> #0) do begin SetLength(kl,length(kl)+1); kl[length(kl)-1] := p;
inc(p,lstrlen(p)+1); end;
Ist der Puffer zu klein, entspricht der Rückgabewert der Funktion wieder der Puffergröße minus Zwei.