Skip to content

feat(system): Load Uniscribe at runtime - #3241

Open
OmarAglan wants to merge 1 commit into
TheSuperHackers:mainfrom
OmarAglan:feature/usp10-loader
Open

feat(system): Load Uniscribe at runtime#3241
OmarAglan wants to merge 1 commit into
TheSuperHackers:mainfrom
OmarAglan:feature/usp10-loader

Conversation

@OmarAglan

Copy link
Copy Markdown

Adds a small Windows-only loader for the five Uniscribe functions required by the complex-text renderer.

The loader resolves the functions from the system usp10.dll at runtime and reports failure to callers when Uniscribe is unavailable. This allows #3231 to retain the existing per-character renderer as its fallback while removing the compile-time dependency on usp10.h and usp10.lib, which are missing from the VC6 SDK.

Cross-platform text shaping remains outside this focused compatibility change.

The stacked result was validated with:

  • Visual Studio 2022 x86 Release builds of Generals and Zero Hour
  • The repository’s exact portable VC6 toolchain for Generals and Zero Hour
  • Verification that the resulting executables do not statically import usp10.dll
  • git diff --check

The change was developed with AI assistance, then manually reviewed against the nearby runtime-loader pattern and the official Windows SDK function declarations.

@OmarAglan
OmarAglan marked this pull request as ready for review August 31, 2026 20:18
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Load required Uniscribe APIs dynamically on Windows

✨ Enhancement 🕐 10-20 Minutes

Grey Divider

AI Description

• Loads five Uniscribe APIs dynamically from Windows’ system usp10.dll.
• Reports unavailable libraries or exports so renderers can retain existing fallbacks.
• Provides SDK-independent declarations compatible with the portable VC6 toolchain.
Diagram

graph TD
    Renderer["Text renderer"] --> Loader["Usp10 loader"] --> Attempt{"First attempt?"}
    Attempt -->|Yes| DLL["System usp10.dll"] --> Exports["Five exports"] --> Status["Cached status"]
    Attempt -->|No| Status
Loading
High-Level Assessment

The runtime-loader approach is appropriate for this compatibility-focused change: it avoids unavailable VC6 SDK headers and import libraries, prevents a static usp10.dll dependency, loads only from the Windows system directory, and exposes failure for the renderer’s existing fallback. Static linking and linker delay-loading were considered but would retain toolchain or import-table dependencies, while a general-purpose loader abstraction would add unnecessary scope for five tightly related APIs.

Files changed (3) +184 / -0

Enhancement (2) +182 / -0
Usp10Loader.cppResolve and wrap Uniscribe exports at runtime +111/-0

Resolve and wrap Uniscribe exports at runtime

• Implements thread-safe, one-time loading of 'usp10.dll' from the Windows system directory and resolves five required exports. Wrapper methods return 'E_FAIL' or 'nullptr' when the DLL or any required function is unavailable, allowing callers to fall back safely.

Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.cpp

Usp10Loader.hDeclare SDK-independent Uniscribe wrappers +71/-0

Declare SDK-independent Uniscribe wrappers

• Defines the minimal opaque types, flags, function signatures, and loader state required by the complex-text renderer without including 'usp10.h'. The public static API mirrors the required Uniscribe calls while hiding dynamic-resolution details.

Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.h

Other (1) +2 / -0
CMakeLists.txtBuild the Uniscribe loader on Windows +2/-0

Build the Uniscribe loader on Windows

• Adds the loader implementation and header to WWLib’s Windows-only source list, keeping non-Windows builds unaffected.

Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a Windows-only WWLib loader that resolves the five required Uniscribe functions from the system DLL at runtime, avoiding a compile-time SDK and linker dependency.

  • Registers the loader sources for Windows WWLib targets.
  • Loads usp10.dll from the Windows system directory and validates all required exports.
  • Provides synchronized, failure-reporting wrappers around the resolved functions.

Confidence Score: 5/5

The PR appears safe to merge; no concrete build, ABI, lifecycle, or runtime failure remains reachable in the changed code.

The loader is limited to Windows targets, follows the repository’s established runtime-loader and compiler-compatibility patterns, validates every required export before use, and exposes ABI-compatible guarded wrappers.

Important Files Changed

Filename Overview
Core/Libraries/Source/WWVegas/WWLib/CMakeLists.txt Adds the loader implementation and header to the Windows-only WWLib source set.
Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.cpp Implements synchronized one-time loading, complete export validation, and guarded wrappers without an accepted defect.
Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.h Declares compatible opaque Uniscribe types, constants, wrapper signatures, and function-pointer storage.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Caller[Complex-text renderer] --> Wrapper[Usp10Loader wrapper]
    Wrapper --> Load{Loader initialized?}
    Load -->|No| System[Load system usp10.dll]
    System --> Resolve[Resolve five exports]
    Resolve -->|All present| Call[Invoke Uniscribe function]
    Resolve -->|Missing or unavailable| Fallback[Return failure for renderer fallback]
    Load -->|Yes| Call
Loading

Reviews (1): Last reviewed commit: "feat(system): Load Uniscribe at runtime" | Re-trigger Greptile

#include "mutex.h"


static CriticalSectionClass Usp10LoaderCriticalSection;

Copy link
Copy Markdown

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?


bool Usp10Loader::isLoaded()
{
return load();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This calling load looks strange.

Maybe return return Module != HMODULE(nullptr); ?


static bool isLoaded();

static HRESULT WINAPI ScriptIsComplex(const WCHAR *text, int text_length, DWORD flags);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these made WINAPI?

I see DbgHelpLoader does the same but it probably should not have.

Comment thread Core/Libraries/Source/WWVegas/WWLib/Usp10Loader.cpp

private:

static bool load();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current model does not allow to unload it. Is this acceptable?

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"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe keep the "_pSize" naming consistent across all variables?

@OmarAglan

Copy link
Copy Markdown
Author

@codex

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 68a4beb2f0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants