Managing INI Configuration Files in C# via Windows API

Working with classic INI files in C# relies on native Windows functions: GetPrivateProfileString and WritePrivateProfileString. This article demonstrates a clean wrapper and a practical configuration manager built around them.

Sample INI structure

Assume a file named AppSettings.ini:

[FtpServer]
IP=127.0.0.1
Port=21
UserName=user
Password=user

Encapsulating the kernel32 calls

Create a static helper that exposes read and write operations with automatic type conversion.

public static class IniFile
{
    [DllImport("kernel32", CharSet = CharSet.Unicode)]
    private static extern long WritePrivateProfileString(
        string section, string key, string val, string path);

    [DllImport("kernel32", CharSet = CharSet.Unicode)]
    private static extern int GetPrivateProfileString(
        string section, string key, string def,
        StringBuilder buffer, int size, string path);

    public static string GetString(string section, string key, string fallback, string filePath)
    {
        var sb = new StringBuilder(512);
        GetPrivateProfileString(section, key, fallback, sb, sb.Capacity, filePath);
        return sb.ToString();
    }

    public static int GetInt(string section, string key, int fallback, string filePath)
    {
        var raw = GetString(section, key, fallback.ToString(), filePath);
        return int.TryParse(raw, out int result) ? result : fallback;
    }

    public static void SetValue(string section, string key, string value, string filePath)
    {
        WritePrivateProfileString(section, key, value, filePath);
    }
}

Thread-safe configuration manager

Below is a singleton that loads FTP settings on demand and allows udpating them while persisting changes back to disk.

internal sealed class AppConfiguration
{
    public string FtpAddress { get; private set; }
    public int FtpPort { get; private set; }
    public string FtpUser { get; private set; }
    public string FtpPass { get; private set; }

    private readonly string _configPath =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AppSettings.ini");

    private static readonly ILog Log =
        LogManager.GetLogger(typeof(AppConfiguration));

    public void Load()
    {
        try
        {
            FtpAddress = IniFile.GetString("FtpServer", "IP", "127.0.0.1", _configPath);
            FtpPort     = IniFile.GetInt("FtpServer", "Port", 21, _configPath);
            FtpUser     = IniFile.GetString("FtpServer", "UserName", "user", _configPath);
            FtpPass     = IniFile.GetString("FtpServer", "Password", "user", _configPath);
        }
        catch (Exception ex)
        {
            Log.Error($"INI load error: {ex.Message}");
        }
    }

    public void UpdateFtp(string address, int port, string user, string pass)
    {
        FtpAddress = address;
        FtpPort    = port;
        FtpUser    = user;
        FtpPass    = pass;

        try
        {
            IniFile.SetValue("FtpServer", "IP", address, _configPath);
            IniFile.SetValue("FtpServer", "Port", port.ToString(), _configPath);
            IniFile.SetValue("FtpServer", "UserName", user, _configPath);
            IniFile.SetValue("FtpServer", "Password", pass, _configPath);
        }
        catch (Exception ex)
        {
            Log.Error($"FTP update failed: {ex.Message}");
            throw;
        }
    }

    #region Singleton

    private static readonly object Padlock = new object();
    private static AppConfiguration _instance;

    private AppConfiguration() { }

    public static AppConfiguration Current
    {
        get
        {
            if (_instance != null) return _instance;
            lock (Padlock)
            {
                _instance = _instance ?? new AppConfiguration();
            }
            return _instance;
        }
    }

    #endregion
}

Tags: C# ini Windows API configuration

Posted on Tue, 19 May 2026 20:14:58 +0000 by noobcody