diff --git a/inc/config.h b/inc/config.h
index 381df22..709a800 100644
--- a/inc/config.h
+++ b/inc/config.h
@@ -1,8 +1,8 @@
 #ifndef CONFIG_H
 #define CONFIG_H
 
-#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
+#include "ini.h"
 
 #define FILE_EXISTS(a) (GetFileAttributes(a) != INVALID_FILE_ATTRIBUTES)
 
@@ -15,6 +15,7 @@ typedef struct CNCDDRAWCONFIG
     char game_path[MAX_PATH];
     char process_file_name[MAX_PATH];
     char process_file_ext[MAX_PATH];
+    INIFILE ini;
     
     /* Optional settings */
 
diff --git a/inc/ini.h b/inc/ini.h
index 9b73604..ee88575 100644
--- a/inc/ini.h
+++ b/inc/ini.h
@@ -1,6 +1,20 @@
 #ifndef INI_H
 #define INI_H
 
-BOOL ini_section_exists(char* section);
+typedef struct
+{
+    char filename[MAX_PATH];
+
+    struct {
+        unsigned long hash;
+        char* data;
+    }*sections;
+} INIFILE;
+
+void ini_create(INIFILE* ini, char* filename);
+DWORD ini_get_string(INIFILE* ini, LPCSTR section, LPCSTR key, LPCSTR def, LPSTR buf, DWORD size);
+BOOL ini_get_bool(INIFILE* ini, LPCSTR section, LPCSTR key, BOOL def);
+int ini_get_int(INIFILE* ini, LPCSTR section, LPCSTR key, int def);
+void ini_free(INIFILE* ini);
 
 #endif
diff --git a/src/config.c b/src/config.c
index 55b0e0a..a96644c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -106,6 +106,8 @@ void cfg_load()
     GET_BOOL(g_config.mgs_hack, "mgs_hack", FALSE);
 
     GameHandlesClose = GameHandlesClose || g_config.infantryhack;
+
+    ini_free(&g_config.ini);
 }
 
 void cfg_save()
@@ -1098,31 +1100,25 @@ static void cfg_init()
     {
         cfg_create_ini();
     }
