SDL: Fixed coding style and building on older Windows SDKs

From e0e95b1ea978fdf6234d8a8f3541854e0f12d711 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 4 May 2023 16:28:16 -0700
Subject: [PATCH] Fixed coding style and building on older Windows SDKs

---
 src/filesystem/windows/SDL_sysfilesystem.c | 292 ++++++++++-----------
 1 file changed, 139 insertions(+), 153 deletions(-)

diff --git a/src/filesystem/windows/SDL_sysfilesystem.c b/src/filesystem/windows/SDL_sysfilesystem.c
index 46acf098bb59..a7693e9ee151 100644
--- a/src/filesystem/windows/SDL_sysfilesystem.c
+++ b/src/filesystem/windows/SDL_sysfilesystem.c
@@ -26,17 +26,21 @@
 /* System dependent filesystem routines                                */
 
 #include "../../core/windows/SDL_windows.h"
-#include <errhandlingapi.h>
-#include <fileapi.h>
 #include <shlobj.h>
-#include <libloaderapi.h>
-/* Lowercase is necessary for Wine */
-#include <knownfolders.h>
-#include <initguid.h>
-#include <windows.h>
 
-char *
-SDL_GetBasePath(void)
+/* These aren't all defined in older SDKs, so define them here */
+DEFINE_KNOWN_FOLDER(SDL_FOLDERID_Profile, 0x5E6C858F, 0x0E22, 0x4760, 0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73);
+DEFINE_KNOWN_FOLDER(FOLDERID_Desktop, 0xB4BFCC3A, 0xDB2C, 0x424C, 0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41);
+DEFINE_KNOWN_FOLDER(FOLDERID_Documents, 0xFDD39AD0, 0x238F, 0x46AF, 0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7);
+DEFINE_KNOWN_FOLDER(FOLDERID_Downloads, 0x374de290, 0x123f, 0x4565, 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b);
+DEFINE_KNOWN_FOLDER(FOLDERID_Music, 0x4BD8D571, 0x6D19, 0x48D3, 0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43);
+DEFINE_KNOWN_FOLDER(FOLDERID_Pictures, 0x33E28130, 0x4E1E, 0x4676, 0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB);
+DEFINE_KNOWN_FOLDER(FOLDERID_SavedGames, 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4);
+DEFINE_KNOWN_FOLDER(FOLDERID_Screenshots, 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f);
+DEFINE_KNOWN_FOLDER(FOLDERID_Templates, 0xA63293E8, 0x664E, 0x48DB, 0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7);
+DEFINE_KNOWN_FOLDER(FOLDERID_Videos, 0x18989B1D, 0x99B5, 0x455B, 0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC);
+
+char *SDL_GetBasePath(void)
 {
     DWORD buflen = 128;
     WCHAR *path = NULL;
@@ -86,8 +90,7 @@ SDL_GetBasePath(void)
     return retval;
 }
 
