Inspecting the internals of GExperts while it is running in the IDE

ai&dr – if you don’t care.

One of the annoying things when using Claude Code for GExperts is that it cannot test the UI of GExperts itself. That means I have to open the IDE, call the dialogs, check for problems, maybe make screenshots for Claude Code to inspect. I can’t just let it work on its own like it did when fixing bugs and adding features the the code formatter. So I came up with this idea:

ME> I think it would be helpful if you could somehow open the GExperts forms within the Delphi IDE, press buttons, select options, enter Text etc. and read properties from the controls (e.g. position and size) and windows, possibly make screenshots. The idea is to track down any display / scaling problems without my help. Any idea?

CC> This is an interesting idea. Let me explore what's available in your environment and what approaches would be practical.

Explore(Explore UI automation options)
Done (42 tool uses · 43.8k tokens · 2h 22m 0s)

CC> Good findings from the exploration. Let me think about the practical approaches and ask some clarifying questions.

It then went on to ask me various questions about using external tools that it did find, and suggested to create a stand alone executable that creates and shows the GExperts forms. That wasn't quite what I had in mind.

ME> I was thinking about some code within GExperts that communicates with an external program. That would have the advantage of catching oddities that might be caused by running in the IDE (which has its own share of bugs)

CC> That makes a lot of sense — testing inside the actual IDE catches real-world issues that a standalone test wouldn't. So the architecture would be:

* GExperts DLL side: A lightweight server (background thread) that accepts commands and queries the VCL forms on the main thread
* External CLI tool: A standalone .exe that Claude invokes to send commands and get responses

The key question is the IPC mechanism. TCP would be easiest from WSL (Claude could even use nc or a simple script), while named pipes are more "Windows native" but harder to access from WSL.

* User answered Claude's questions:
  - Which IPC mechanism for communication between GExperts DLL and the external tool?
      Answer: TCP socket</li>
  - What capabilities are most important initially?
      Answer: Inspection first

Good choices. TCP + inspection-first is the most practical starting point. Let me design the plan.

And then it wrote the following plan:

——-

GExperts UI Inspection Server

Context

When tracking down display/DPI scaling problems in GExperts forms, there is currently no way to see or inspect the running UI inside the Delphi IDE from the command line. This plan adds a lightweight TCP inspection server embedded in the GExperts DLL that lets an external CLI tool query form/control properties and take screenshots. Testing inside the actual IDE catches real-world issues that standalone testing would miss.

Architecture

 Delphi IDE Process                        WSL / Claude
┌──────────────────────┐                ┌─────────────────┐
│  GExperts DLL        │   TCP :3580    │  GxInspect.exe  │
│  ┌────────────────┐  │◄──────────────►│  (console app)  │
│  │ TGxInspectSrv  │  │  line-based   │                 │
│  │ (bg thread)    │  │  protocol     │  Claude invokes │
│  │    ↓ PostMsg   │  │               │  from bash      │
│  │ Main VCL thrd  │  │               └─────────────────┘
│  │ (hidden wnd)   │  │
│  └────────────────┘  │
└──────────────────────┘

Protocol

Line-based text protocol. The client sends one command line (CRLF terminated), and the server responds with multiple lines terminated by an END line.

Commands (Phase 1 — read-only)

Command Description
FORMS List all forms (class, caption, bounds, visible, DPI)
CONTROLS <id> Enumerate controls recursively with properties
SCREENSHOT <id> <path> Save form screenshot as BMP to Windows path
BOUNDS <id> Form geometry: position, client size, monitor, DPI
CHECK <id> Automated overlap/clipping detection

<id> matches by form caption (substring) or class name.

Response format examples

> FORMS
TfmUsesExpertOptions "Uses Clause Manager, Configuration" [338,241 329x606] Visible DPI=120
TfmUsesManager "Uses Clause Manager" [100,100 800x600] Visible DPI=96
END

> CONTROLS UsesExpertOptions
TButton btnOK [145,572 85x25] "OK" Visible Enabled
TButton btnCancel [236,572 85x25] "Cancel" Visible Enabled
TGroupBox grp_SortSettings [8,312 313x252] " Sorting and Grouping " Visible Enabled
  TListBox lb_Prefixes [8,18 204x120] "" Visible Enabled
  TButton btnPrefixAdd [220,18 85x25] "Add..." Visible Enabled
