Project Specific Instruction
August 9, 2026 ยท View on GitHub
Solution to Work On
You are working on the solution REPO-ROOT/Test/GacUISrc/GacUISrc.sln,
therefore SOLUTION-ROOT is REPO-ROOT/Test/GacUISrc.
Files not Allowed to Modify
Files in these folders (recursively) are not allowed to modify.
You can only change them using what is described in the Code Generation Projects section.
If you encounter any error that prevent these files from being generated,
always fix the root cause.
REPO-ROOT/Test/Resources/MetadataREPO-ROOT/Test/GacUISrc/Generated_DarkSkinREPO-ROOT/Test/GacUISrc/Generated_DialogsREPO-ROOT/Test/GacUISrc/Generated_FullControlTestREPO-ROOT/Test/GacUISrc/Generated_RemoteProtocolTestREPO-ROOT/Test/GacUISrc/Generated_RemoteViewModelTestREPO-ROOT/Test/GacUISrc/Generated_UnitTestViewerREPO-ROOT/Source/Utilities/FakeServices/Dialogs/SourceREPO-ROOT/Source/UnitTestUtilities/SnapshotViewer/SourceREPO-ROOT/Source/Compiler/InstanceQuery/GeneratedREPO-ROOT/Source/Compiler/RemoteProtocol/Generated
Files in REPO-ROOT/Import and REPO-ROOT/Release (recursively) are also not allowed to modify.
These files are prepared for foreign dependencies.
Source/Utilities/AutomationService
The reusable MiniHTTP and Windows HTTP automation endpoints live in this folder and are compiled through Test/GacUISrc/Source_GacUI_Core/Source_GacUI_Core.vcxitems.
MiniHttpAutomationService.*is CodePacked intoRelease/GacUI.handRelease/GacUI.cpp.Windows/WindowsAutomationService.Windows.*is CodePacked intoRelease/GacUI.Windows.handRelease/GacUI.Windows.cpp.- Standalone test applications receive these implementations through their GacUI library dependency; they do not import
Source_RemotingHelpersfor automation.
Test/RemotingHelpers
Files in this folder are for test apps only:
- Only test apps could use these source files.
- No need to create unit test for them.
- Source files in
Sourcecannot use anything inTest/RemotingHelpers. - They are excluded from ordinary public GacUI amalgamations and the aggregate
Releaserepository. GacUI CodePack emits dedicated neutral, Windows, and Linux pairs (Test.RemotingHelpers*) inReleaseandRelease/IncludeOnlyonly for platform repositories'Import-Testsnapshots. - No production quality required, these files are only for building test apps quickly.
Test/RemotingHelpers/Rvmt
Files in this folder are generic client and requester helpers used only by CppTest_Rvm, RemotingTest_Core, and RemotingTest_RvmHost.
- They are enumerated and compiled through the single
Test/GacUISrc/Source_RemotingHelpers/Source_RemotingHelpers.vcxitemsinventory shared by all helper consumers. ViewModelShared.howns generic aliases, fixed RVM channel/control constants, and inline Ready-message helpers;ViewModelHostClient.*owns the generic network-side host client; andViewModelHostServer.*owns the specialized channel server's generic RPC helpers and server-side local-client behavior.- Generated RemoteViewModelTest RPC composition belongs to
Test/GacUISrc/Generated_RemoteViewModelTest/RemoteViewModelTestInitialize.*, which each affected application invokes after its generic connection is assigned a client ID. Release/CodegenConfig.xmlscans this helper tree only into the dedicated test pairs. OrdinaryGacUI*pairs and the aggregateReleaserepository remain independent of these helpers.
Test/RemotingHelpers/StdioRedirection
This folder implements the test-only stdio transport behind the platform-neutral StdioRedirectionServer, StdioRedirectionClient, and StdioRedirectionConnection names.
- Shared code owns callback-safe connection lifecycle and one-line UTF-8/Base64 framing. Exact
!Exitis the only raw control line; ordinary serialized channel packages remain opaqueWStringmessages. StdioRedirection.Windows.cppowns Windows process and anonymous-pipe work.StdioRedirection.Linux.cppowns the shared Linux/macOSfork/pipe implementation.- The server launches no process in
Start. EachConnectNewClientcall launches and owns one independent child;Stopsends!Exit, drains callbacks and readers, and reaps every child. - The unconditional
Source_RemotingHelpers.vcxitemsinventory lists every platform translation unit. Portablevmakeinputs remove only the Windows implementation.
Reflectable Types
- You must be really careful when changing any interface, especially structs, classes, unions and a few functions.
- Check if the class and the method is registered in reflection.
- Reflection allow registering normal functions into a class, becoming its static functions. It is not easy to determine by the function definition itself.
- You must read the knowledge base about reflection and try to find the pattern in any *.cpp file.
- If the reflection registration is affected, you should always fix the reflection and run necessary code generation projects.
Projects for Verification
You are required to follow the guideline to run any project in this solution, do not run the compiled binary directly.
The REPO-ROOT/Test/GacUISrc/UnitTest/UnitTest.vcxproj is the unit test project.
When any *.h or *.cpp file is changed, unit test is required to run.
Except for the GuiRemoteRendererSingle class which is not covered in the unit test.
When any test case fails, you must fix the issue immediately, even those errors are unrelated to the issue you are working on.
For any GacUI specific unit test that running with the GacUI unit test framework,
when it calls GacUIUnitTest_StartFast_WithResourceAsText with path, for example, Application/Windows/Order,
running it ends up creating log files in REPO-ROOT/Test/Resources/UnitTestSnapshots/Application/Windows:
- Order.json: an entry of snapshots for this test case
- Order[].: log files about remote protocol recordings and compiler output
- Order/Frame_*.json: snapshot of the UI DOM tree for each frame.
Each Frame_*.json is captured at each OnNextIdleFrame call, recording what the UI look like before running the code in this frame.
This is the reason why the name of the frame should say what the previous frame was done,
so that frame names in snapshot files make sense.
Code Generation Tools
REPO-ROOT/../Tools/Tools/GlrParserGen.exe
This executable needs to run if any file in the following folders are changed:
REPO-ROOT/Source/Compiler/InstanceQuery/SyntaxREPO-ROOT/Source/Compiler/RemoteProtocol/Syntax
There is a Parser.xml file in these folder.
You need to offer the absolute path of Parser.xml to the tool as a command-line argument.
Only run necessary Parser.xml in folders that are changed.
Code Generation Projects
Code generation projects are CLI projects. They are required to run when a certain set of files are changed, in order to generate code paring with them. Here are a list of projects to run and files that should trigger them:
Metadata_Generate and Metadata_Test
These two projects need to run if any reflection code is touched:
GuiReflection*.cppis updated.GacUI_Compilerproject is executed.
To execute these projects, you should:
- Build the solution with Debug|Win32.
- Run
Metadata_Generatewith Debug|Win32. - Build the solution with Debug|x64.
- Run
Metadata_Generatewith Debug|x64. - Run
Metadata_Testwith Debug|x64.
It generates binary metadata files containing type informations from reflection code. This step cannot be skipped after changing any reflection code, because GacUI_Compiler and some other test applications consume these binary metadata files.
Metadata_UpdateProtocol
This project need to run if REPO-ROOT/Source/PlatformProviders/Remote/Protocol/*.txt is updated.
It generates REPO-ROOT/Source/PlatformProviders/Remote/Generated/*.
GacUI_Compiler
This project need to run if any of the following XML file is updated:
REPO-ROOT/Source/Utilities/FakeServices/Dialog/*.xml-> generatesREPO-ROOT/Source/Utilities/FakeServices/Dialog/Source/*.REPO-ROOT/Source/UnitTestUtilities/SnapshotViewer/*.xml-> generatesREPO-ROOT/Source/UnitTestUtilities/SnapshotViewer/Source/*.REPO-ROOT/Test/Resources/App/DarkSkin/*.xml-> generatesREPO-ROOT/Test/GacUISrc/Generated_DarkSkin/Source_(x86|x64)/*.- IMPORTANT:
REPO-ROOT/Source/Skins/DarkSkinhas another copy, this is used by the CI and is not involved in this solution, ignore it.
- IMPORTANT:
REPO-ROOT/Test/Resources/App/FullControlTest/*.xml-> generatesREPO-ROOT/Test/GacUISrc/Generated_FullControlTest/Source_(x86|x64)/*.REPO-ROOT/Test/Resources/App/RemoteProtocolTest/*.xml-> generatesREPO-ROOT/Test/GacUISrc/Generated_RemoteProtocolTest/Source_(x86|x64)/*.REPO-ROOT/Test/Resources/App/RemoteViewModelTest/*.xml-> generates ordinary and RPC C++ inREPO-ROOT/Test/GacUISrc/Generated_RemoteViewModelTest/Source_(x86|x64)/*.
After running GacUI_Compiler, you should always git status to find if there is any untracked *.UI.errors.txt.
- Such file means there are compile errors in some xml files, read it to find the detail.
- You don't need to delete the file, if
GacUI_Compilersucceeds the next time, they will be gone. GacUI_Compilermay also fail by printing one line of error message or return non-zero exit code. If the*.UI.errors.txtfile does not exist, you are recommended to debug the project to find out what happened.- Whenever
GacUI_Compilerreports any error, you must fix the issue immediately, even those errors are unrelated to the issue you are working on.
Maintaining darkskin::Theme
This is a default skin that not only releases, but also used by all projects in this solution. To make a change:
- Update
REPO-ROOT/Test/Resources/DarkSkin. - Run
GacUI_Compilerand make sure it updated generated C++ code expectely.- Sometimes reordering could happen in generated C++ code even when correlated resource is not changed.
- Rebuild before running any test project.
Debugging Remote Protocol Issues
Use REPO-ROOT/DebugRemoteProtocolSop.md for the shared end-to-end UI operations and
observable results.
Remote protocol is involved in three ways:
- Core with native renderer:
REPO-ROOT/DebugRemoteProtocolWithNativeRenderer.md. - Core with
GacJS:REPO-ROOT/DebugRemoteProtocolWithGacJS.md. UnitTest, some e2e test cases are running on top of a unit test only remote protocol renderer, which is designed to save snapshots of UI between frames atREPO-ROOT/Test/Resources/UnitTestSnapshots.
Running core always uses network protocols. Three ways are calling three different renderer implementations, but with the same core implementation. By careful tell if a bug repro in some or all three ways, you can easily narrow down the scope of the possible cause.
Remote Protocol HTTP Disconnection Contract
- The HTTP remote protocol consists of
/Connect,/Request, and/Response. Do not add a reverse/Disconnectendpoint or require a renderer-to-core shutdown handshake. - A renderer can close independently while the core remains available, and another renderer can connect later. If a new renderer connects while an old renderer is still active, accepting the new renderer drops the old connection and token.
- HTTP 404 on an old renderer request after replacement means that renderer's connection is no longer active. After a VlppOS channel has connected, its
IChannelClientimplementation promotes this and every other local protocol error to a fatal local channel error because delivery is no longer reliable. - If the core has exited, an error from an outstanding or subsequent renderer request, including 404 or another transport failure, is handled by the same channel-level fatal transition. The renderer acts on that callback directly, without requiring
OnDisconnected, stops emitting requests, and presents its ordinary disconnected state rather than a fatal transport prompt. - Core shutdown does not wait for a renderer acknowledgement. Requests that reach the core while it is still serving should receive their normal protocol response when possible; errors after the core has stopped are expected.
Maintaining Test Apps
Test apps means CppTest* and RemotingTest*, they are demos and do not require production level quality.
No need to gracefully handle any exception, actually we need them to just crash when anything unexpected thing happens, that's how we know anything in REPO-ROOT/Source is going wrong.
REPO-ROOT/DebugRemoteProtocolSop.md defines the expected behavior of these test apps apon connection/disconnection.
Keep test apps simple without introducing unnecessary "gracefully recovering".
Windows Specific
Automation HTTP service for GUI applications are available for Windows:
CppTest: Run FullControlTest in hosted mode, built without reflection (VCZH_DEBUG_NO_REFLECTION).CppTest_Rvm: Run RemoteViewModelTest in hosted mode after acquiring its service fromRemotingTest_RvmHost;/Cli:<path>auto-launches that host with/Cli.CppTest_Metaonly: Run FullControlTest, built with metaonly reflection (VCZH_DEBUG_METAONLY_REFLECTION).CppTest_Reflection: Run FullControlTest, built with full reflection.GacUI_Host: Run FullControlTest, by loading Workflow binary assembly instead of generated C++ code.Playground: RunREPO-ROOT/Test/GacUISrc/Playground/Resources/Resource*.xml, resource file to load specified, main window specified inOpenMainWindowfunction.RemotingTest_Core: Run FullControlTest, RemoteProtocolTest, or RemoteViewModelTest with renderer traffic hosted by HTTP, MiniHTTP, or NamedPipe;/RVMTmay independently use/Cli:<path>for its host.RemotingTest_Rendering_Win32: Renderer ofRemotingTest_Core.RemotingTest_RvmHost: Provide the remote view-model service used byCppTest_RvmandRemotingTest_Core /RVMT, including the stdio/Climode.
FullControlTest means Generated_FullControlTest.vcxitems, generated from REPO-ROOT/Test/Resources/App/FullControlTest/Resource.xml.
RemoteProtocolTest means Generated_RemoteProtocolTest.vcxitems, generated from REPO-ROOT/Test/Resources/App/RemoteProtocolTest/Resource.xml.
RemoteViewModelTest means Generated_RemoteViewModelTest.vcxitems, generated from REPO-ROOT/Test/Resources/App/RemoteViewModelTest/Resource.xml.
When FakeDialogService is used, all system dialogs are replaced by REPO-ROOT/Source/Utilities/FakeServices/Dialogs/Resource.xml.
For the non-remoting projects above, the automation endpoint is http://localhost:8888/Automation/<PROJECT-NAME>/... and is hosted by StartWindowsHttpAutomationService.
- Checkout
REPO-ROOT/.github/Guidelines/Running-GacUI.mdfor details.
Each application owns its automation stack directly. It constructs the concrete service matching its setup (WindowsAutomationService, WindowsAutomationServiceHosted, WindowsAutomationServiceRenderer, RemoteProtocolAutomationService, or a platform renderer service), substitutes it, starts the selected Windows HTTP or MiniHTTP endpoint, runs the application, then stops the endpoint and service before unsubstituting it. Both endpoint implementations expose the same Controls, Dom, and IO contract.
Both RemotingTest_Core and RemotingTest_Rendering_Win32 expose automation in /Http, /Pipe, and /MiniHttp modes:
RemotingTest_Coreexposes the UI as a window-control tree athttp://localhost:8888/Automation/RemotingTest_Core/....RemotingTest_Rendering_Win32exposes the UI as a DOM tree athttp://localhost:<renderer-port>/Automation/RemotingTest_Rendering_Native/.... Pass/port:<renderer-port>to select the automation port; omitting it keeps the default port8889./Httpand/PipeuseStartWindowsHttpAutomationService.- In
/MiniHttpmode, the core registers its automation prefix with the exact sameIAsyncSocketServerthat hosts the remote protocol on port8888. The renderer is a separate process, so it hosts its automation prefix with a separate MiniHTTP socket server on the selected renderer automation port (default8889). - Both support IO operations:
- When performing IO via the renderer, remote protocol events pass the IO operations to the core.
- When performing IO via the core, the renderer only receives UI updates and redraws.
- Core and renderer should synchronize to the same UI state afterwards.
- Performing IO through either the renderer or the core should result in the same UI state.
RVM RPC uses the exact logical channels ViewModelChannel and ViewModelReadyChannel; renderers use GacUIRemoteProtocol. Core-to-renderer transport and Core-to-host mode are separate dimensions:
- Without
/Cli,RemotingTest_Core /RVMTand its manually startedRemotingTest_RvmHostshare the selected/Pipe,/Http, or/MiniHttpserver. Start Core, then the host with the same selector, then start the renderer after Core automation containsRemote View Model Test. - With
/Cli:<nonempty-host-path>, Core still requires/RVMTand one renderer transport. It starts a renderer-only server plus a host-only stdio server, quotes the path, and auto-launchesRemotingTest_RvmHost /Cli; do not start that host manually. Stop order is host server first, renderer server second. CppTest_Rvmaccepts exactly one of/Pipe,/Http,/MiniHttp, or/Cli:<nonempty-host-path>. The first three wait for a manually started host using the same selector./Cliauto-launches the host and is itself the exclusive RVM transport. This variant never uses a renderer.RemotingTest_RvmHostaccepts exact/Cliin addition to its network selectors. In stdio mode, stdin/stdout are reserved for framed protocol traffic and the ordinary startup banner is suppressed.- A requester terminates with an error if
RemotingTest_RvmHostdisconnects while the application is running. CppTest_Rvmexposes automation athttp://localhost:8888/Automation/CppTest_Rvm/..../Pipe,/Http, and/Cliuse the Windows HTTP endpoint;/MiniHttpregisters MiniHTTP automation on the same port-8888 socket server that carries its RVM traffic.
Playground is for adhoc testing:
- The UI in resource file, including
GuiMainandOpenMainWindow, could be modified freely without any concern, it is not part of the release. DO NOT revertPlaygroundchange as I can also use it for manual verification. - Actual resource files to load is specified in
GuiMain. - Actual theme type and main window type is specified in
OpenMainWindow. - All candidate resource files to load are supposed to put in the same folder, and add to the same solution explorer folder in
Playgroundproject.
Linux/macOS Specific
REPO-ROOT/Test/Linux stores linux configurations for:
Metadata_Generate:Metadata_Generate.vcxproj.Metadata_Test:Metadata_Test.vcxproj.CppTest:CppTest.vcxproj.CppTest_Metaonly:CppTest_Metaonly.vcxproj.CppTest_Reflection:CppTest_Reflection.vcxproj.GacUI_Compiler:GacUI_Compiler.vcxproj.RemotingTest_Core:RemotingTest_Core.vcxproj.RemotingTest_RvmHost:RemotingTest_RvmHost/vmake.UnitTest:UnitTest.vcxproj.
Metadata_UpdateProtocol is not included. If it is needed, create it and remove this line.
You need to build, test and debug in that specific folder, otherwise the unit test will not function properly. On Linux, only configuration "debug x64" is available, no need to build or run projects with other configurations. Unlike Windows, building have to be done in each folder separately.
CppTest_Rvm is Windows-only in this solution. The portable RVM demo is RemotingTest_Core /RVMT with /MiniHttp for renderers; its host is either manually started with /MiniHttp or auto-launched with /Cli:<path>. Linux/macOS stdio code is shared by StdioRedirection.Linux.cpp.