mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-08-17 09:21:41 +08:00
Run CDB directly
This commit is contained in:
@@ -157,6 +157,10 @@ object, causing missing of a complete picture.
|
|||||||
- Such finalization includes but not limited to:
|
- Such finalization includes but not limited to:
|
||||||
- Free an object or memory (`Ptr<T>` is a good example).
|
- Free an object or memory (`Ptr<T>` is a good example).
|
||||||
- Release a lock (`SPIN_LOCK` and other similar macros are good examples).
|
- Release a lock (`SPIN_LOCK` and other similar macros are good examples).
|
||||||
|
- If an exception is surely going to crash the app and nothing will recover from it:
|
||||||
|
- It usually means that under the situation, ensuring finalization to execute might bring no benefits.
|
||||||
|
- In this case, just call finalization as if there will be no exception, no RAII or try-catch is needed here.
|
||||||
|
- Such scenario is very usual in test apps. In shared library it is less likely to happen.
|
||||||
|
|
||||||
## Keep C++ Code Cross Platform
|
## Keep C++ Code Cross Platform
|
||||||
|
|
||||||
|
|||||||
@@ -7,43 +7,42 @@
|
|||||||
## Windows Specific
|
## Windows Specific
|
||||||
|
|
||||||
Debugging can be useful when you lack necessary information.
|
Debugging can be useful when you lack necessary information.
|
||||||
This section offers a set of PowerShell scripts that work with CDB (Microsoft's Console Debugger).
|
|
||||||
CDB accepts exactly the same commands as WinDBG.
|
CDB accepts exactly the same commands as WinDBG.
|
||||||
|
|
||||||
### Start a Debugger
|
### Start a Debugger
|
||||||
|
|
||||||
Read `REPO-ROOT/Project.md` to understand the solution folder and the unit test project name you are working with.
|
Read `REPO-ROOT/Project.md` to understand the solution folder and the unit test project name you are working with.
|
||||||
Additional information can be found in the first line of `REPO-ROOT/.github/Scripts/Execute.log`.
|
Additional information can be found in the first line of `REPO-ROOT/.github/Scripts/Execute.log`.
|
||||||
Execute the following PowerShell commands:
|
Choose the executable for the intended configuration and read its arguments from the matching `*.vcxproj.user` file.
|
||||||
|
|
||||||
```
|
Run CDB directly from `SOLUTION-ROOT` in a PTY-backed tool session:
|
||||||
|
|
||||||
|
```powershell
|
||||||
cd SOLUTION-ROOT
|
cd SOLUTION-ROOT
|
||||||
start powershell {& REPO-ROOT\.github\Scripts\copilotDebug_Start.ps1 -Executable PROJECT-NAME}
|
& $env:CDBPATH -lines "ABSOLUTE-PATH-TO-EXECUTABLE" ARGUMENTS
|
||||||
```
|
```
|
||||||
|
|
||||||
If the debugger is already started, this script will fail because the pipe name is occupied. That probably means the last time you forgot to stop the debugger. You can kill `cdb` and the process being debugged, before starting a new debugger.
|
Keep the session ID returned by the tool. The process is paused at the initial breakpoint, giving you a chance to configure source mode and set breakpoints. Send these commands as newline-terminated stdin, one round at a time, and wait for output between rounds:
|
||||||
|
|
||||||
The `start powershell {}` is necessary; otherwise the script will block the execution forever, causing you to wait infinitely.
|
```text
|
||||||
The script will finish immediately, leaving a debugger running in the background. You can send commands to the debugger.
|
l+s;l+t
|
||||||
The process being debugged is paused at the beginning; you are given a chance to set breakpoints.
|
g
|
||||||
After you are ready, send the `g` command to start running.
|
```
|
||||||
|
|
||||||
|
Do not leave unbounded debugger output flowing through the terminal. If output repeats continuously, interrupt execution immediately and configure the relevant exception or output filter before continuing.
|
||||||
|
|
||||||
### Stop a Debugger
|
### Stop a Debugger
|
||||||
|
|
||||||
- Kill `cdb` process first, if any.
|
- If the debugged process is running or stuck, send Ctrl-C (`\u0003`).
|
||||||
- The cdb path is stored in `$env:CDBPATH`.
|
- Send `q` to terminate the debugged process and CDB.
|
||||||
- Kill the binary process that is blocked.
|
- If CDB does not respond, terminate the exact CDB process first and then the exact debugged process.
|
||||||
|
|
||||||
### Sending Commands to Debugger
|
### Sending Commands to CDB
|
||||||
|
|
||||||
```
|
Send commands to the same PTY-backed session. The effect of commands lasts for the whole session. For example, after you execute `.frame X`, you do not need to repeat it to use `dx` under the same call stack frame later.
|
||||||
& REPO-ROOT\.github\Scripts\copilotDebug_RunCommand.ps1 -Command "Commands"
|
|
||||||
```
|
|
||||||
|
|
||||||
The effect of commands lasts across multiple `copilotDebug_RunCommand.ps1` calls. For example, after you execute `.frame X`, you do not need to repeat it to use `dx` under the same call stack frame in later calls, as `.frame X` is already effective.
|
|
||||||
|
|
||||||
Multiple commands can be executed in sequence, separated by ";".
|
Multiple commands can be executed in sequence, separated by ";".
|
||||||
The debugger is configured to use source mode, which means you can see source files and line numbers in the call stack, and step in/out/over work line by line.
|
The `-lines` option and the `l+s;l+t` commands enable source mode, which means you can see source files and line numbers in the call stack, and step in/out/over work line by line.
|
||||||
CDB accepts exactly the same commands as WinDBG, and here are some recommended commands:
|
CDB accepts exactly the same commands as WinDBG, and here are some recommended commands:
|
||||||
- **g**: continue until hitting a breakpoint or crashing.
|
- **g**: continue until hitting a breakpoint or crashing.
|
||||||
- **k**n: print current call stack.
|
- **k**n: print current call stack.
|
||||||
@@ -57,8 +56,8 @@ CDB accepts exactly the same commands as WinDBG, and here are some recommended c
|
|||||||
- **t**: step in, aka execute the current line, if any function is called, goes into the function.
|
- **t**: step in, aka execute the current line, if any function is called, goes into the function.
|
||||||
- **pt**: step out, aka run until the end of the current function.
|
- **pt**: step out, aka run until the end of the current function.
|
||||||
|
|
||||||
An `.natvis` file is automatically provided with the debugger,
|
Load the installed `vlpp.natvis` file with `.nvload` when structured visualization is needed.
|
||||||
it formats some primitive types defined in the `Vlpp` project,
|
It formats some primitive types defined in the `Vlpp` project,
|
||||||
including `WString` and other string types, `Nullable`, `Variant`, container types, etc.
|
including `WString` and other string types, `Nullable`, `Variant`, container types, etc.
|
||||||
The formatting applies to the **dx** command,
|
The formatting applies to the **dx** command,
|
||||||
when you want to see raw data instead of formatted printing,
|
when you want to see raw data instead of formatted printing,
|
||||||
@@ -70,7 +69,6 @@ You can also use `dv -rX` to expand "X" levels of fields. The default option is
|
|||||||
|
|
||||||
- Only use **dv** without any parameters.
|
- Only use **dv** without any parameters.
|
||||||
- DO NOT use **dt**.
|
- DO NOT use **dt**.
|
||||||
- DO NOT use **q**, **qd**, **qq**, **qqd** etc. to stop the debugger.
|
|
||||||
|
|
||||||
## Linux/macOS Specific
|
## Linux/macOS Specific
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ When the model `gpt-5.3-codex-spark` is available:
|
|||||||
|
|
||||||
## Windows Specific
|
## Windows Specific
|
||||||
|
|
||||||
- You are strongly recommended to attach a debugger when running any GacUI application.
|
|
||||||
- Because some runtime exceptions are silently consumed by Windows causing the application not to crash, covering issues if no debugger is attached.
|
|
||||||
- GacUI applications could end up in dead loop or dead locks, so DO NOT JUST wait for the process to exit.
|
- GacUI applications could end up in dead loop or dead locks, so DO NOT JUST wait for the process to exit.
|
||||||
- When it is crashed, sometimes (but not always) a native dialog would show and block the process.
|
- When it is crashed, sometimes (but not always) a native dialog would show and block the process.
|
||||||
- Native dialogs could be proactivately called from a GacUI application, even when `FakeDialogService` is not used.
|
- Native dialogs could be proactivately called from a GacUI application, even when `FakeDialogService` is not used.
|
||||||
@@ -25,6 +23,12 @@ When the model `gpt-5.3-codex-spark` is available:
|
|||||||
This is a very useful way for coding agent to debug GacUI applications.
|
This is a very useful way for coding agent to debug GacUI applications.
|
||||||
Computer use via UI Automation may not work when the computer screen is locked.
|
Computer use via UI Automation may not work when the computer screen is locked.
|
||||||
|
|
||||||
|
Automation is composed explicitly by each application:
|
||||||
|
- Construct the concrete automation service that matches the active controller: `WindowsAutomationService` for an ordinary Windows app, `WindowsAutomationServiceHosted` for hosted mode, `WindowsAutomationServiceRenderer` for a Windows remote renderer, `RemoteProtocolAutomationService` for a remote core, or the platform renderer service on Linux/macOS.
|
||||||
|
- Substitute that service with `GetNativeServiceSubstitution()->Substitute` before starting an endpoint.
|
||||||
|
- Start either the Windows HTTP endpoint or the MiniHTTP endpoint, run the application, then stop the endpoint, call `Stop` on the service, and unsubstitute it in that order.
|
||||||
|
- Endpoint selection changes the transport only. Windows HTTP and MiniHTTP expose the same `Controls`, `Dom`, and `IO` contract described below.
|
||||||
|
|
||||||
When `StartWindowsHttpAutomationService` is used during startup up a GacUI application:
|
When `StartWindowsHttpAutomationService` is used during startup up a GacUI application:
|
||||||
- It listens to `http://localhost:<port>/Automation/<applicationName>/...`.
|
- It listens to `http://localhost:<port>/Automation/<applicationName>/...`.
|
||||||
- GET `.../Controls`, for GacUI applications, exposing all visible windows and popups.
|
- GET `.../Controls`, for GacUI applications, exposing all visible windows and popups.
|
||||||
|
|||||||
@@ -28,6 +28,17 @@ Runtime type information retrieval and manipulation through the reflection syste
|
|||||||
|
|
||||||
[API Explanation](./KB_VlppReflection_TypeMetadata.md)
|
[API Explanation](./KB_VlppReflection_TypeMetadata.md)
|
||||||
|
|
||||||
|
#### Metaonly Metadata Generation and Loading
|
||||||
|
|
||||||
|
Generate binary reflection metadata as either an independently loadable file or a layer that depends on types registered from previous files.
|
||||||
|
|
||||||
|
- Use `CollectRegisteredTypes` after loading a base type manager to capture descriptors supplied by previous layers
|
||||||
|
- Pass an empty exclusion list to `GenerateMetaonlyTypes` for a self-contained file
|
||||||
|
- Pass a captured descriptor list to omit foreign metadata records while preserving references to those types
|
||||||
|
- Load and activate every dependency before reading a dependent file with `LoadMetaonlyTypes`
|
||||||
|
|
||||||
|
[API Explanation](./KB_VlppReflection_GenerateMetaonlyTypes.md)
|
||||||
|
|
||||||
#### Type Registration Structure
|
#### Type Registration Structure
|
||||||
|
|
||||||
Organized approach for registering types with proper file organization and macro usage.
|
Organized approach for registering types with proper file organization and macro usage.
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ Protocol types are code-generated from `Protocol/*.txt` files into `GuiRemotePro
|
|||||||
|
|
||||||
`GuiRemoteProtocolAsyncJsonChannel` is the core-side async wrapper around an `IJsonChannel`. It queues outgoing packages, queues incoming events for `ProcessRemoteEvents()`, stores incoming responses by request id, and blocks `BatchWrite(disconnected)` until the current `PendingRequestGroup` is satisfied or disconnected. `connectionCounter` and `connectionClientId` protect pending requests when channel events arrive after disconnect/reconnect boundaries.
|
`GuiRemoteProtocolAsyncJsonChannel` is the core-side async wrapper around an `IJsonChannel`. It queues outgoing packages, queues incoming events for `ProcessRemoteEvents()`, stores incoming responses by request id, and blocks `BatchWrite(disconnected)` until the current `PendingRequestGroup` is satisfied or disconnected. `connectionCounter` and `connectionClientId` protect pending requests when channel events arrive after disconnect/reconnect boundaries.
|
||||||
|
|
||||||
`GuiRemoteProtocolAsyncJsonChannelRenderer` is the renderer-side async wrapper. It queues received packages and schedules `ProcessRemoteMessages()` through an `IGuiRemoteProtocolAsyncRendererInvoker`. Before `SetInvokeInMainThread(...)` is called by renderer `GuiMain`, packages are cached. After the invoker is installed, they are drained on the renderer UI thread. `Initialize(reader)` requires a non-null reader; `Detach()` explicitly clears it, increments `messageVersion`, and drops queued work. The version check prevents callbacks queued before `Detach()` from running after detachment or a later reader installation.
|
`GuiRemoteProtocolAsyncJsonChannelRenderer` is the renderer-side async wrapper. It queues received packages and main-thread tasks, then schedules `ProcessPendingMessages()` through an `IGuiRemoteProtocolAsyncRendererInvoker`. Before `SetInvokeInMainThread(...)` is called by renderer `GuiMain`, work is cached. After the invoker is installed, it is drained in FIFO order on the renderer UI thread. `Initialize(reader)` requires a non-null reader; `Detach()` explicitly clears it, increments `messageVersion`, and drops queued work. The version check prevents callbacks queued before `Detach()` from running after detachment or a later reader installation.
|
||||||
|
|
||||||
## Demo Project Pair
|
## Demo Project Pair
|
||||||
|
|
||||||
@@ -146,10 +146,10 @@ Located at `Test/GacUISrc/RemotingTest_Rendering_Win32/`. Accepts `/Pipe` or `/H
|
|||||||
2. Creates `GuiRemoteProtocolAsyncJsonChannelRenderer` over the client's protocol channel.
|
2. Creates `GuiRemoteProtocolAsyncJsonChannelRenderer` over the client's protocol channel.
|
||||||
3. Creates `GuiRemoteRendererSingle` and `GuiRemoteProtocolRendererChannel(&asyncRendererChannel, &remoteRenderer)`.
|
3. Creates `GuiRemoteRendererSingle` and `GuiRemoteProtocolRendererChannel(&asyncRendererChannel, &remoteRenderer)`.
|
||||||
4. Waits for the server, then calls `SetupRawWindowsDirect2DRenderer()` to run the native window event loop.
|
4. Waits for the server, then calls `SetupRawWindowsDirect2DRenderer()` to run the native window event loop.
|
||||||
5. In `GuiMain()`, creates the native window, registers it with `GuiRemoteRendererSingle`, installs `GuiMainAsyncRendererInvoker` through `asyncChannel->SetInvokeInMainThread(&invoker)`, and runs the window service.
|
5. In `GuiMain()`, creates the native window, registers it with `GuiRemoteRendererSingle`, creates a retained `Ptr<GuiMainAsyncRendererInvoker>`, installs it through `asyncChannel->SetInvokeInMainThread(invoker)`, drains startup work with `ProcessPendingMessages()`, and runs the window service.
|
||||||
6. On exit, clears the invoker, unregisters the main window, stops the network connection, and clears stack-owned renderer/channel pointers.
|
6. On exit, clears the invoker, unregisters the main window, stops the network connection, and clears stack-owned renderer/channel pointers.
|
||||||
|
|
||||||
`RemotingTestChannelClient` records only the first fatal error and queues a native Yes/No prompt asking whether to close the renderer. A core read error uses the core-error title. A fatal local transport error uses the renderer-transport title and first calls `GuiRemoteRendererSingle::RequestCoreForceExitByFatalError()`. Choosing Yes calls `ForceExitByFatelError()`; choosing No calls `RetainByFatalError(message)`, keeps the native renderer window open with a `[STOPPED]` title and fatal overlay, and exposes the error through the renderer automation service. On disconnect, the client calls `GuiRemoteProtocolAsyncJsonChannelRenderer::Detach()` and forces renderer exit only when no fatal error has already been claimed.
|
`RemotingTestChannelClient` queues both protocol packages and terminal actions through the async renderer's ordered main-thread FIFO. A Core-authored `!Error` arrives through `OnReadError`, claims the first fatal error, and opens the native Yes/No prompt. Choosing Yes calls `ForceExitByFatelError()`; choosing No calls `RetainByFatalError(message)`, keeps the native renderer window open with a `[STOPPED]` title and fatal overlay, and exposes the error through renderer automation. A fatal local channel error has different UI semantics: after VlppOS's `IChannelClient` promotes a post-connection protocol error, `OnLocalError(..., true)` queues the ordinary disconnected transition directly, without showing a fatal prompt and without waiting for `OnDisconnected`. `OnDisconnected` queues the same idempotent transition when it is delivered. FIFO ordering lets an earlier `ControllerConnectionStopped` or Core `!Error` win before detach.
|
||||||
|
|
||||||
### Protocol Stack Direction
|
### Protocol Stack Direction
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ For an accepted connection:
|
|||||||
3. Return `WaitForClientResult::Accept`, or return `Reject` without using the connection.
|
3. Return `WaitForClientResult::Accept`, or return `Reject` without using the connection.
|
||||||
4. Exchange nonempty `WString` messages with `SendString`.
|
4. Exchange nonempty `WString` messages with `SendString`.
|
||||||
|
|
||||||
The most-derived server destructor must call `Stop` before destroying fields that connection callbacks can access. From outside callbacks, `Stop` is the callback-draining shutdown boundary. A callback-reentrant `Stop` prevents further work but does not unwind the current callback, whose visible state must survive until it returns.
|
The most-derived server destructor must call `Stop` before destroying fields that connection callbacks can access and must suppress any shutdown exception. From outside callbacks, `Stop` is the callback-draining shutdown boundary and reports a recorded completion exception at most once. A callback-reentrant `Stop` prevents further work but does not unwind the current callback, whose visible state must survive until it returns.
|
||||||
|
|
||||||
`INetworkProtocolClient` owns one logical connection. The normal client sequence is:
|
`INetworkProtocolClient` owns one logical connection. The normal client sequence is:
|
||||||
|
|
||||||
@@ -113,7 +113,13 @@ public:
|
|||||||
|
|
||||||
~ChannelServer()
|
~ChannelServer()
|
||||||
{
|
{
|
||||||
Stop();
|
try
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitForClientResult OnClientConnected(
|
WaitForClientResult OnClientConnected(
|
||||||
@@ -182,10 +188,14 @@ channels[L"Events"]->BroadcastFromClient(package);
|
|||||||
channels[L"Events"]->BatchWrite(disconnected);
|
channels[L"Events"]->BatchWrite(disconnected);
|
||||||
```
|
```
|
||||||
|
|
||||||
The derived client can also handle `OnConnected`, `OnDisconnected`, `OnReadError` and `OnLocalError`.
|
The derived client can also handle `OnConnected`, `OnDisconnected`, `OnReadError` and `OnLocalError`. A raw protocol callback returns `true` from `INetworkProtocolCallback::OnLocalError` when it needs to promote a recoverable transport error to fatal; the protocol then stops only after the callback returns. `NetworkProtocolChannelClient` uses this hook after its channel reaches `Connected`: it reports every local error to its `IChannelClient` user with `fatal == true`, transitions the channel to disconnected, and asks the raw transport to stop. Before the channel is connected, raw retry policy remains in control.
|
||||||
|
|
||||||
`IChannelServer<TPackage>` routes messages but is not itself a channel participant. When server-side code must send ordinary channel messages, connect a `NetworkProtocolLocalChannelClient<TPackage, TSerialization>` with `ConnectLocalClient`; this gives the local participant a normal positive client id.
|
`IChannelServer<TPackage>` routes messages but is not itself a channel participant. When server-side code must send ordinary channel messages, connect a `NetworkProtocolLocalChannelClient<TPackage, TSerialization>` with `ConnectLocalClient`; this gives the local participant a normal positive client id.
|
||||||
|
|
||||||
|
`BroadcastError` is an idempotent terminal admission boundary: the first error wins, it snapshots existing recipients, and it rejects new admissions. A client whose application admission callback was already in flight cannot commit after that snapshot; if the application accepted it, the server delivers the retained first terminal error before disconnecting it. A committed client becomes eligible for the snapshot only after its network client-id response or local `OnConnected` callback completes, so retained delivery preserves `connected -> fatal -> disconnected` ordering.
|
||||||
|
|
||||||
|
The server keeps its underlying transport alive until raw protocol callbacks, admission callbacks and fatal-delivery work have left a shared stop barrier. Concurrent `Stop` calls wait for the same physical shutdown and cannot overtake retained delivery. If an admission, fatal, or disconnection callback itself calls `BroadcastError` or `Stop`, terminal state is published synchronously and physical stop is deferred until the protected callback unwinds so it cannot wait on itself. When the last barrier is a raw protocol callback, completion runs on a separate thread so the underlying transport's `Stop` can drain that callback. Recipient exceptions are recorded without bypassing best-effort terminal delivery and shutdown; a later non-reentrant `Stop` reports the recorded completion exception once.
|
||||||
|
|
||||||
## How Socket HTTP Implements the Protocol
|
## How Socket HTTP Implements the Protocol
|
||||||
|
|
||||||
`async_tcp_socket::SocketHttpServer`, defined in `Source/InterProcess/AsyncSocket/AsyncSocket_HttpServer.h`, derives from `async_tcp_socket::SocketHttpServerApi` and implements `INetworkProtocolServer`. `async_tcp_socket::SocketHttpClient`, defined in `Source/InterProcess/AsyncSocket/AsyncSocket_HttpClient.h`, implements both `INetworkProtocolClient` and its single logical `INetworkProtocolConnection`.
|
`async_tcp_socket::SocketHttpServer`, defined in `Source/InterProcess/AsyncSocket/AsyncSocket_HttpServer.h`, derives from `async_tcp_socket::SocketHttpServerApi` and implements `INetworkProtocolServer`. `async_tcp_socket::SocketHttpClient`, defined in `Source/InterProcess/AsyncSocket/AsyncSocket_HttpClient.h`, implements both `INetworkProtocolClient` and its single logical `INetworkProtocolConnection`.
|
||||||
@@ -270,6 +280,6 @@ Use `VlppOS.Windows.h` on Windows; Winsock initialization and `Ws2_32.lib` linka
|
|||||||
|
|
||||||
`urlPrefix` is empty for the origin root or an ASCII origin-form prefix such as `/example`. Both adapters remove trailing slashes, so `/` becomes the origin root. A nonempty normalized prefix must start with `/` and must not contain a query, fragment, backslash, NUL, malformed escape, or encoded path separator. Server and client must use the same normalized prefix, and their injected sockets must report the same port.
|
`urlPrefix` is empty for the origin root or an ASCII origin-form prefix such as `/example`. Both adapters remove trailing slashes, so `/` becomes the origin root. A nonempty normalized prefix must start with `/` and must not contain a query, fragment, backslash, NUL, malformed escape, or encoded path separator. Server and client must use the same normalized prefix, and their injected sockets must report the same port.
|
||||||
|
|
||||||
The portable `HttpRequestClient` treats a 404 response as `HttpResponseFailure::NotFound`, reports a fatal error, and stops its socket. `SocketHttpClientApi` exposes this as `SocketHttpClientErrorCode::ResponseNotFound`; the logical `SocketHttpClient` reports one fatal local error immediately instead of retrying `/Connect`, `/Request`, or `/Response`.
|
The portable `HttpRequestClient` treats a 404 response as `HttpResponseFailure::NotFound`, reports a terminal physical-lane error, and stops that socket. `SocketHttpClientApi` exposes this as `SocketHttpClientErrorCode::ResponseNotFound`. The logical `SocketHttpClient` does not inherit that physical fatal classification: it reports the endpoint failure as nonfatal and applies the endpoint's normal retry policy. `/Connect` and `/Response` retry up to their normal attempt limit, replacing a failed physical lane when needed; `/Request` replaces its receive lane and continues polling. If a connected `NetworkProtocolChannelClient` owns the callback, its promotion response stops the logical client after the first reported failure instead.
|
||||||
|
|
||||||
For the lower socket, HTTP request and Mini HTTP API startup rules on each platform, see [Inter-Process Async-Socket-Based Mini HTTP API](./KB_VlppOS_InterProcessAsyncSocketBasedMiniHttpApi.md).
|
For the lower socket, HTTP request and Mini HTTP API startup rules on each platform, see [Inter-Process Async-Socket-Based Mini HTTP API](./KB_VlppOS_InterProcessAsyncSocketBasedMiniHttpApi.md).
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ Use `IAttributeInfo` to inspect an attribute:
|
|||||||
Attributes are serialized into metaonly binary metadata by `GenerateMetaonlyTypes` and deserialized by `LoadMetaonlyTypes`.
|
Attributes are serialized into metaonly binary metadata by `GenerateMetaonlyTypes` and deserialized by `LoadMetaonlyTypes`.
|
||||||
Ordinary attribute values are serialized through `ISerializableType::Serialize` and deserialized through `ISerializableType::Deserialize`.
|
Ordinary attribute values are serialized through `ISerializableType::Serialize` and deserialized through `ISerializableType::Deserialize`.
|
||||||
`ITypeDescriptor*` attribute values are encoded separately as referenced type-descriptor indices with empty serialized data.
|
`ITypeDescriptor*` attribute values are encoded separately as referenced type-descriptor indices with empty serialized data.
|
||||||
|
For general metadata generation, dependency layers, and loading order, see [GenerateMetaonlyTypes](./KB_VlppReflection_GenerateMetaonlyTypes.md).
|
||||||
|
|
||||||
Attributes appear in the logged text output (`.txt` baseline files) in the format:
|
Attributes appear in the logged text output (`.txt` baseline files) in the format:
|
||||||
```
|
```
|
||||||
@Attribute:<AttributeTypeName>(<ArgTypeName>:<SerializedData>, ...)
|
@Attribute:<AttributeTypeName>(<ArgTypeName>:<SerializedData>, ...)
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# GenerateMetaonlyTypes
|
||||||
|
|
||||||
|
## Generate and load binary reflection metadata
|
||||||
|
|
||||||
|
`GenerateMetaonlyTypes` serializes the registered reflection metadata in a loaded global type manager.
|
||||||
|
The output can be a self-contained file or a dependent layer whose previously registered types are referenced without repeating their metadata records.
|
||||||
|
|
||||||
|
The related APIs are:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void CollectRegisteredTypes(collections::List<ITypeDescriptor*>& types);
|
||||||
|
void GenerateMetaonlyTypes(
|
||||||
|
const collections::List<ITypeDescriptor*>& excludedTypes,
|
||||||
|
stream::IStream& outputStream
|
||||||
|
);
|
||||||
|
Ptr<ITypeLoader> LoadMetaonlyTypes(
|
||||||
|
stream::IStream& inputStream,
|
||||||
|
const collections::Dictionary<WString, Ptr<ISerializableType>>& serializableTypes
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Self-contained metadata
|
||||||
|
|
||||||
|
Pass an empty exclusion list to create an independently loadable file:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
collections::List<ITypeDescriptor*> dependencies;
|
||||||
|
stream::FileStream output(fileName, stream::FileStream::WriteOnly);
|
||||||
|
GenerateMetaonlyTypes(dependencies, output);
|
||||||
|
```
|
||||||
|
|
||||||
|
The global type manager must already be loaded before generation.
|
||||||
|
An empty dependency list is serialized at the beginning of the file, and `LoadMetaonlyTypes` does not require pre-existing registered types when reading it.
|
||||||
|
|
||||||
|
## Dependent metadata layers
|
||||||
|
|
||||||
|
Use a snapshot of all currently registered descriptors when a later group of types should be stored in a separate file:
|
||||||
|
|
||||||
|
1. Register and load every type in the base layer.
|
||||||
|
2. Call `CollectRegisteredTypes` to capture the base descriptors. The function replaces the output list instead of appending to it.
|
||||||
|
3. Register the types for the dependent layer. Adding a loader to an already loaded type manager applies it immediately; do not call `ITypeManager::Load` again.
|
||||||
|
4. Pass the captured base descriptors to `GenerateMetaonlyTypes`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto manager = GetGlobalTypeManager();
|
||||||
|
manager->Load();
|
||||||
|
|
||||||
|
collections::List<ITypeDescriptor*> baseTypes;
|
||||||
|
CollectRegisteredTypes(baseTypes);
|
||||||
|
|
||||||
|
manager->AddTypeLoader(CreateDependentTypeLoader());
|
||||||
|
|
||||||
|
stream::FileStream output(layerFileName, stream::FileStream::WriteOnly);
|
||||||
|
GenerateMetaonlyTypes(baseTypes, output);
|
||||||
|
```
|
||||||
|
|
||||||
|
The exclusion snapshot identifies descriptors supplied by previous layers.
|
||||||
|
Those descriptors can still be referenced by local base types, signatures, generic arguments, properties, events, attributes, and other metadata, but their own records are not emitted again.
|
||||||
|
|
||||||
|
## Loading order
|
||||||
|
|
||||||
|
Load and activate every dependency before even calling `LoadMetaonlyTypes` for a dependent file:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto manager = GetGlobalTypeManager();
|
||||||
|
|
||||||
|
auto baseLoader = LoadMetaonlyTypes(baseStream, serializableTypes);
|
||||||
|
manager->AddTypeLoader(baseLoader);
|
||||||
|
manager->Load();
|
||||||
|
|
||||||
|
auto dependentLoader = LoadMetaonlyTypes(dependentStream, serializableTypes);
|
||||||
|
manager->AddTypeLoader(dependentLoader);
|
||||||
|
```
|
||||||
|
|
||||||
|
Dependency validation happens while `LoadMetaonlyTypes` reads the file.
|
||||||
|
If any required registered name is missing, it raises an error that includes that name.
|
||||||
|
When the manager is already loaded, adding the dependent loader registers its local descriptors immediately.
|
||||||
|
|
||||||
|
## Dependency identity and ordering
|
||||||
|
|
||||||
|
- Dependencies are identified by `ITypeDescriptor::GetTypeName()`, which is the registered reflection name. Do not use the C++ full name.
|
||||||
|
- `GenerateMetaonlyTypes` sorts dependency names in ascending order. The result does not depend on caller order or `ITypeManager::GetTypeDescriptor(vint)` enumeration order.
|
||||||
|
- The file begins with exactly one serialized `List<WString>` containing the sorted dependency names.
|
||||||
|
- Foreign descriptor indices occupy the dependency prefix in serialized-name order. Local descriptors follow in deterministic type-name order.
|
||||||
|
- Type-descriptor references use the combined foreign-and-local table. Method, property, and event indices remain local to the current layer.
|
||||||
|
|
||||||
|
## Preconditions and lifetime
|
||||||
|
|
||||||
|
- The global type manager must be loaded before calling `CollectRegisteredTypes` or `GenerateMetaonlyTypes`.
|
||||||
|
- Every excluded descriptor must be non-null, unique, and the exact descriptor currently registered under its name.
|
||||||
|
- Captured descriptors must remain registered and unchanged until generation finishes. Adding the new local types is expected, but do not replace captured descriptors, reset the manager, or mutate it concurrently with collection or generation.
|
||||||
|
- Keep dependency layers loaded while their dependent layers are in use. The dependent loader retains resolved foreign descriptors so its local metadata references remain valid.
|
||||||
|
|
||||||
|
Attribute values participate in the same combined descriptor table.
|
||||||
|
For the attribute-specific representation of serializable values and `ITypeDescriptor*`, see [Attribute Registration](./KB_VlppReflection_AttributeRegistration.md).
|
||||||
@@ -3,20 +3,20 @@
|
|||||||
# Orders
|
# Orders
|
||||||
|
|
||||||
- Process staged tasks one by one with verification [19]
|
- Process staged tasks one by one with verification [19]
|
||||||
- Verify generated artifacts with downstream consumer checks [15]
|
- Verify generated artifacts with downstream consumer checks [17]
|
||||||
- Port fixes from imports to source repositories [13]
|
- Crash early instead of adding error-tolerance fallbacks [14]
|
||||||
- Crash early instead of adding error-tolerance fallbacks [9]
|
- Port fixes from imports to source repositories [14]
|
||||||
- Keep design documentation aligned with code after refactoring [8]
|
- Proactively remove code made redundant by refactoring [12]
|
||||||
- Proactively remove code made redundant by refactoring [8]
|
- Keep design documentation aligned with code after refactoring [10]
|
||||||
- Fix behavior at the owning state instead of patching symptoms [7]
|
- Fix behavior at the owning state instead of patching symptoms [10]
|
||||||
|
- Verify and localize portability on every target OS [7]
|
||||||
|
- Extract abstractions only for real shared behavior [7]
|
||||||
- Make `Stop()` drain asynchronous work before returning [6]
|
- Make `Stop()` drain asynchronous work before returning [6]
|
||||||
- Validate expectations against implementation and existing tests [5]
|
- Validate expectations against implementation and existing tests [5]
|
||||||
- Verify and localize portability on every target OS [5]
|
|
||||||
- Use `WString::IndexOf` with `wchar_t` (not `const wchar_t*`) [4]
|
- Use `WString::IndexOf` with `wchar_t` (not `const wchar_t*`) [4]
|
||||||
- Use `collections::BinarySearchLambda` on contiguous buffers (guard empty) [4]
|
- Use `collections::BinarySearchLambda` on contiguous buffers (guard empty) [4]
|
||||||
|
- Do not assume async callback owners are heap allocated [4]
|
||||||
- Use `vl::Exception` for expected semantic failures and `CHECK_ERROR` for invariants [3]
|
- Use `vl::Exception` for expected semantic failures and `CHECK_ERROR` for invariants [3]
|
||||||
- Extract abstractions only for real shared behavior [3]
|
|
||||||
- Do not assume async callback owners are heap allocated [3]
|
|
||||||
- Capture dependent lambdas explicitly [2]
|
- Capture dependent lambdas explicitly [2]
|
||||||
- Don't assume observable changes are batched [2]
|
- Don't assume observable changes are batched [2]
|
||||||
- Use `ERROR_MESSAGE_PREFIX` for meaningful `CHECK_ERROR` / `CHECK_FAIL` messages [2]
|
- Use `ERROR_MESSAGE_PREFIX` for meaningful `CHECK_ERROR` / `CHECK_FAIL` messages [2]
|
||||||
@@ -25,6 +25,9 @@
|
|||||||
- Prefer well-defined tests over ambiguous edge cases [2]
|
- Prefer well-defined tests over ambiguous edge cases [2]
|
||||||
- Prefer raw pointers unless shared ownership is required [2]
|
- Prefer raw pointers unless shared ownership is required [2]
|
||||||
- Start async callbacks after most-derived construction [2]
|
- Start async callbacks after most-derived construction [2]
|
||||||
|
- Sort serialization metadata by deterministic keys, not pointer addresses [2]
|
||||||
|
- Use RAII scope cleanup instead of manual catch cleanup [2]
|
||||||
|
- Treat environment correlation as evidence, not a cause [2]
|
||||||
- Prefer `operator<=> = default` for lexicographic key structs [1]
|
- Prefer `operator<=> = default` for lexicographic key structs [1]
|
||||||
- Prefer two-pointer merge for sorted range maps [1]
|
- Prefer two-pointer merge for sorted range maps [1]
|
||||||
- Use named sentinel constants instead of raw values [1]
|
- Use named sentinel constants instead of raw values [1]
|
||||||
@@ -32,9 +35,7 @@
|
|||||||
- Avoid references into containers when mutating them [1]
|
- Avoid references into containers when mutating them [1]
|
||||||
- Prefer designated initializers for aggregate-like structs [1]
|
- Prefer designated initializers for aggregate-like structs [1]
|
||||||
- Construct `Nullable<WString>` explicitly in function calls [1]
|
- Construct `Nullable<WString>` explicitly in function calls [1]
|
||||||
- Sort serialization metadata by deterministic keys, not pointer addresses [1]
|
|
||||||
- Do not rely on `Event<T>` handler invocation order [1]
|
- Do not rely on `Event<T>` handler invocation order [1]
|
||||||
- Use RAII scope cleanup instead of manual catch cleanup [1]
|
|
||||||
- `collections::Dictionary` copy assignment is deleted (use move/swap) [1]
|
- `collections::Dictionary` copy assignment is deleted (use move/swap) [1]
|
||||||
- Dereference `Ptr<T>` via `.Obj()` (not `*ptr`) [1]
|
- Dereference `Ptr<T>` via `.Obj()` (not `*ptr`) [1]
|
||||||
- `vl::regex` separator regex: `L"[\\/\\\\]+"` [1]
|
- `vl::regex` separator regex: `L"[\\/\\\\]+"` [1]
|
||||||
@@ -46,7 +47,6 @@
|
|||||||
- Keep generated makefiles platform-invariant [1]
|
- Keep generated makefiles platform-invariant [1]
|
||||||
- Group non-template C++ implementations by class in `.cpp` files [1]
|
- Group non-template C++ implementations by class in `.cpp` files [1]
|
||||||
- Use reentrant POSIX date-time conversions [1]
|
- Use reentrant POSIX date-time conversions [1]
|
||||||
- Treat environment correlation as evidence, not a cause [1]
|
|
||||||
|
|
||||||
# Refinements
|
# Refinements
|
||||||
|
|
||||||
@@ -66,6 +66,8 @@ When an invariant says a value must exist or a conversion must succeed, prefer u
|
|||||||
|
|
||||||
Build-generation scripts must also preserve failures from compiler or dependency probes across command substitutions and formatting pipelines. Stop before emitting tracked output when a required header or package is missing, and declare the dependency in the canonical environment bootstrap so the original diagnostic is reported instead of a malformed generated rule.
|
Build-generation scripts must also preserve failures from compiler or dependency probes across command substitutions and formatting pipelines. Stop before emitting tracked output when a required header or package is missing, and declare the dependency in the canonical environment bootstrap so the original diagnostic is reported instead of a malformed generated rule.
|
||||||
|
|
||||||
|
For HTTP automation endpoints, return protocol errors such as 404 only for recognized request rejection. Unexpected parser, automation, callback, or invariant failures should reach a process-terminating boundary instead of being translated into a healthy-looking endpoint response.
|
||||||
|
|
||||||
## Process staged tasks one by one with verification
|
## Process staged tasks one by one with verification
|
||||||
|
|
||||||
When a request is split into explicit tasks, complete and verify each task before starting the next one. This keeps commits easy to understand and review, limits side effects to the current task, and avoids having to diagnose many unrelated issues at the same time. If a task has its own finishing instructions, finish that task properly before moving on.
|
When a request is split into explicit tasks, complete and verify each task before starting the next one. This keeps commits easy to understand and review, limits side effects to the current task, and avoids having to diagnose many unrelated issues at the same time. If a task has its own finishing instructions, finish that task properly before moving on.
|
||||||
@@ -204,6 +206,8 @@ When multiple handlers attached to the same `Event<T>` can both observe, mutate,
|
|||||||
|
|
||||||
When a helper temporarily suppresses callbacks, changes ownership flags, or otherwise establishes scoped state, use a small scope object whose destructor restores state during normal return and exception unwinding. Avoid manual `try`/`catch` blocks that only restore state and rethrow; C++ stack unwinding should own that cleanup.
|
When a helper temporarily suppresses callbacks, changes ownership flags, or otherwise establishes scoped state, use a small scope object whose destructor restores state during normal return and exception unwinding. Avoid manual `try`/`catch` blocks that only restore state and rethrow; C++ stack unwinding should own that cleanup.
|
||||||
|
|
||||||
|
Do not add a scope wrapper solely to run normal-path finalization after an exception in a fail-fast test app. When the exception is intended to terminate the process and the OS releases the endpoint, keep ordinary shutdown calls straight-line at the end. Retain scoped ownership where destruction order prevents callbacks from reaching expired stack objects.
|
||||||
|
|
||||||
## `collections::Dictionary` copy assignment is deleted (use move/swap)
|
## `collections::Dictionary` copy assignment is deleted (use move/swap)
|
||||||
|
|
||||||
`collections::Dictionary` does not support copy assignment. When you need to replace one dictionary with another, use move semantics (when appropriate), or rebuild/swap explicitly instead of `a = b`.
|
`collections::Dictionary` does not support copy assignment. When you need to replace one dictionary with another, use move semantics (when appropriate), or rebuild/swap explicitly instead of `a = b`.
|
||||||
@@ -232,6 +236,8 @@ When generated build metadata must be platform-invariant, generate it with nativ
|
|||||||
|
|
||||||
When a generator produces runnable sample applications, verify the generated output through the actual app workflow too. For example, generated ChatBot RPC code should be checked by running the server and multiple clients through joins, chat messages, client exit, and server shutdown, not only by confirming generation succeeds.
|
When a generator produces runnable sample applications, verify the generated output through the actual app workflow too. For example, generated ChatBot RPC code should be checked by running the server and multiple clients through joins, chat messages, client exit, and server shutdown, not only by confirming generation succeeds.
|
||||||
|
|
||||||
|
When CodePack ownership is split, inspect the exact generated code pairs and their dependency boundaries. Confirm neutral output excludes platform-only dependencies, ordinary library pairs do not absorb the helper layer, and generated formatting is preserved rather than hand-edited.
|
||||||
|
|
||||||
When a shared dispatcher schema such as `Rpc.d.ts` changes, type-check the shared schema itself as well as generated fixtures so envelope changes are caught even before concrete generated values instantiate every request shape.
|
When a shared dispatcher schema such as `Rpc.d.ts` changes, type-check the shared schema itself as well as generated fixtures so envelope changes are caught even before concrete generated values instantiate every request shape.
|
||||||
|
|
||||||
For a released VlppOS namespace change, validate Workflow through the ChatBot SOP and validate GacUI through `RemotingTest_Core /RPT /Http` with `RemotingTest_Rendering_Win32 /Http`, plus GacJS against the HTTP remoting core. An upstream build alone does not prove the imported public surface works.
|
For a released VlppOS namespace change, validate Workflow through the ChatBot SOP and validate GacUI through `RemotingTest_Core /RPT /Http` with `RemotingTest_Rendering_Win32 /Http`, plus GacJS against the HTTP remoting core. An upstream build alone does not prove the imported public surface works.
|
||||||
@@ -302,6 +308,8 @@ When a layered transport needs a stricter response policy than its general parse
|
|||||||
|
|
||||||
When a bug reproduces on one machine but not another, do not assume hardware speed or timing is causal merely because the machines differ. Reproduce the smallest differing state or response shape deterministically, then identify the missing transition or dependency that the other environment happens to mask.
|
When a bug reproduces on one machine but not another, do not assume hardware speed or timing is causal merely because the machines differ. Reproduce the smallest differing state or response shape deterministically, then identify the missing transition or dependency that the other environment happens to mask.
|
||||||
|
|
||||||
|
The same standard applies when severe CPU usage coincides with a debugger or terminal session: treat the tool/output feedback path as a hypothesis until resource evidence identifies the consuming process or thread. Do not turn an unobserved incident into a durable application-thread-leak diagnosis.
|
||||||
|
|
||||||
## Verify and localize portability on every target OS
|
## Verify and localize portability on every target OS
|
||||||
|
|
||||||
Run the relevant tests on every target operating system whose behavior is being claimed, and report only the platforms actually exercised. Use contrasts between passing and failing platforms to narrow investigation toward the failing platform's implementation before changing shared code, while retaining cross-platform regression verification. Instructions may be prepared for an untested operating system only when they are clearly labeled untested; never report that platform as verified.
|
Run the relevant tests on every target operating system whose behavior is being claimed, and report only the platforms actually exercised. Use contrasts between passing and failing platforms to narrow investigation toward the failing platform's implementation before changing shared code, while retaining cross-platform regression verification. Instructions may be prepared for an untested operating system only when they are clearly labeled untested; never report that platform as verified.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ The copied `.github` folder contains several kinds of files:
|
|||||||
- `copilot-instructions.md`: the main instruction file. It tells the agent to read `Project.md`, use the knowledge base, and prefer provided scripts.
|
- `copilot-instructions.md`: the main instruction file. It tells the agent to read `Project.md`, use the knowledge base, and prefer provided scripts.
|
||||||
- `Guidelines`: build, run, debug, source-file, coding, and GacUI resource instructions.
|
- `Guidelines`: build, run, debug, source-file, coding, and GacUI resource instructions.
|
||||||
- `prompts`: job prompts such as `ask.prompt.md`, `investigate.prompt.md`, `refine.prompt.md`, and `kb.prompt.md`.
|
- `prompts`: job prompts such as `ask.prompt.md`, `investigate.prompt.md`, `refine.prompt.md`, and `kb.prompt.md`.
|
||||||
- `Scripts`: Windows PowerShell wrappers for building, executing, debugging, and archiving task logs.
|
- `Scripts`: Windows PowerShell wrappers for building, executing, and archiving task logs.
|
||||||
- `Ubuntu`: Linux build wrapper and helper commands.
|
- `Ubuntu`: Linux build wrapper and helper commands.
|
||||||
- `KnowledgeBase`: copied API, design, manual, and learning documents that the agent can read without network access.
|
- `KnowledgeBase`: copied API, design, manual, and learning documents that the agent can read without network access.
|
||||||
- `Learning`: project-local lessons that refine future agent behavior.
|
- `Learning`: project-local lessons that refine future agent behavior.
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
# Installing Required Tools on Windows
|
# Installing Required Tools on Windows
|
||||||
|
|
||||||
The Windows agent scripts build with MSBuild through Visual Studio's developer environment and debug with CDB. Install Visual Studio with the C++ desktop workload, a Windows SDK, and the Windows debugging tools that provide `cdb.exe`. If CDB is not available, install the Windows Driver Kit or the Windows debugging tools component from the Visual Studio Installer.
|
The Windows agent scripts build with MSBuild through Visual Studio's developer environment, and the agent debugs directly with CDB. Install Visual Studio with the C++ desktop workload, a Windows SDK, and the Windows debugging tools that provide `cdb.exe`. If CDB is not available, install the Windows Driver Kit or the Windows debugging tools component from the Visual Studio Installer.
|
||||||
|
|
||||||
Define these environment variables before asking the agent to build or debug:
|
Define these environment variables before asking the agent to build or debug:
|
||||||
- `VLPP_VSDEVCMD_PATH`: absolute path to `VsDevCmd.bat`, for example `C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat`.
|
- `VLPP_VSDEVCMD_PATH`: absolute path to `VsDevCmd.bat`, for example `C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat`.
|
||||||
- `CDBPATH`: absolute path to `cdb.exe`, for example `C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe`.
|
- `CDBPATH`: absolute path to `cdb.exe`, for example `C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe`.
|
||||||
|
|
||||||
After copying the Release `.github` folder, the agent should use these scripts instead of calling tools directly:
|
After copying the Release `.github` folder, the agent should use these scripts instead of calling build or execution tools directly:
|
||||||
- `.github\Scripts\copilotBuild.ps1`: builds the solution found from `Project.md` context and writes `Build.log`.
|
- `.github\Scripts\copilotBuild.ps1`: builds the solution found from `Project.md` context and writes `Build.log`.
|
||||||
- `.github\Scripts\copilotExecute.ps1`: runs unit-test or CLI projects and writes `Execute.log` for unit tests.
|
- `.github\Scripts\copilotExecute.ps1`: runs unit-test or CLI projects and writes `Execute.log` for unit tests.
|
||||||
- `.github\Scripts\copilotDebug_Start.ps1` and `copilotDebug_RunCommand.ps1`: start CDB and send debugger commands.
|
|
||||||
|
Run CDB directly in an interactive terminal when debugging.
|
||||||
|
|
||||||
If the application uses the tools shipped by Release, build them from the Release repository:
|
If the application uses the tools shipped by Release, build them from the Release repository:
|
||||||
- Open `Tools\Executables\Executables.sln` in Visual Studio.
|
- Open `Tools\Executables\Executables.sln` in Visual Studio.
|
||||||
@@ -17,5 +18,5 @@ If the application uses the tools shipped by Release, build them from the Releas
|
|||||||
- Run `Tools\CopyExecutables.ps1`.
|
- Run `Tools\CopyExecutables.ps1`.
|
||||||
- Confirm `CodePack.exe`, `CppMerge.exe`, `GacGen.exe`, and `GlrParserGen.exe` exist in `Release\Tools`.
|
- Confirm `CodePack.exe`, `CppMerge.exe`, `GacGen.exe`, and `GlrParserGen.exe` exist in `Release\Tools`.
|
||||||
|
|
||||||
For debugger readability, copy `Import\vlpp.natvis` from Release to Visual Studio's visualizers folder. The CDB startup script also loads the natvis file for debugger commands such as `dx`.
|
For debugger readability, copy `Import\vlpp.natvis` from Release to Visual Studio's visualizers folder. Load the natvis file in CDB for debugger commands such as `dx`.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Investigate and Refine Jobs
|
# Investigate and Refine Jobs
|
||||||
|
|
||||||
`AGENTS.md` and `CLAUDE.md` route short request keywords to prompt files in `.github/prompts`. These jobs make agent work repeatable because the agent writes durable task documents, uses the copied knowledge base, and follows the repository's build and debug scripts.
|
`AGENTS.md` and `CLAUDE.md` route short request keywords to prompt files in `.github/prompts`. These jobs make agent work repeatable because the agent writes durable task documents, uses the copied knowledge base, and follows the repository's build, run, and debugging instructions.
|
||||||
|
|
||||||
## investigate
|
## investigate
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ The service is independent from the remote protocol. A normal Windows applicatio
|
|||||||
|
|
||||||
`INativeAutomationService` has one service-level availability flag and three feature groups:
|
`INativeAutomationService` has one service-level availability flag and three feature groups:
|
||||||
- `Available`: returns false when no automation service exists for the current controller.
|
- `Available`: returns false when no automation service exists for the current controller.
|
||||||
- `Stop`: turns off all features. Windows implementations also stop the HTTP listener.
|
- `Stop`: turns off all features. Endpoint lifetime is owned separately.
|
||||||
- `CanDumpControlTree` and `DumpControlTree`: expose visible GacUI windows, popups, controls and compositions.
|
- `CanDumpControlTree` and `DumpControlTree`: expose visible GacUI windows, popups, controls and compositions.
|
||||||
- `CanDumpDomTree` and `DumpDomTree`: expose the remote protocol renderer DOM.
|
- `CanDumpDomTree` and `DumpDomTree`: expose the remote protocol renderer DOM.
|
||||||
- `CanRunIOCommands` and `RunIOCommand`: send a textual IO command to the main window or to a selected native window.
|
- `CanRunIOCommands` and `RunIOCommand`: send a textual IO command to the main window or to a selected native window.
|
||||||
@@ -22,7 +22,7 @@ Feature availability is checked separately. A real service returns true from `Av
|
|||||||
|
|
||||||
## Windows HTTP Layer
|
## Windows HTTP Layer
|
||||||
|
|
||||||
`StartWindowsHttpAutomationService` creates a localhost HTTP wrapper around the current `INativeAutomationService`. It is declared in `PlatformProviders/Windows/WinNativeWindow.h` and implemented by the Windows platform provider. If `GetCurrentController()->AutomationService()->Available()` is false, the function returns without starting a listener.
|
`StartWindowsHttpAutomationService` creates a localhost HTTP wrapper around the current `INativeAutomationService`. The test-support implementation lives in `Source/RemotingHelpers/AutomationService/Windows`, outside the ordinary `GacUI.Windows` library pair. Test applications consume it through the shared `Source_RemotingHelpers` project.
|
||||||
|
|
||||||
The function takes `applicationName` as a URL path fragment and `port` as the localhost port. Given `applicationName == L"Automation/MyApp"` and `port == 8888`, the listener prefix is `http://localhost:8888/Automation/MyApp/`. The service offers exactly these HTTP URLs:
|
The function takes `applicationName` as a URL path fragment and `port` as the localhost port. Given `applicationName == L"Automation/MyApp"` and `port == 8888`, the listener prefix is `http://localhost:8888/Automation/MyApp/`. The service offers exactly these HTTP URLs:
|
||||||
- `GET http://localhost:8888/Automation/MyApp/Controls`: calls `DumpControlTree` on the UI thread when `CanDumpControlTree` is true.
|
- `GET http://localhost:8888/Automation/MyApp/Controls`: calls `DumpControlTree` on the UI thread when `CanDumpControlTree` is true.
|
||||||
@@ -34,40 +34,31 @@ The window id is a path segment after `IO`, not a query parameter. All other met
|
|||||||
|
|
||||||
## Starting The Service
|
## Starting The Service
|
||||||
|
|
||||||
Call `StartWindowsHttpAutomationService` from `GuiMain`, after the setup function has installed the current native controller and before entering the application event loop. Every code path that calls `StartWindowsHttpAutomationService` must later call `StopWindowsHttpAutomationService` before the native controller or substituted automation service is torn down. Skipping the stop leaks the process-wide HTTP service. Use a local guard or equivalent try/catch so the stop runs after the start on normal returns and exceptions.
|
Each application owns the automation service and endpoint directly. After the setup function has installed the current native controller, construct the concrete service matching that controller, substitute it, start an endpoint, and enter the application event loop. On exit, reverse the dependency order: stop the endpoint, stop the service, and finally unsubstitute it.
|
||||||
|
|
||||||
A normal Windows application can start the service before `GetApplication()->Run`:
|
A normal Windows application can start the service before `GetApplication()->Run`:
|
||||||
```c++
|
```c++
|
||||||
#include "../../../Source/PlatformProviders/Windows/WinNativeWindow.h"
|
#include "../../../Source/RemotingHelpers/AutomationService/Windows/WindowsAutomationService.Windows.h"
|
||||||
|
|
||||||
using namespace vl;
|
using namespace vl;
|
||||||
using namespace vl::presentation;
|
using namespace vl::presentation;
|
||||||
using namespace vl::presentation::controls;
|
using namespace vl::presentation::controls;
|
||||||
|
|
||||||
class WindowsHttpAutomationServiceScope
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WindowsHttpAutomationServiceScope(const WString& applicationName, vint port)
|
|
||||||
{
|
|
||||||
windows::StartWindowsHttpAutomationService(applicationName, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
~WindowsHttpAutomationServiceScope()
|
|
||||||
{
|
|
||||||
windows::StopWindowsHttpAutomationService();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void GuiMain()
|
void GuiMain()
|
||||||
{
|
{
|
||||||
demo::MainWindow window;
|
demo::MainWindow window;
|
||||||
window.ForceCalculateSizeImmediately();
|
window.ForceCalculateSizeImmediately();
|
||||||
window.MoveToScreenCenter();
|
window.MoveToScreenCenter();
|
||||||
|
|
||||||
WindowsHttpAutomationServiceScope httpAutomationService(
|
windows::WindowsAutomationServiceHosted automationService;
|
||||||
|
GetNativeServiceSubstitution()->Substitute(&automationService, false);
|
||||||
|
windows::StartWindowsHttpAutomationService(
|
||||||
WString::Unmanaged(L"Automation/MyApp"),
|
WString::Unmanaged(L"Automation/MyApp"),
|
||||||
8888);
|
8888);
|
||||||
GetApplication()->Run(&window);
|
GetApplication()->Run(&window);
|
||||||
|
windows::StopWindowsHttpAutomationService();
|
||||||
|
automationService.Stop();
|
||||||
|
GetNativeServiceSubstitution()->Unsubstitute(&automationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||||
@@ -76,46 +67,42 @@ int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Repeated calls do not create multiple listeners. The Windows implementation keeps one process-wide HTTP service until `StopWindowsHttpAutomationService` stops it.
|
Only one substituted automation service and one endpoint may be active in a process. Duplicate starts fail immediately. `StartMiniHttpAutomationService(socketServer, applicationName)` follows the same lifecycle and URL contract, but requires the application to pass the exact `IAsyncSocketServer` that should host its automation prefix.
|
||||||
|
|
||||||
## Setup Function Cases
|
## Setup Function Cases
|
||||||
|
|
||||||
The setup function decides which controller and service are active while `GuiMain` runs. Use the following cases when deciding whether user code must substitute another automation service:
|
The setup function decides which controller is active while `GuiMain` runs; it no longer installs test automation implicitly. Select the matching helper service explicitly:
|
||||||
- `SetupWindowsGDIRenderer`: installs `WindowsAutomationService`. Use `StartWindowsHttpAutomationService` directly for multi-window control tree and IO. The DOM route is normally unavailable.
|
- `SetupWindowsGDIRenderer` and `SetupWindowsDirect2DRenderer`: construct `WindowsAutomationService` for multi-window control tree and IO. The DOM route is normally unavailable.
|
||||||
- `SetupWindowsDirect2DRenderer`: same automation behavior as `SetupWindowsGDIRenderer`, with the Direct2D renderer.
|
- `SetupHostedWindowsGDIRenderer` and `SetupHostedWindowsDirect2DRenderer`: construct `WindowsAutomationServiceHosted`. IO should use `/IO` without a window id because hosted sub windows and popups are represented under the main window.
|
||||||
- `SetupHostedWindowsGDIRenderer`: installs `WindowsAutomationServiceHosted`. Use the HTTP service directly. IO should use `/IO` without a window id because hosted sub windows and popups are represented under the main window.
|
- `SetupRawWindowsGDIRenderer` and `SetupRawWindowsDirect2DRenderer`: construct `WindowsAutomationService` for an ordinary raw native controller. A remote protocol renderer that owns a `GuiRemoteRendererSingle` constructs `WindowsAutomationServiceRenderer` with the renderer pointer to expose renderer DOM and renderer-side IO.
|
||||||
- `SetupHostedWindowsDirect2DRenderer`: same automation behavior as `SetupHostedWindowsGDIRenderer`, with the Direct2D renderer.
|
|
||||||
- `SetupRawWindowsGDIRenderer`: installs `WindowsAutomationService` for the raw native window controller. If the raw process is a remote protocol renderer and owns a `GuiRemoteRendererSingle`, substitute `WindowsAutomationServiceRenderer` to expose renderer DOM and renderer-side IO.
|
|
||||||
- `SetupRawWindowsDirect2DRenderer`: same automation behavior as `SetupRawWindowsGDIRenderer`, with the Direct2D renderer.
|
|
||||||
- `SetupRemoteNativeController`: the remote controller itself does not return an automation service. Substitute `RemoteProtocolAutomationService` around `GetApplication()->Run` when the remote core should expose the hosted control tree and core-side IO.
|
- `SetupRemoteNativeController`: the remote controller itself does not return an automation service. Substitute `RemoteProtocolAutomationService` around `GetApplication()->Run` when the remote core should expose the hosted control tree and core-side IO.
|
||||||
- `SetupGacGenNativeController`: this setup is for generation-time resource processing, not an interactive UI session. It does not provide an automation service for HTTP control.
|
- `SetupGacGenNativeController`: this setup is for generation-time resource processing, not an interactive UI session. It does not provide an automation service for HTTP control.
|
||||||
- `SetupGtkRenderer`: do not call the Windows HTTP helper. A Gtk port must provide its own endpoint layer and automation service implementation if it needs coding-agent automation.
|
- `SetupGtkRenderer`: do not call the Windows HTTP helper. A Gtk port must provide its own endpoint layer and automation service implementation if it needs coding-agent automation.
|
||||||
- `SetupWGacRenderer`: do not call the Windows HTTP helper. A Wayland port must provide its own endpoint layer and automation service implementation if it needs coding-agent automation.
|
- `SetupWGacRenderer`: construct the Wayland platform service such as `WGacAutomationServiceRenderer` and expose it through MiniHTTP.
|
||||||
- `SetupWGacHostedRenderer`: same requirement as `SetupWGacRenderer`, but the service should follow hosted-mode window-id behavior if it exposes hosted windows.
|
- `SetupWGacHostedRenderer`: use the corresponding hosted Wayland service and hosted-mode window-id behavior.
|
||||||
|
- A macOS remote renderer constructs `CocoaAutomationServiceRenderer` and exposes it through MiniHTTP.
|
||||||
|
|
||||||
## Substituting a Service
|
## Substituting a Service
|
||||||
|
|
||||||
Use `GetNativeServiceSubstitution()->Substitute(service, false)` before the automation service is first requested. The substitution layer rejects a late substitution after a service has already been used. Keep the substituted object alive until it is unsubstituted.
|
Use `GetNativeServiceSubstitution()->Substitute(service, false)` before the automation service is first requested. The substitution layer rejects a late substitution after a service has already been used. Keep the concrete service alive until the endpoint has stopped, `service.Stop()` has completed, and the service is unsubstituted.
|
||||||
|
|
||||||
A remote protocol core can expose the core-side automation surface like this. The sample uses the same `WindowsHttpAutomationServiceScope` guard from the normal Windows application example.
|
A remote protocol core owns its neutral service and endpoint directly:
|
||||||
```c++
|
```c++
|
||||||
void GuiMain()
|
void GuiMain()
|
||||||
{
|
{
|
||||||
RemoteProtocolAutomationService automationService;
|
RemoteProtocolAutomationService automationService;
|
||||||
GetNativeServiceSubstitution()->Substitute(&automationService, false);
|
GetNativeServiceSubstitution()->Substitute(&automationService, false);
|
||||||
|
windows::StartWindowsHttpAutomationService(
|
||||||
{
|
WString::Unmanaged(L"Automation/RemoteCore"),
|
||||||
WindowsHttpAutomationServiceScope httpAutomationService(
|
8888);
|
||||||
WString::Unmanaged(L"Automation/RemoteCore"),
|
GetApplication()->Run(mainWindow);
|
||||||
8888);
|
windows::StopWindowsHttpAutomationService();
|
||||||
GetApplication()->Run(mainWindow);
|
automationService.Stop();
|
||||||
}
|
|
||||||
|
|
||||||
GetNativeServiceSubstitution()->Unsubstitute(&automationService);
|
GetNativeServiceSubstitution()->Unsubstitute(&automationService);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
A remote protocol renderer that owns a `GuiRemoteRendererSingle` can substitute `WindowsAutomationServiceRenderer` in the same scope before starting the HTTP service. This is the case where `GET /Dom` becomes meaningful.
|
A Windows remote protocol renderer constructs `WindowsAutomationServiceRenderer` with its `GuiRemoteRendererSingle`, substitutes it, and owns either the Windows HTTP or MiniHTTP endpoint directly. Linux uses `WGacAutomationServiceRenderer`; macOS uses `CocoaAutomationServiceRenderer`; both use MiniHTTP. These renderer cases are where `GET /Dom` becomes meaningful.
|
||||||
|
|
||||||
When a remote renderer is retained after a fatal remote-protocol error, renderer automation keeps `GET /Dom` available. The DOM response is still an HTTP success containing the frozen renderer DOM, and it adds a lowercase top-level `fatalError` string with the original error. Renderer IO switches to `ExitOnly`: ordinary IO returns exactly `!Application stopped responding.`, while exact `!Exit` is still accepted so automation can close the retained renderer.
|
When a remote renderer is retained after a fatal remote-protocol error, renderer automation keeps `GET /Dom` available. The DOM response is still an HTTP success containing the frozen renderer DOM, and it adds a lowercase top-level `fatalError` string with the original error. Renderer IO switches to `ExitOnly`: ordinary IO returns exactly `!Application stopped responding.`, while exact `!Exit` is still accepted so automation can close the retained renderer.
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using namespace vl::presentation::remote_renderer;
|
|||||||
GuiRemoteRendererSingle* remoteRenderer = nullptr;
|
GuiRemoteRendererSingle* remoteRenderer = nullptr;
|
||||||
GuiRemoteProtocolAsyncJsonChannelRenderer* asyncChannel = nullptr;
|
GuiRemoteProtocolAsyncJsonChannelRenderer* asyncChannel = nullptr;
|
||||||
|
|
||||||
class GuiMainInvoker : public IGuiRemoteProtocolAsyncRendererInvoker
|
class GuiMainInvoker : public Object, public virtual IGuiRemoteProtocolAsyncRendererInvoker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void InvokeInMainThread(const Func<void()>& proc) override
|
void InvokeInMainThread(const Func<void()>& proc) override
|
||||||
@@ -29,9 +29,10 @@ void GuiMain()
|
|||||||
auto mainWindow = GetCurrentController()->WindowService()->CreateNativeWindow(INativeWindow::Normal);
|
auto mainWindow = GetCurrentController()->WindowService()->CreateNativeWindow(INativeWindow::Normal);
|
||||||
mainWindow->SetTitle(L"Connecting ...");
|
mainWindow->SetTitle(L"Connecting ...");
|
||||||
|
|
||||||
GuiMainInvoker invoker;
|
auto invoker = Ptr(new GuiMainInvoker);
|
||||||
remoteRenderer->RegisterMainWindow(mainWindow);
|
remoteRenderer->RegisterMainWindow(mainWindow);
|
||||||
asyncChannel->SetInvokeInMainThread(&invoker);
|
asyncChannel->SetInvokeInMainThread(invoker);
|
||||||
|
asyncChannel->ProcessPendingMessages();
|
||||||
|
|
||||||
GetCurrentController()->WindowService()->Run(mainWindow);
|
GetCurrentController()->WindowService()->Run(mainWindow);
|
||||||
|
|
||||||
@@ -66,5 +67,4 @@ GuiRemoteProtocolAsyncJsonChannelRenderer queues messages from the channel and r
|
|||||||
|
|
||||||
The portable **/MiniHttp** path creates a default loopback TCP client with **vl::inter_process::async_tcp_socket::CreateDefaultAsyncSocketClient(port)**, wraps it in **vl::inter_process::async_tcp_socket::SocketHttpClient(socketClient, L"localhost", urlPrefix)**, and passes that object to **GuiRemoteProtocolChannelClient**. The renderer application shown by the linked test remains Win32 even though the VlppOS transport itself is available on Windows, Linux and macOS.
|
The portable **/MiniHttp** path creates a default loopback TCP client with **vl::inter_process::async_tcp_socket::CreateDefaultAsyncSocketClient(port)**, wraps it in **vl::inter_process::async_tcp_socket::SocketHttpClient(socketClient, L"localhost", urlPrefix)**, and passes that object to **GuiRemoteProtocolChannelClient**. The renderer application shown by the linked test remains Win32 even though the VlppOS transport itself is available on Windows, Linux and macOS.
|
||||||
|
|
||||||
Override GuiRemoteProtocolChannelClient::OnReadError, OnLocalError, or OnDisconnected when the renderer should show a fatal error dialog or call GuiRemoteRendererSingle::ForceExitByFatelError. See [RemotingTest_Rendering_Win32](https://github.com/vczh-libraries/GacUI/tree/master/Test/GacUISrc/RemotingTest_Rendering_Win32) for the complete named-pipe (**/Pipe**), Windows HTTP.sys/WinHTTP (**/Http**) and portable Mini HTTP (**/MiniHttp**) implementations.
|
Override `GuiRemoteProtocolChannelClient::OnReadError` when a Core-authored `!Error` should show fatal UI. Treat `OnLocalError(..., true)` as an independently complete, prompt-free disconnected transition and do not wait for `OnDisconnected`; use `OnDisconnected` as the idempotent fallback when it is delivered. See [RemotingTest_Rendering_Win32](https://github.com/vczh-libraries/GacUI/tree/master/Test/GacUISrc/RemotingTest_Rendering_Win32) for the complete named-pipe (**/Pipe**), Windows HTTP.sys/WinHTTP (**/Http**) and portable Mini HTTP (**/MiniHttp**) implementations.
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,8 @@ The bridge uses **NetworkPackage** as the raw text envelope. Its string shape is
|
|||||||
|
|
||||||
A network channel client connects by sending one handshake package with an empty client id, an empty channel name and all supported channel names joined by **!**. The server validates the names, assigns a positive client id, records channel membership and sends the id back in an empty-channel response. After that, normal channel packages are delivered only when sender and receiver membership matches the channel name.
|
A network channel client connects by sending one handshake package with an empty client id, an empty channel name and all supported channel names joined by **!**. The server validates the names, assigns a positive client id, records channel membership and sends the id back in an empty-channel response. After that, normal channel packages are delivered only when sender and receiver membership matches the channel name.
|
||||||
|
|
||||||
|
**BroadcastError** is a terminal admission boundary. The first broadcast error is retained, later broadcasts are ignored, and new network or local admissions are rejected. If an application **OnClientConnected** callback was already running, the server keeps the underlying transport alive until an accepted client receives that retained error and disconnects. A committed client is not included in the broadcast snapshot until its client-id response or local **OnConnected** callback completes, preserving connected-before-fatal ordering. Concurrent **Stop** calls share this barrier and cannot stop the transport early. Callback-reentrant terminal calls never wait on themselves; when broadcast owns the terminal boundary, physical stop is deferred until protected raw protocol, admission, fatal-delivery and disconnection callbacks unwind. If the last barrier is a raw protocol callback, completion moves to another thread so the underlying transport can drain that callback. A non-reentrant **Stop** reports a recorded shutdown exception once; a most-derived server destructor must call **Stop** before destroying callback-visible fields and catch any exception.
|
||||||
|
|
||||||
A channel server over a Windows named pipe can be declared like this:
|
A channel server over a Windows named pipe can be declared like this:
|
||||||
```C++
|
```C++
|
||||||
#include <vlppos.h>
|
#include <vlppos.h>
|
||||||
@@ -265,7 +267,7 @@ The raw HTTP protocol uses these routes under the configured base URL:
|
|||||||
- **POST /VlppInterProcess/Request/GUID** is the client-maintained long-poll request for server-to-client messages.
|
- **POST /VlppInterProcess/Request/GUID** is the client-maintained long-poll request for server-to-client messages.
|
||||||
- **POST /VlppInterProcess/Response/GUID** sends client-to-server messages and may also receive one queued server-to-client message.
|
- **POST /VlppInterProcess/Response/GUID** sends client-to-server messages and may also receive one queued server-to-client message.
|
||||||
|
|
||||||
**vl::inter_process::windows_http::HttpClient::WaitForServer** sends the connect request, validates the returned URLs, records them and reports connection. **BeginReadingLoopUnsafe** starts the long-poll request loop. **SendString** posts to the response URL. Connect and response failures retry a limited number of times; request failures retry while the client is still running.
|
**vl::inter_process::windows_http::HttpClient::WaitForServer** sends the connect request, validates the returned URLs, records them and reports connection. **BeginReadingLoopUnsafe** starts the long-poll request loop. **SendString** posts to the response URL. Each recoverable failed Connect, Request or Response exchange calls **INetworkProtocolCallback::OnLocalError** with **fatal == false** before retrying; Connect and Response retry a limited number of times, while Request retries while the client is still running. Bounded retry exhaustion remains raw-fatal. Returning **true** from **OnLocalError** promotes a recoverable failure and makes the raw client stop after the callback returns. **NetworkProtocolChannelClient** does this for every local error after its channel reaches **Connected**, forwards **fatal == true** to its **IChannelClient** user and disconnects the channel; pre-handshake Connect retries remain under raw-client policy.
|
||||||
|
|
||||||
**vl::inter_process::windows_http::HttpServer** creates a **vl::inter_process::windows_http::HttpServerConnection** for each connect request. Server-to-client messages are returned through a pending long-poll request when possible, or queued until the next request. Client-to-server request bodies are dispatched as inbound strings. When the server stops, pending long-poll requests are cancelled and connection callbacks receive disconnection.
|
**vl::inter_process::windows_http::HttpServer** creates a **vl::inter_process::windows_http::HttpServerConnection** for each connect request. Server-to-client messages are returned through a pending long-poll request when possible, or queued until the next request. Client-to-server request bodies are dispatched as inbound strings. When the server stops, pending long-poll requests are cancelled and connection callbacks receive disconnection.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
.lines
|
|
||||||
l+s
|
|
||||||
l+t
|
|
||||||
.nvload "C:\Program Files\Microsoft Visual Studio\18\Community\Common7\Packages\Debugger\Visualizers\vlpp.natvis"
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
param(
|
|
||||||
[string]$Command = $null
|
|
||||||
)
|
|
||||||
|
|
||||||
if ([string]::IsNullOrEmpty($Command)) {
|
|
||||||
throw "\$Command parameter is required."
|
|
||||||
}
|
|
||||||
|
|
||||||
. $PSScriptRoot\copilotShared.ps1
|
|
||||||
$cdbpath = GetCDBPath
|
|
||||||
$debuggerNamedPipe = GetDebuggerNamedPipe
|
|
||||||
$commandLine = "echo .remote_exit | `"$($cdbpath)`" -remote npipe:server=.,pipe=$debuggerNamedPipe -clines 0 -c `"$Command`""
|
|
||||||
echo $commandLine
|
|
||||||
cmd.exe /S /C $commandLine
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
param(
|
|
||||||
[string]$Executable = $null
|
|
||||||
)
|
|
||||||
|
|
||||||
if ([string]::IsNullOrEmpty($Executable)) {
|
|
||||||
throw "\$Executable parameter is required."
|
|
||||||
}
|
|
||||||
|
|
||||||
. $PSScriptRoot\copilotShared.ps1
|
|
||||||
|
|
||||||
# Ensure the executable name does not have the .exe extension
|
|
||||||
if ($Executable.EndsWith(".exe")) {
|
|
||||||
throw "\$Executable parameter should not include the .exe extension: $Executable"
|
|
||||||
}
|
|
||||||
$executableName = $Executable + ".exe"
|
|
||||||
|
|
||||||
# Find the solution folder by looking for *.sln files
|
|
||||||
$solutionFolder = GetSolutionDir
|
|
||||||
|
|
||||||
# Find the file with the latest modification time
|
|
||||||
$latestFile = GetLatestModifiedExecutable $solutionFolder $executableName
|
|
||||||
Write-Host "Selected $executableName`: $($latestFile.Path) (Modified: $($latestFile.LastWriteTime))"
|
|
||||||
|
|
||||||
# Try to read debug arguments from the corresponding .vcxproj.user file
|
|
||||||
$debugArgs = GetDebugArgs $solutionFolder $latestFile $Executable
|
|
||||||
|
|
||||||
$cdbpath = GetCDBPath
|
|
||||||
$debuggerNamedPipe = GetDebuggerNamedPipe
|
|
||||||
$commandLine = "`"$($cdbpath)`" -server npipe:pipe=$debuggerNamedPipe -cf `"$PSScriptRoot\copilotDebug_Init.txt`" -o `"$($latestFile.Path)`" $debugArgs"
|
|
||||||
echo $commandLine
|
|
||||||
cmd.exe /S /C $commandLine
|
|
||||||
@@ -1,18 +1,3 @@
|
|||||||
function GetCDBPath {
|
|
||||||
if ($env:CDBPATH -eq $null) {
|
|
||||||
$MESSAGE_1 = "You have to add an environment variable named CDBPATH and set its value to the path of cdb.exe, e.g.:"
|
|
||||||
$MESSAGE_2 = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe"
|
|
||||||
$MESSAGE_3 = "To get cdb.exe, you need to install WDK via VS Installer (Individual Components page) followed by Windows WDK."
|
|
||||||
throw "$MESSAGE_1\r\n$MESSAGE_2\r\n$MESSAGE_3"
|
|
||||||
}
|
|
||||||
return $env:CDBPATH
|
|
||||||
}
|
|
||||||
|
|
||||||
function GetDebuggerNamedPipe {
|
|
||||||
$debuggerRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).Path
|
|
||||||
return ($debuggerRoot -replace "[^A-Za-z0-9]", "").ToUpperInvariant()
|
|
||||||
}
|
|
||||||
|
|
||||||
function GetSolutionDir {
|
function GetSolutionDir {
|
||||||
$currentDir = Get-Location
|
$currentDir = Get-Location
|
||||||
$solutionFolder = $null
|
$solutionFolder = $null
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
- None of the test apps is going to be published, unnecessary error recovery will just cover mistakes up, preventing us from finding the root cause of the problem, making it harder to fix issues in libraries.
|
- None of the test apps is going to be published, unnecessary error recovery will just cover mistakes up, preventing us from finding the root cause of the problem, making it harder to fix issues in libraries.
|
||||||
- Defensive cleanup should always be avoided when affected errors and exceptions crash the app. Since the app is going to be killed, cleaning up just make the code more complex and gain no benefit.
|
- Defensive cleanup should always be avoided when affected errors and exceptions crash the app. Since the app is going to be killed, cleaning up just make the code more complex and gain no benefit.
|
||||||
- Any `REPO-ROOT/Tools/<TOOL-NAME>` only allow very limited error recovery just to print error messages and exit.
|
- Any `REPO-ROOT/Tools/<TOOL-NAME>` only allow very limited error recovery just to print error messages and exit.
|
||||||
|
- No heart beats or similar construction is needed, as all test apps are supposed to be running in the same computer, where the network quality is not an issue.
|
||||||
|
|
||||||
### For Multi-Process Communication
|
### For Multi-Process Communication
|
||||||
|
|
||||||
@@ -28,8 +29,9 @@
|
|||||||
|
|
||||||
## (Windows Specific) External Tools Environment and Context
|
## (Windows Specific) External Tools Environment and Context
|
||||||
|
|
||||||
- Always prefer the offered script files instead of direct CLI commands.
|
- Always prefer the offered script files for building and running projects.
|
||||||
- DO NOT call `msbuild` or other executable files directly.
|
- DO NOT call `msbuild` directly.
|
||||||
|
- Run CDB directly following `REPO-ROOT/.github/Guidelines/Debugging.md`.
|
||||||
- DO NOT create or delete any file unless explicitly directed.
|
- DO NOT create or delete any file unless explicitly directed.
|
||||||
- MUST run any PowerShell script in this format: `& absolute-path.ps1 parameters...`.
|
- MUST run any PowerShell script in this format: `& absolute-path.ps1 parameters...`.
|
||||||
- Multiple PowerShell commands are concatenated with `;` to be executed in one line.
|
- Multiple PowerShell commands are concatenated with `;` to be executed in one line.
|
||||||
@@ -104,8 +106,6 @@ If you need to find any document for the current working task, they are in the `
|
|||||||
If you need to find any script or support files, they are in the `REPO-ROOT/.github/Scripts` folder:
|
If you need to find any script or support files, they are in the `REPO-ROOT/.github/Scripts` folder:
|
||||||
- `copilotBuild.ps1`
|
- `copilotBuild.ps1`
|
||||||
- `copilotExecute.ps1`
|
- `copilotExecute.ps1`
|
||||||
- `copilotDebug_Start.ps1`
|
|
||||||
- `copilotDebug_RunCommand.ps1`
|
|
||||||
- `copilotRemember.ps1`
|
- `copilotRemember.ps1`
|
||||||
- `Build.log`
|
- `Build.log`
|
||||||
- `Execute.log`
|
- `Execute.log`
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Investigate
|
# Investigate
|
||||||
|
|
||||||
- Check out `Accessing Task Documents`, `(Windows Specific) Accessing Script Files`, and `(Linux Specific) Accessing Script Files` in `REPO-ROOT/.github/copilot-instructions.md` for context about mentioned `*.md`, `*.ps1` and `*.sh` files.
|
- Check out `Accessing Task Documents`, `(Windows Specific) Accessing Script Files`, and `(Linux Specific) Accessing Script Files` in `REPO-ROOT/.github/copilot-instructions.md` for context about mentioned `*.md`, `*.ps1` and `*.sh` files.
|
||||||
- Check out `(Windows Specific) External Tools Environment and Context` and `(Linux Specific) External Tools Environment and Context` in `REPO-ROOT/.github/copilot-instructions.md` for accessing scripts for testing and debugging.
|
- Check out `(Windows Specific) External Tools Environment and Context` and `(Linux Specific) External Tools Environment and Context` in `REPO-ROOT/.github/copilot-instructions.md` for accessing testing scripts and debugging tools.
|
||||||
- Check out `REPO-ROOT/Project.md` to find out what solutions you need to build.
|
- Check out `REPO-ROOT/Project.md` to find out what solutions you need to build.
|
||||||
- All `*.md`, `*.ps1` and `*.sh` files should exist; you should not create any new files unless explicitly instructed.
|
- All `*.md`, `*.ps1` and `*.sh` files should exist; you should not create any new files unless explicitly instructed.
|
||||||
- The `Copilot_Investigate.md` file should already exist, it may or may not contain content from the last investigation.
|
- The `Copilot_Investigate.md` file should already exist, it may or may not contain content from the last investigation.
|
||||||
|
|||||||
Reference in New Issue
Block a user