diff --git a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt index 77721250c6c..a74cd8baf2c 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt @@ -162,6 +162,8 @@ if(WIN32) rcfile.h registry.cpp registry.h + Usp10Loader.cpp + Usp10Loader.h verchk.cpp verchk.h WWCOMUtil.cpp diff --git a/Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.cpp b/Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.cpp new file mode 100644 index 00000000000..e5685993aa5 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.cpp @@ -0,0 +1,111 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2026 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#include "Usp10Loader.h" +#include "mutex.h" + + +static CriticalSectionClass Usp10LoaderCriticalSection; + +HMODULE Usp10Loader::Module = HMODULE(nullptr); +bool Usp10Loader::LoadAttempted = false; +Usp10Loader::ScriptIsComplex_t Usp10Loader::ScriptIsComplexPtr = nullptr; +Usp10Loader::ScriptStringAnalyse_t Usp10Loader::ScriptStringAnalysePtr = nullptr; +Usp10Loader::ScriptStringFree_t Usp10Loader::ScriptStringFreePtr = nullptr; +Usp10Loader::ScriptStringSize_t Usp10Loader::ScriptStringSizePtr = nullptr; +Usp10Loader::ScriptStringOut_t Usp10Loader::ScriptStringOutPtr = nullptr; + + +bool Usp10Loader::load() +{ + CriticalSectionClass::LockClass lock(Usp10LoaderCriticalSection); + + if (LoadAttempted) { + return Module != HMODULE(nullptr); + } + LoadAttempted = true; + + char dll_path[MAX_PATH]; + const char dll_name[] = "\\usp10.dll"; + const UINT path_length = ::GetSystemDirectoryA(dll_path, ARRAY_SIZE(dll_path)); + if (path_length == 0 || path_length + ARRAY_SIZE(dll_name) > ARRAY_SIZE(dll_path)) { + return false; + } + strcpy(dll_path + path_length, dll_name); + + Module = ::LoadLibraryA(dll_path); + if (Module == HMODULE(nullptr)) { + return false; + } + + ScriptIsComplexPtr = reinterpret_cast(::GetProcAddress(Module, "ScriptIsComplex")); + ScriptStringAnalysePtr = reinterpret_cast(::GetProcAddress(Module, "ScriptStringAnalyse")); + ScriptStringFreePtr = reinterpret_cast(::GetProcAddress(Module, "ScriptStringFree")); + ScriptStringSizePtr = reinterpret_cast(::GetProcAddress(Module, "ScriptString_pSize")); + ScriptStringOutPtr = reinterpret_cast(::GetProcAddress(Module, "ScriptStringOut")); + + if (ScriptIsComplexPtr == nullptr || ScriptStringAnalysePtr == nullptr || ScriptStringFreePtr == nullptr || + ScriptStringSizePtr == nullptr || ScriptStringOutPtr == nullptr) + { + ::FreeLibrary(Module); + Module = HMODULE(nullptr); + return false; + } + + return true; +} + + +bool Usp10Loader::isLoaded() +{ + return load(); +} + + +HRESULT WINAPI Usp10Loader::ScriptIsComplex(const WCHAR *text, int text_length, DWORD flags) +{ + return load() ? ScriptIsComplexPtr(text, text_length, flags) : E_FAIL; +} + + +HRESULT WINAPI Usp10Loader::ScriptStringAnalyse(HDC dc, const void *text, int text_length, int glyph_count, + int charset, DWORD flags, int required_width, ScriptControl *control, ScriptState *state, + const int *spacing, ScriptTabDefinition *tabs, const BYTE *character_classes, ScriptStringAnalysis *analysis) +{ + return load() ? ScriptStringAnalysePtr(dc, text, text_length, glyph_count, charset, flags, required_width, + control, state, spacing, tabs, character_classes, analysis) : E_FAIL; +} + + +HRESULT WINAPI Usp10Loader::ScriptStringFree(ScriptStringAnalysis *analysis) +{ + return load() ? ScriptStringFreePtr(analysis) : E_FAIL; +} + + +const SIZE *WINAPI Usp10Loader::ScriptString_pSize(ScriptStringAnalysis analysis) +{ + return load() ? ScriptStringSizePtr(analysis) : nullptr; +} + + +HRESULT WINAPI Usp10Loader::ScriptStringOut(ScriptStringAnalysis analysis, int x, int y, UINT options, + const RECT *rect, int minimum_selection, int maximum_selection, BOOL disabled) +{ + return load() ? ScriptStringOutPtr(analysis, x, y, options, rect, minimum_selection, maximum_selection, disabled) : E_FAIL; +} diff --git a/Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.h b/Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.h new file mode 100644 index 00000000000..f6dfb8e4fea --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.h @@ -0,0 +1,71 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2026 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +#pragma once + +#include "win.h" + + +class Usp10Loader +{ +public: + + typedef void *ScriptStringAnalysis; + struct ScriptControl; + struct ScriptState; + struct ScriptTabDefinition; + + enum + { + SIC_COMPLEX = 0x00000001, + SSA_FALLBACK = 0x00000020, + SSA_GLYPHS = 0x00000080, + SSA_RTL = 0x00000100, + }; + + static bool isLoaded(); + + static HRESULT WINAPI ScriptIsComplex(const WCHAR *text, int text_length, DWORD flags); + static HRESULT WINAPI ScriptStringAnalyse(HDC dc, const void *text, int text_length, int glyph_count, + int charset, DWORD flags, int required_width, ScriptControl *control, ScriptState *state, + const int *spacing, ScriptTabDefinition *tabs, const BYTE *character_classes, + ScriptStringAnalysis *analysis); + static HRESULT WINAPI ScriptStringFree(ScriptStringAnalysis *analysis); + static const SIZE *WINAPI ScriptString_pSize(ScriptStringAnalysis analysis); + static HRESULT WINAPI ScriptStringOut(ScriptStringAnalysis analysis, int x, int y, UINT options, + const RECT *rect, int minimum_selection, int maximum_selection, BOOL disabled); + +private: + + static bool load(); + + typedef HRESULT (WINAPI *ScriptIsComplex_t)(const WCHAR *, int, DWORD); + typedef HRESULT (WINAPI *ScriptStringAnalyse_t)(HDC, const void *, int, int, int, DWORD, int, + ScriptControl *, ScriptState *, const int *, ScriptTabDefinition *, const BYTE *, ScriptStringAnalysis *); + typedef HRESULT (WINAPI *ScriptStringFree_t)(ScriptStringAnalysis *); + typedef const SIZE *(WINAPI *ScriptStringSize_t)(ScriptStringAnalysis); + typedef HRESULT (WINAPI *ScriptStringOut_t)(ScriptStringAnalysis, int, int, UINT, const RECT *, int, int, BOOL); + + static HMODULE Module; + static bool LoadAttempted; + static ScriptIsComplex_t ScriptIsComplexPtr; + static ScriptStringAnalyse_t ScriptStringAnalysePtr; + static ScriptStringFree_t ScriptStringFreePtr; + static ScriptStringSize_t ScriptStringSizePtr; + static ScriptStringOut_t ScriptStringOutPtr; +};