-char *
-SDL_GetPrefPath(const char *org, const char *app)
+char *SDL_GetPrefPath(const char *org, const char *app)
 {
     /*
      * Vista and later has a new API for this, but SHGetFolderPath works there,
@@ -173,177 +176,160 @@ SDL_GetPrefPath(const char *org, const char *app)
     return retval;
 }
 
-char *
-SDL_GetPath(SDL_Folder folder)
+char *SDL_GetPath(SDL_Folder folder)
 {
-    typedef HRESULT (*SHGKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *);
-    char *retval;
+    typedef HRESULT (*pfnSHGetKnownFolderPath)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *);
     HMODULE lib = LoadLibrary(L"Shell32.dll");
-    SHGKFP SHGetKnownFolderPath_ = (SHGKFP) GetProcAddress(lib,
-                                                       "SHGetKnownFolderPath");
+    pfnSHGetKnownFolderPath pSHGetKnownFolderPath = NULL;
+    char *retval = NULL;
 
-    if (!SHGetKnownFolderPath_)
-    {
-        int type;
+    if (lib) {
+        pSHGetKnownFolderPath = (pfnSHGetKnownFolderPath)GetProcAddress(lib, "SHGetKnownFolderPath");
+    }
+
+    if (pSHGetKnownFolderPath) {
+        KNOWNFOLDERID type;
         HRESULT result;
-    	wchar_t path[MAX_PATH];
-
-        switch (folder)
-        {
-            case SDL_FOLDER_HOME:
-                type = CSIDL_PROFILE;
-                break;
-
-            case SDL_FOLDER_DESKTOP:
-                type = CSIDL_DESKTOP;
-                break;
-
-            case SDL_FOLDER_DOCUMENTS:
-                type = CSIDL_MYDOCUMENTS;
-                break;
-
-            case SDL_FOLDER_DOWNLOADS:
-                SDL_SetError("Downloads folder unavailable before Vista");
-                return NULL;
-
-            case SDL_FOLDER_MUSIC:
-                type = CSIDL_MYMUSIC;
-                break;
-
-            case SDL_FOLDER_PICTURES:
-                type = CSIDL_MYPICTURES;
-                break;
-
-            case SDL_FOLDER_PUBLICSHARE:
-                SDL_SetError("Public share unavailable on Windows");
-                return NULL;
-
-            case SDL_FOLDER_SAVEDGAMES:
-                SDL_SetError("Saved games unavailable before Vista");
-                return NULL;
-
-            case SDL_FOLDER_SCREENSHOTS:
-                SDL_SetError("Screenshots folder unavailable before Vista");
-                return NULL;
-
-            case SDL_FOLDER_TEMPLATES:
-                type = CSIDL_TEMPLATES;
-                break;
-
-            case SDL_FOLDER_VIDEOS:
-                type = CSIDL_MYVIDEO;
-                break;
-
-            default:
-                SDL_SetError("Unsupported SDL_Folder on Windows before Vista: %d",
-                              (int) folder);
-                return NULL;
-        };
+        wchar_t *path;
 
-        /* Create the OS-specific folder if it doesn't already exist */
-        type |= CSIDL_FLAG_CREATE;
+        switch (folder) {
+        case SDL_FOLDER_HOME:
+            type = FOLDERID_Profile;
+            break;
 
-#if 0
-        /* Apparently the oldest, but not supported in modern Windows */
-        HRESULT result = SHGetSpecialFolderPath(NULL, path, type, TRUE);
-#endif
+        case SDL_FOLDER_DESKTOP:
+            type = FOLDERID_Desktop;
+            break;
 
-        /* Windows 2000/XP and later, deprecated as of Windows 10 (still
-           available), available in Wine (tested 6.0.3) */
-        result = SHGetFolderPathW(NULL, type, NULL, SHGFP_TYPE_CURRENT, path);
+        case SDL_FOLDER_DOCUMENTS:
+            type = FOLDERID_Documents;
+            break;
 
-        /* use `!= TRUE` for SHGetSpecialFolderPath */
-        if (result != S_OK)
-        {
-            SDL_SetError("Couldn't get folder, windows-specific error: %ld",
-                         result);
-            return NULL;
-        }
+        case SDL_FOLDER_DOWNLOADS:
+            type = FOLDERID_Downloads;
+            break;
 
-        retval = (char *) SDL_malloc((SDL_wcslen(path) + 1) * 2);
-        if (retval == NULL)
-        {
-            SDL_OutOfMemory();
-            return NULL;
+        case SDL_FOLDER_MUSIC:
+            type = FOLDERID_Music;
+            break;
+
+        case SDL_FOLDER_PICTURES:
+            type = FOLDERID_Pictures;
+            break;
+
+        case SDL_FOLDER_PUBLICSHARE:
+            SDL_SetError("Public share unavailable on Windows");
+            goto done;
+
+        case SDL_FOLDER_SAVEDGAMES:
+            type = FOLDERID_SavedGames;
+            break;
+
+        case SDL_FOLDER_SCREENSHOTS:
+            type = FOLDERID_Screenshots;
+            break;
+
+        case SDL_FOLDER_TEMPLATES:
+            type = FOLDERID_Templates;
+            break;
+
+        case SDL_FOLDER_VIDEOS:
+            type = FOLDERID_Videos;
+            break;
+
+        default:
+            SDL_SetError("Invalid SDL_Folder: %d", (int)folder);
+            goto done;
+        };
+
+        result = pSHGetKnownFolderPath(&type, 0x00008000 /* KF_FLAG_CREATE */, NULL, &path);
+        if (SUCCEEDED(result)) {
+            retval = WIN_StringToUTF8W(path);
+        } else {
+            WIN_SetErrorFromHRESULT("Couldn't get folder", result);
         }
-        retval = WIN_StringToUTF8W(path);
-        return retval;
-    }
-    else
-    {
-        KNOWNFOLDERID type;
+
+    } else {
+        int type;
         HRESULT result;
-    	wchar_t *path;
+        wchar_t path[MAX_PATH];
 
-        switch (folder)
-        {
-            case SDL_FOLDER_HOME:
-                type = FOLDERID_Profile;
-                break;
+        switch (folder) {
+        case SDL_FOLDER_HOME:
+            type = CSIDL_PROFILE;
+            break;
 
-            case SDL_FOLDER_DESKTOP:
-                type = FOLDERID_Desktop;
-                break;
+        case SDL_FOLDER_DESKTOP:
+            type = CSIDL_DESKTOP;
+            break;
 
-            case SDL_FOLDER_DOCUMENTS:
-                type = FOLDERID_Documents;
-                break;
+        case SDL_FOLDER_DOCUMENTS:
+            type = CSIDL_MYDOCUMENTS;
+            break;
 
-            case SDL_FOLDER_DOWNLOADS:
-                type = FOLDERID_Downloads;
-                break;
+        case SDL_FOLDER_DOWNLOADS:
+            SDL_SetError("Downloads folder unavailable before Vista");
+            goto done;
 
-            case SDL_FOLDER_MUSIC:
-                type = FOLDERID_Music;
-                break;
+        case SDL_FOLDER_MUSIC:
+            type = CSIDL_MYMUSIC;
+            break;
 
-            case SDL_FOLDER_PICTURES:
-                type = FOLDERID_Pictures;
-                break;
+        case SDL_FOLDER_PICTURES:
+            type = CSIDL_MYPICTURES;
+            break;
 
-            case SDL_FOLDER_PUBLICSHARE:
-                SDL_SetError("Public share unavailable on Windows");
-                return NULL;
+        case SDL_FOLDER_PUBLICSHARE:
+            SDL_SetError("Public share unavailable on Windows");
+            goto done;
 
-            case SDL_FOLDER_SAVEDGAMES:
-                type = FOLDERID_SavedGames;
-                break;
+        case SDL_FOLDER_SAVEDGAMES:
+            SDL_SetError("Saved games unavailable before Vista");
+            goto done;
 
-            case SDL_FOLDER_SCREENSHOTS:
-                type = FOLDERID_Screenshots;
-                break;
+        case SDL_FOLDER_SCREENSHOTS:
+            SDL_SetError("Screenshots folder unavailable before Vista");
+            goto done;
 
-            case SDL_FOLDER_TEMPLATES:
-                type = FOLDERID_Templates;
-                break;
+        case SDL_FOLDER_TEMPLATES:
+            type = CSIDL_TEMPLATES;
+            break;
 
-            case SDL_FOLDER_VIDEOS:
-                type = FOLDERID_Videos;
-                break;
+        case SDL_FOLDER_VIDEOS:
+            type = CSIDL_MYVIDEO;
+            break;
 
-            default:
-                SDL_SetError("Invalid SDL_Folder: %d", (int) folder);
-                return NULL;
+        default:
+            SDL_SetError("Unsupported SDL_Folder on Windows before Vista: %d",
+                         (int)folder);
+            goto done;
         };
 
-        result = SHGetKnownFolderPath_(&type, KF_FLAG_CREATE, NULL, &path);
+        /* Create the OS-specific folder if it doesn't already exist */
+        type |= CSIDL_FLAG_CREATE;
 
-        if (result != S_OK)
-        {
-            SDL_SetError("Couldn't get folder, windows-specific error: %ld",
-                         result);
-            return NULL;
-        }
+#if 0
+        /* Apparently the oldest, but not supported in modern Windows */
+        HRESULT result = SHGetSpecialFolderPath(NULL, path, type, TRUE);
+#endif
 
-        retval = (char *) SDL_malloc((SDL_wcslen(path) + 1) * 2);
-        if (retval == NULL)
-        {
-            SDL_OutOfMemory();
-            return NULL;
+        /* Windows 2000/XP and later, deprecated as of Windows 10 (still
+           available), available in Wine (tested 6.0.3) */
+        result = SHGetFolderPathW(NULL, type, NULL, SHGFP_TYPE_CURRENT, path);
+
+        /* use `== TRUE` for SHGetSpecialFolderPath */
+        if (SUCCEEDED(result)) {
+            retval = WIN_StringToUTF8W(path);
+        } else {
+            WIN_SetErrorFromHRESULT("Couldn't get folder", result);
         }
-        retval = WIN_StringToUTF8W(path);
-        return retval;
     }
+
+done:
+    if (lib) {
+        FreeLibrary(lib);
+    }
+    return retval;
 }
 
 #endif /* SDL_FILESYSTEM_WINDOWS */