From abbe60e74c495b94809f0171c16b2db7040a2ee0 Mon Sep 17 00:00:00 2001 From: xomx Date: Sun, 8 Dec 2024 03:30:07 +0100 Subject: [PATCH] Allow using the Scintilla DirectWrite in non-Core Windows Server Fix #15916, close #15921 --- PowerEditor/src/MISC/Common/Common.cpp | 60 +++++++++++++++++++ PowerEditor/src/MISC/Common/Common.h | 2 + PowerEditor/src/Parameters.h | 2 +- .../ScintillaComponent/ScintillaEditView.cpp | 12 +++- .../WinControls/Preference/preferenceDlg.cpp | 1 + 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 9ab45d9e3..8df09af21 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -1905,6 +1905,7 @@ bool doesPathExist(const wchar_t* path, DWORD milliSec2wait, bool* isTimeoutReac return (attributes.dwFileAttributes != INVALID_FILE_ATTRIBUTES); } + #if defined(__GNUC__) #define LAMBDA_STDCALL __attribute__((__stdcall__)) #else @@ -1957,3 +1958,62 @@ bool isWindowVisibleOnAnyMonitor(const RECT& rectWndIn) ::EnumDisplayMonitors(NULL, &rectVirtualScreen, callback, reinterpret_cast(¶m4InOut)); return param4InOut.isWndVisibleOut; } + +#pragma warning(disable:4996) // 'GetVersionExW': was declared deprecated +bool isCoreWindows() +{ + bool isCoreWindows = false; + + // older Windows (Windows Server 2008 R2-) check 1st + OSVERSIONINFOEXW osviex{}; + osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + if (::GetVersionEx(reinterpret_cast(&osviex))) + { + DWORD dwReturnedProductType = 0; + if (::GetProductInfo(osviex.dwMajorVersion, osviex.dwMinorVersion, osviex.wServicePackMajor, osviex.wServicePackMinor, &dwReturnedProductType)) + { + switch (dwReturnedProductType) + { + case PRODUCT_STANDARD_SERVER_CORE: + case PRODUCT_STANDARD_A_SERVER_CORE: + case PRODUCT_STANDARD_SERVER_CORE_V: + case PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE: + case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE: + case PRODUCT_ENTERPRISE_SERVER_CORE: + case PRODUCT_ENTERPRISE_SERVER_CORE_V: + case PRODUCT_DATACENTER_SERVER_CORE: + case PRODUCT_DATACENTER_A_SERVER_CORE: + case PRODUCT_DATACENTER_SERVER_CORE_V: + case PRODUCT_STORAGE_STANDARD_SERVER_CORE: + case PRODUCT_STORAGE_WORKGROUP_SERVER_CORE: + case PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE: + case PRODUCT_STORAGE_EXPRESS_SERVER_CORE: + case PRODUCT_WEB_SERVER_CORE: + isCoreWindows = true; + } + } + } + + if (!isCoreWindows) + { + // in Core Server 2012+, the recommended way to determine is via the Registry + HKEY hKey = nullptr; + if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + constexpr size_t bufLen = 127; + wchar_t wszBuf[bufLen + 1]{}; // +1 ... to be always NULL-terminated string + DWORD dataSize = sizeof(wchar_t) * bufLen; + if (::RegQueryValueExW(hKey, L"InstallationType", nullptr, nullptr, reinterpret_cast(&wszBuf), &dataSize) == ERROR_SUCCESS) + { + if (lstrcmpiW(wszBuf, L"Server Core") == 0) + isCoreWindows = true; + } + ::RegCloseKey(hKey); + hKey = nullptr; + } + } + + return isCoreWindows; +} +#pragma warning(default:4996) diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 9ad19654c..eb66830a7 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -292,3 +292,5 @@ bool doesPathExist(const wchar_t* path, DWORD milliSec2wait = 0, bool* isTimeout // check if the window rectangle intersects with any currently active monitor's working area bool isWindowVisibleOnAnyMonitor(const RECT& rectWndIn); + +bool isCoreWindows(); diff --git a/PowerEditor/src/Parameters.h b/PowerEditor/src/Parameters.h index 6b6f2d41d..1cef400a9 100644 --- a/PowerEditor/src/Parameters.h +++ b/PowerEditor/src/Parameters.h @@ -117,7 +117,7 @@ enum ChangeDetect { cdDisabled = 0x0, cdEnabledOld = 0x01, cdEnabledNew = 0x02, enum BackupFeature {bak_none = 0, bak_simple = 1, bak_verbose = 2}; enum OpenSaveDirSetting {dir_followCurrent = 0, dir_last = 1, dir_userDef = 2}; enum MultiInstSetting {monoInst = 0, multiInstOnSession = 1, multiInst = 2}; -enum writeTechnologyEngine {defaultTechnology = 0, directWriteTechnology = 1}; +enum writeTechnologyEngine {defaultTechnology = 0, directWriteTechnology = 1, directWriteTechnologyUnavailable = 2}; enum urlMode {urlDisable = 0, urlNoUnderLineFg, urlUnderLineFg, urlNoUnderLineBg, urlUnderLineBg, urlMin = urlDisable, urlMax = urlUnderLineBg}; diff --git a/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp index bba5ad04e..765788209 100644 --- a/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScintillaComponent/ScintillaEditView.cpp @@ -320,8 +320,16 @@ void ScintillaEditView::init(HINSTANCE hInst, HWND hPere) isWINE = ::GetProcAddress(hNtdllModule, "wine_get_version"); if (isWINE || // There is a performance issue under WINE when DirectWrite is ON, so we turn it off if user uses Notepad++ under WINE - ::IsWindowsServer()) // In the case of Windows Server Core, DirectWrite cannot be on. - nppGui._writeTechnologyEngine = defaultTechnology; + isCoreWindows()) // In the case of Windows Server Core, DirectWrite cannot be on. + { + nppGui._writeTechnologyEngine = directWriteTechnologyUnavailable; + } + else + { + // allow IDC_CHECK_DIRECTWRITE_ENABLE to be set in Preferences > MISC. again + if (nppGui._writeTechnologyEngine == directWriteTechnologyUnavailable) + nppGui._writeTechnologyEngine = defaultTechnology; + } if (nppGui._writeTechnologyEngine == directWriteTechnology) { diff --git a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp index d50919db3..bbb74a308 100644 --- a/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp +++ b/PowerEditor/src/WinControls/Preference/preferenceDlg.cpp @@ -2487,6 +2487,7 @@ intptr_t CALLBACK MiscSubDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM) ::SendDlgItemMessage(_hSelf, IDC_CHECK_DETECTENCODING, BM_SETCHECK, nppGUI._detectEncoding, 0); ::SendDlgItemMessage(_hSelf, IDC_CHECK_SAVEALLCONFIRM, BM_SETCHECK, nppGUI._saveAllConfirm, 0); ::SendDlgItemMessage(_hSelf, IDC_CHECK_AUTOUPDATE, BM_SETCHECK, nppGUI._autoUpdateOpt._doAutoUpdate, 0); + ::EnableWindow(::GetDlgItem(_hSelf, IDC_CHECK_DIRECTWRITE_ENABLE), nppGUI._writeTechnologyEngine != directWriteTechnologyUnavailable); ::SendDlgItemMessage(_hSelf, IDC_CHECK_DIRECTWRITE_ENABLE, BM_SETCHECK, nppGUI._writeTechnologyEngine == directWriteTechnology, 0); ::SendDlgItemMessage(_hSelf, IDC_CHECK_ENABLEDOCPEEKER, BM_SETCHECK, nppGUI._isDocPeekOnTab ? BST_CHECKED : BST_UNCHECKED, 0); ::SendDlgItemMessage(_hSelf, IDC_CHECK_ENABLEDOCPEEKONMAP, BM_SETCHECK, nppGUI._isDocPeekOnMap ? BST_CHECKED : BST_UNCHECKED, 0);