+
+    ini_create(&g_config.ini, g_config.ini_path);
 }
 
 static DWORD cfg_get_string(LPCSTR key, LPCSTR default_value, LPSTR out_string, DWORD out_size)
 {
-    if (!g_config.ini_path[0])
-        cfg_init();
-
     char buf[MAX_PATH] = { 0 };
 
-    if (ini_section_exists(g_config.process_file_name))
-    {
-        DWORD s = GetPrivateProfileStringA(
-            g_config.process_file_name, key, "", out_string, out_size, g_config.ini_path);   
+    DWORD s = ini_get_string(&g_config.ini, g_config.process_file_name, key, "", out_string, out_size);
 
-        if (s > 0)
+    if (s > 0)
+    {
+        if (ini_get_string(&g_config.ini, g_config.process_file_name, "checkfile", "", buf, sizeof(buf)) > 0)
         {
-            if (GetPrivateProfileStringA(
-                g_config.process_file_name, "checkfile", "", buf, sizeof(buf), g_config.ini_path) > 0)
-            {
-                if (FILE_EXISTS(buf))
-                    return s;
-            }
-            else
+            if (FILE_EXISTS(buf))
                 return s;
         }
+        else
+            return s;
     }
 
     for (int i = 2; i < 10; i++)
@@ -1130,22 +1126,19 @@ static DWORD cfg_get_string(LPCSTR key, LPCSTR default_value, LPSTR out_string,
         char section[MAX_PATH] = { 0 };
         _snprintf(section, sizeof(section) - 1, "%s/%d", g_config.process_file_name, i);
 
-        if (ini_section_exists(section))
-        {
-            DWORD s = GetPrivateProfileStringA(section, key, "", out_string, out_size, g_config.ini_path);
+        DWORD s = ini_get_string(&g_config.ini, section, key, "", out_string, out_size);
 
-            if (s > 0)
+        if (s > 0)
+        {
+            if (ini_get_string(&g_config.ini, section, "checkfile", "", buf, sizeof(buf)) > 0)
             {
-                if (GetPrivateProfileStringA(section, "checkfile", "", buf, sizeof(buf), g_config.ini_path) > 0)
-                {
-                    if (FILE_EXISTS(buf))
-                        return s;
-                }
+                if (FILE_EXISTS(buf))
+                    return s;
             }
         }
     }
 
-    return GetPrivateProfileStringA("ddraw", key, default_value, out_string, out_size, g_config.ini_path);
+    return ini_get_string(&g_config.ini, "ddraw", key, default_value, out_string, out_size);
 }
 
 static BOOL cfg_get_bool(LPCSTR key, BOOL default_value)
diff --git a/src/ini.c b/src/ini.c
index 38c42bc..69456b5 100644
--- a/src/ini.c
+++ b/src/ini.c
@@ -1,49 +1,173 @@
 #include <windows.h>
+#include <stdio.h>
 #include "debug.h"
 #include "config.h"
 #include "crc32.h"
+#include "ini.h"
 
-static unsigned long g_ini_section_hashes[1024];
+// Microsoft: The maximum profile section size is 32,767 characters.
+#define BUF_SIZE (8192)
 
-BOOL ini_section_exists(char* section)
+void ini_create(INIFILE* ini, char* filename)
 {
-    if (!g_ini_section_hashes[0])
-    {
-        char* buf = calloc(8192, 1);
-        if (buf)
-        {
-            if (GetPrivateProfileSectionNamesA(buf, 8192, g_config.ini_path) > 0)
-            {
-                for (int i = 0; *buf && i < sizeof(g_ini_section_hashes) / sizeof(g_ini_section_hashes[0]); i++)
-                {
-                    size_t len = strlen(buf);
+    if (!ini || !filename || !filename[0])
+        return;
 
-                    for (char* p = buf; *p; ++p) 
+    ini->sections = calloc(sizeof(ini->sections[0]), 1);
+    if (ini->sections)
+    {
+        strncpy(ini->filename, filename, sizeof(ini->filename) - 1);
+
+        char* names = calloc(BUF_SIZE, 1);
+        if (names)
+        {
+            if (GetPrivateProfileSectionNamesA(names, BUF_SIZE, filename) > 0)
+            {
+                char* name = names;
+
+                for (int i = 0; *name; i++)
+                {
+                    ini->sections = realloc(ini->sections, sizeof(ini->sections[0]) * (i + 2));
+
+                    if (!ini->sections)
+                        return;
+
+                    memset(&ini->sections[i + 1], 0, sizeof(ini->sections[0]));
+
+                    char* buf = malloc(BUF_SIZE);
+                    if (buf)
+                    {
+                        DWORD size = GetPrivateProfileSectionA(name, buf, BUF_SIZE, ini->filename);
+                        if (size > 0)
+                        {
+                            ini->sections[i].data = malloc(size + 2);
+                            if (ini->sections[i].data)
+                            {
+                                memcpy(ini->sections[i].data, buf, size + 2);
+                            }
+                        }
+
+                        free(buf);
+                    }
+
+                    size_t len = strlen(name);
+
+                    for (char* p = name; *p; ++p)
                         *p = tolower(*p);
 
-                    g_ini_section_hashes[i] = Crc32_ComputeBuf(0, buf, len);
+                    ini->sections[i].hash = Crc32_ComputeBuf(0, name, len);
 
-                    buf += len + 1;
+                    name += len + 1;
                 }
             }
-            
-            free(buf);
+
+            free(names);
         }
     }
+}
+
+DWORD ini_get_string(INIFILE* ini, LPCSTR section, LPCSTR key, LPCSTR def, LPSTR buf, DWORD size)
+{
+    if (!buf || size == 0)
+    {
+        return 0;
+    }  
+
+    if (!ini || !ini->sections || !section || !key)
+    {
+        goto end;
+    }
+
+    size_t key_len = strlen(key);
+
+    if (key_len == 0 || strlen(section) == 0)
+    {
+        goto end;
+    }
 
     char s[MAX_PATH];
     strncpy(s, section, sizeof(s) - 1);
+    buf[sizeof(s) - 1] = 0;
 
     for (char* p = s; *p; ++p)
         *p = tolower(*p);
-
+    
     unsigned long hash = Crc32_ComputeBuf(0, s, strlen(s));
-
-    for (int i = 0; i < sizeof(g_ini_section_hashes) / sizeof(g_ini_section_hashes[0]) && g_ini_section_hashes[i]; i++)
+  
+    for (int i = 0; ini->sections[i].hash; i++)
     {
-        if (g_ini_section_hashes[i] == hash)
-            return TRUE;
+        if (ini->sections[i].hash == hash)
+        {
+            if (!ini->sections[i].data)
+                break;
+
+            for (char* p = ini->sections[i].data; *p; p += strlen(p) + 1)
+            {
+                if (_strnicmp(key, p, key_len) == 0 && p[key_len] == '=')
+                {
+                    strncpy(buf, &p[key_len + 1], size - 1);
+                    buf[size - 1] = 0;
+                    return strlen(buf);
+                }
+            }
+
+            break;
+        }
     }
 
-    return FALSE;
+end:
+    if (def)
+    {
+        strncpy(buf, def, size - 1);
+        buf[size - 1] = 0;
+        return strlen(buf);
+    }
+    
+    buf[0] = 0;
+
+    return 0;
+}
+
+BOOL ini_get_bool(INIFILE* ini, LPCSTR section, LPCSTR key, BOOL def)
+{
+    char value[8];
+    ini_get_string(ini, section, key, def ? "Yes" : "No", value, sizeof(value));
+
+    return (_stricmp(value, "yes") == 0 || _stricmp(value, "true") == 0 || _stricmp(value, "1") == 0);
+}
+
+int ini_get_int(INIFILE* ini, LPCSTR section, LPCSTR key, int def)
+{
+    char def_str[32];
+    _snprintf(def_str, sizeof(def_str) - 1, "%d", def);
+
+    char value[32];
+    ini_get_string(ini, section, key, def_str, value, sizeof(value));
+
+    if (strstr(value, "0x"))
+    {
+        return strtol(value, NULL, 0);
+    }
+    else
+    {
+        return atoi(value);
+    }
+}
+
+void ini_free(INIFILE* ini)
+{
+    if (ini->sections)
+    {
+        for (int i = 0; ini->sections[i].hash; i++)
+        {
+            if (ini->sections[i].data)
+            {
+                free(ini->sections[i].data);
+                ini->sections[i].data = NULL;
+            }  
+        }
+
+        free(ini->sections);
+        ini->sections = NULL;
+    }
 }