From 75471df7877f23fe39a1e1784186388c6622bf00 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 24 Apr 2015 22:26:57 -0400 Subject: [PATCH 1/2] - Made a few Win32 calls optional in order to restore capatibility with Windows NT 4.0 (not that anyone is using NT 4, but it was a trivial fix) --- src/m_specialpaths.cpp | 26 ++++++++++++-------------- src/win32/i_system.cpp | 11 +++++++++-- src/win32/i_system.h | 29 +++++++++++++++++++++++++++++ src/win32/win32video.cpp | 5 ++++- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index a45c23dc79..086f170f8f 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 2dabe7de9a..5b6a69c638 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", "GetLongPathNameW", "GetLongPathNameA"); + + // 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 647a08d134..6872ca232c 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 8aa74bfb58..690bb5725b 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, From 682f3e230a382f72342e43ee8f0c603f211c3314 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Apr 2015 09:08:59 +0200 Subject: [PATCH 2/2] - fixed: We should not try calling unicode functions on ASCII strings. Should ZDoom ever switch to unicode I_GetLongPathName will have to be adjusted, but for now it must call GetLongPathNameA, not GetLongPathNameW. --- src/win32/i_system.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 5b6a69c638..d25229b672 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1601,7 +1601,7 @@ unsigned int I_MakeRNGSeed() FString I_GetLongPathName(FString shortpath) { static TOptWin32Proc - GetLongPathName("kernel32.dll", "GetLongPathNameW", "GetLongPathNameA"); + GetLongPathName("kernel32.dll", "GetLongPathNameA", NULL); // Doesn't exist on NT4 if (GetLongPathName == NULL)