-
Notifications
You must be signed in to change notification settings - Fork 250
feat(system): Load Uniscribe at runtime #3241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| #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<ScriptIsComplex_t>(::GetProcAddress(Module, "ScriptIsComplex")); | ||
| ScriptStringAnalysePtr = reinterpret_cast<ScriptStringAnalyse_t>(::GetProcAddress(Module, "ScriptStringAnalyse")); | ||
| ScriptStringFreePtr = reinterpret_cast<ScriptStringFree_t>(::GetProcAddress(Module, "ScriptStringFree")); | ||
| ScriptStringSizePtr = reinterpret_cast<ScriptStringSize_t>(::GetProcAddress(Module, "ScriptString_pSize")); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe keep the "_pSize" naming consistent across all variables? |
||
| ScriptStringOutPtr = reinterpret_cast<ScriptStringOut_t>(::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(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This calling Maybe return |
||
| } | ||
|
|
||
|
|
||
| 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) | ||
|
xezon marked this conversation as resolved.
|
||
| { | ||
| 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; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| #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); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are these made WINAPI? I see |
||
| 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(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current model does not allow to unload it. Is this acceptable? |
||
|
|
||
| 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; | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be part of the class?