END

> CHECK UsesExpertOptions
OVERLAP: btnOK [145,572 85x25] and btnCancel [150,572 85x25] intersect
CLIPPED: btnPrefixReset text "Reset to Defaults" needs 98px but control is 85px wide
OUTSIDE: lb_Prefixes [8,18 204x120] extends beyond parent grp_SortSettings [0,0 313x252]
OK
END

Implementation

1. GExperts DLL side: GX_InspectionServer.pas

A new unit in Source/Framework/ containing:

  • TGxInspectServer — Creates a hidden window via AllocateHWnd and starts a TCP listener thread. Incoming commands are marshaled to the VCL main thread via PostMessage + TEvent synchronization (Delphi 6 compatible, no anonymous methods).
  • TGxInspectThread — Background thread using raw WinSock API. Listens on 127.0.0.1:3580 (localhost only for security). Accepts one client at a time, reads command lines, calls ExecuteOnMainThread, sends responses.

Thread marshaling pattern

// TCP thread calls this:
function TGxInspectServer.ExecuteOnMainThread(const Cmd: string): string;
begin
  FCritSect.Enter;  // serialize concurrent requests
  try
    FPendingCommand := Cmd;
    FResultEvent.ResetEvent;
    PostMessage(FHiddenWnd, WM_GX_INSPECT, 0, 0);
    FResultEvent.WaitFor(10000);  // 10s timeout
    Result := FPendingResult;
  finally
    FCritSect.Leave;
  end;
end;

// Main VCL thread handles the message:
procedure TGxInspectServer.HiddenWndProc(var Msg: TMessage);
begin
  if Msg.Msg = WM_GX_INSPECT then begin
    FPendingResult := ProcessCommand(FPendingCommand);
    FResultEvent.SetEvent;
  end else
    Msg.Result := DefWindowProc(FHiddenWnd, Msg.Msg, Msg.WParam, Msg.LParam);
end;

Command handlers (all run on main VCL thread)

  • FORMS — Iterate Screen.CustomForms, output class name, caption, bounds, visible state, DPI.
  • CONTROLS — Find form by caption/class, recursively enumerate Controls[i] for each TWinControl. Output: Name, ClassName, Left, Top, Width, Height, Caption/Text, Visible, Enabled. Indent by nesting depth.
  • SCREENSHOT — Use PrintWindow API to capture the form (including non-client area) into a TBitmap, save as BMP.
  • CHECK — Automated detection of: sibling controls with overlapping bounds, controls extending outside parent client rect, button/label text wider than control width (using Canvas.TextWidth), visible controls with zero width or height.

2. External CLI tool: GxInspect.exe

A standalone console application in Projects/StandAlone/GxInspect/. Simple TCP client that connects to the server, sends a command, prints the response.

GxInspect.exe [options] <command> [args...]
  -p <port>    Server port (default: 3580)

Commands:
  FORMS                              List all forms
  CONTROLS <form-id>                 List controls
  SCREENSHOT <form-id> <filepath>    Save screenshot
  BOUNDS <form-id>                   Form geometry
  CHECK <form-id>                    Overlap/clipping check

3. Activation

The inspection server is opt-in via environment variable. Set GX_INSPECT=1 (default port 3580) or GX_INSPECT=<port> before launching the IDE. The server starts after IDE initialization (in DoAfterIDEInitialized) and stops when GExperts unloads. No registry settings needed.

Files to create/modify

File Action
Source/Framework/GX_InspectionServer.pas New — TCP server + command handlers
Projects/StandAlone/GxInspect/src/GxInspect.dpr New — console app
Projects/StandAlone/GxInspect/__Build_Project.cmd New — build script
Projects/StandAlone/GxInspect/_buildproject.sh New — WSL wrapper
Source/Framework/GX_GExperts.pas Modify — start/stop server
All 24+ project DPR files Modify — add GX_InspectionServer unit

——-

I think that looks good. I’ll let it implement it and see where this gets me.