Read all ini file values with GetPrivateProfileString
Asked Answered
C

5

16

I need a way to read all sections/keys of ini file in a StringBuilder variable:

[DllImport("kernel32.dll")]
private static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);

...

private List<string> GetKeys(string iniFile, string category)
{
    StringBuilder returnString = new StringBuilder(255);            

    GetPrivateProfileString(category, null, null, returnString, 32768, iniFile);

    ...
}

In returnString is only the first key value! How it is possible to get all at once and write it to the StringBuilder and to List?

Thank you for your help!

greets leon22

Cordwood answered 17/8, 2011 at 8:48 Comment(0)
C
26

Possible solution:

[DllImport("kernel32.dll")]
private static extern int GetPrivateProfileSection(string lpAppName, byte[] lpszReturnBuffer, int nSize, string lpFileName);

private List<string> GetKeys(string iniFile, string category)
{

    byte[] buffer = new byte[2048];

    GetPrivateProfileSection(category, buffer, 2048, iniFile);
    String[] tmp = Encoding.ASCII.GetString(buffer).Trim('\0').Split('\0');

    List<string> result = new List<string>();

    foreach (String entry in tmp)
    {
        result.Add(entry.Substring(0, entry.IndexOf("=")));
    }

    return result;
}
Cordwood answered 19/8, 2011 at 10:53 Comment(2)
Not completely correct: Not the whole lines, only the keys are returned (e.g. the split with "=" is useless since the value isn't returned). Also, it may return unicode strings, so the split up with 0-terminator doesn't work correctly and returns single characters.Tutto
This doesn't really answer the question, which specifically mentions wanting to use the StringBuilder class so we don't have to guess the maximum buffer size.Nowhither
S
2

I believe there's also GetPrivateProfileSection() that could help, but I agree with Zenwalker, there are libraries that could help with this. INI files aren't that hard to read: sections, key/value and comments is pretty much it.

Sacculate answered 17/8, 2011 at 8:57 Comment(0)
C
1

Why dont you use IniReader library to read INI files?? its easier and faster that way.

Cabbala answered 17/8, 2011 at 8:51 Comment(2)
Thanks! Have you an example or an link to this lib?Cordwood
@zenwalker “Since they rely on the Windows API […]” – That library uses the Win32 API itself, so it’s unlikely faster.Sacttler
O
0

These routines will read an entire INI section, and either return the section as a collection of raw strings where each entry is a single line in the INI file (useful if you're using the INI structure but don't necessarily have an =), and another that returns a collection of keyvalue pairs for all of the entries in the section.

    [DllImport("kernel32.dll")]
    public static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName);

    // ReSharper disable once ReturnTypeCanBeEnumerable.Global
    public static string[] GetIniSectionRaw(string section, string file) {
        string[] iniLines;
        GetPrivateProfileSection(section, file, out iniLines);
        return iniLines;
    }

    /// <summary> Return an entire INI section as a list of lines.  Blank lines are ignored and all spaces around the = are also removed. </summary>
    /// <param name="section">[Section]</param>
    /// <param name="file">INI File</param>
    /// <returns> List of lines </returns>
    public static IEnumerable<KeyValuePair<string, string>> GetIniSection(string section, string file) {
        var result = new List<KeyValuePair<string, string>>();
        string[] iniLines;
        if (GetPrivateProfileSection(section, file, out iniLines)) {
            foreach (var line in iniLines) {
                var m = Regex.Match(line, @"^([^=]+)\s*=\s*(.*)");
                result.Add(m.Success
                               ? new KeyValuePair<string, string>(m.Groups[1].Value, m.Groups[2].Value)
                               : new KeyValuePair<string, string>(line, ""));
            }
        }

        return result;
    }
Outspeak answered 10/1, 2016 at 0:16 Comment(1)
This code seems not to be working. GetIniSectionRaw is never called and the parameters of the functions are not matching.Sickener
F
0
Dim MyString    As String = String.Empty
Dim BufferSize As Integer = 1024 
Dim PtrToString As IntPtr = IntPtr.Zero
Dim RetVal As Integer
RetVal = GetPrivateProfileSection(SectionName, PtrToString, BufferSize, FileNameAndPah)

If our function call succeeds, we will get the result in PtrToString memory address and RetVal will contain the length of the string in PtrToString. Else if this function failed due to the lack of enough BufferSize Then RetVal will contain BufferSize - 2. So we can check it and call this function again with larger BufferSize.

'Now, here is how we can get the string from memory address.

MyString = Marshal.PtrToStringAuto(PtrToString, RetVal - 1)

'Here i use " RetVal - 1 " to avoid the extra null string.

' Now, we need to split the string where null chars coming.

Dim MyStrArray() As String = MyString.Split(vbNullChar)

So this array contains all your keyvalue pair in that specific section. And dont forget to free up the memory

Marshal.FreeHGlobal(PtrToString)
Floranceflore answered 9/12, 2017 at 20:17 Comment(1)
Obviously, this api function is slower than native file reading functions. I have wrote a function with managed code and it reads a whole section in 3350 ticks. And with this unmanaged code, the same section reading took 10650 ticks.Floranceflore

© 2022 - 2024 — McMap. All rights reserved.