diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index a45c23dc7..086f170f8 100644 --- a/src/m_specialpaths.cpp +++ b/src/m_specialpaths.cpp @@ -22,6 +22,8 @@ #if defined(_WIN32) +#include "i_system.h" + typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); //=========================================================================== @@ -73,18 +75,7 @@ bool UseKnownFolders() bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path) { - static GKFP SHGetKnownFolderPath = NULL; - static bool tested = false; - - if (!tested) - { - tested = true; - HMODULE shell32 = GetModuleHandle("shell32.dll"); - if (shell32 != NULL) - { - SHGetKnownFolderPath = (GKFP)GetProcAddress(shell32, "SHGetKnownFolderPath"); - } - } + static TOptWin32Proc SHGetKnownFolderPath("shell32.dll", "SHGetKnownFolderPath"); char pathstr[MAX_PATH]; @@ -92,6 +83,13 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create // new to Vista, hence the reason we support both. if (SHGetKnownFolderPath == NULL) { + static TOptWin32Proc + SHGetFolderPathA("shell32.dll", "SHGetFolderPathA"); + + // NT4 doesn't even have this function. + if (SHGetFolderPathA == NULL) + return false; + if (shell_folder < 0) { // Not supported by SHGetFolderPath return false; @@ -100,7 +98,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create { shell_folder |= CSIDL_FLAG_CREATE; } - if (FAILED(SHGetFolderPathA(NULL, shell_folder, NULL, 0, pathstr))) + if (FAILED(SHGetFolderPathA.Call(NULL, shell_folder, NULL, 0, pathstr))) { return false; } @@ -110,7 +108,7 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create else { PWSTR wpath; - if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) + if (FAILED(SHGetKnownFolderPath.Call(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) { return false; } diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 2dabe7de9..d25229b67 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1600,13 +1600,20 @@ unsigned int I_MakeRNGSeed() FString I_GetLongPathName(FString shortpath) { - DWORD buffsize = GetLongPathName(shortpath.GetChars(), NULL, 0); + static TOptWin32Proc + GetLongPathName("kernel32.dll", "GetLongPathNameA", NULL); + + // Doesn't exist on NT4 + if (GetLongPathName == NULL) + return shortpath; + + DWORD buffsize = GetLongPathName.Call(shortpath.GetChars(), NULL, 0); if (buffsize == 0) { // nothing to change (it doesn't exist, maybe?) return shortpath; } TCHAR *buff = new TCHAR[buffsize]; - DWORD buffsize2 = GetLongPathName(shortpath.GetChars(), buff, buffsize); + DWORD buffsize2 = GetLongPathName.Call(shortpath.GetChars(), buff, buffsize); if (buffsize2 >= buffsize) { // Failure! Just return the short path delete[] buff; diff --git a/src/win32/i_system.h b/src/win32/i_system.h index 647a08d13..6872ca232 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -51,6 +51,35 @@ typedef enum { extern os_t OSPlatform; +// Helper template so that we can access newer Win32 functions with a single static +// variable declaration. If this were C++11 it could be totally transparent. +template +class TOptWin32Proc +{ + static Proto GetOptionalWin32Proc(const char* module, const char* function, const char* alt) + { + HMODULE hmodule = GetModuleHandle(module); + if (hmodule == NULL) + return NULL; + + Proto ret = (Proto)GetProcAddress(hmodule, function); + if(ret != NULL || alt == NULL) + return ret; + + // Lookup alternate function name (ex. ProcW -> ProcA) + return (Proto)GetProcAddress(hmodule, alt); + } + +public: + const Proto Call; + + TOptWin32Proc(const char* module, const char* function, const char* alt=NULL) + : Call(GetOptionalWin32Proc(module, function, alt)) {} + + // Wrapper object can be tested against NULL, but not directly called. + operator const void*() const { return Call; } +}; + // Called by DoomMain. void I_Init (void); diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 8aa74bfb5..690bb5725 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -414,7 +414,10 @@ void Win32Video::DumpAdapters() HMONITOR hm = D3D->GetAdapterMonitor(i); MONITORINFOEX mi; mi.cbSize = sizeof(mi); - if (GetMonitorInfo(hm, &mi)) + + TOptWin32Proc GetMonitorInfo("user32.dll", "GetMonitorInfoW"); + assert(GetMonitorInfo != NULL); // Missing in NT4, but so is D3D + if (GetMonitorInfo.Call(hm, &mi)) { mysnprintf(moreinfo, countof(moreinfo), " [%ldx%ld @ (%ld,%ld)]%s", mi.rcMonitor.right - mi.rcMonitor.left,