-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplugin.h
More file actions
168 lines (141 loc) · 7.39 KB
/
Copy pathplugin.h
File metadata and controls
168 lines (141 loc) · 7.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#pragma once
// lvt plugin interface — C ABI for runtime-loaded framework provider plugins.
// Plugins are DLLs placed in %USERPROFILE%/.lvt/plugins/ and discovered at startup.
// This header is the ONLY dependency between lvt core and any plugin.
#include <stdint.h>
#include <Windows.h>
#ifdef __cplusplus
extern "C" {
#endif
// Bumped from 1 to 2 to add the OPTIONAL persistent-connection functions
// below (see "Persistent connections"). This is additive, not a breaking
// change: lvt_loader.cpp accepts any api_version from 1 up to this value
// (not just an exact match), and every v2 function is probed individually
// via GetProcAddress — a v1-only plugin that has never been rebuilt simply
// doesn't export them, and lvt core falls back to the same one-shot
// lvt_enrich_tree path it always used. A plugin only needs to bump its own
// reported api_version once it actually implements the v2 functions.
#define LVT_PLUGIN_API_VERSION 2
// ---------- Plugin metadata ----------
struct LvtPluginInfo {
uint32_t struct_size; // sizeof(LvtPluginInfo), for versioning
uint32_t api_version; // the highest LVT_PLUGIN_API_VERSION this plugin actually implements
const char* name; // short identifier, e.g. "myframework"
const char* description; // human-readable, e.g. "Custom framework support"
};
// ---------- Framework detection ----------
struct LvtFrameworkDetection {
uint32_t struct_size;
const char* name; // framework name reported by plugin
const char* version; // version string or NULL
};
// ---------- Element data (C ABI mirror of lvt::Element) ----------
struct LvtBounds {
int32_t x, y, width, height;
};
struct LvtProperty {
const char* key;
const char* value;
};
struct LvtElementData {
uint32_t struct_size;
const char* type;
const char* framework;
const char* class_name;
const char* text;
LvtBounds bounds;
const LvtProperty* properties;
uint32_t property_count;
struct LvtElementData* children;
uint32_t child_count;
uintptr_t native_handle; // e.g. HWND
};
// ---------- Plugin entry points ----------
// Plugins must export these functions by name.
// Returns static plugin metadata. Called once at load time.
typedef LvtPluginInfo* (*LvtPluginInfoFn)(void);
// Detect if this plugin's framework is present in the target process.
// Returns nonzero if detected, fills `out` with framework info.
// `out` is caller-allocated. Plugin should set name and version fields.
typedef int (*LvtDetectFrameworkFn)(DWORD pid, HWND hwnd, LvtFrameworkDetection* out);
// Enrich the element tree with this plugin's framework data.
// `json_out` receives a malloc'd JSON string (caller frees with lvt_plugin_free).
// The JSON follows the same schema as the XAML TAP DLL output:
// [{"type":"...", "name":"...", "children":[...], "width":..., "height":..., "offsetX":..., "offsetY":...}]
// `hwnd_filter` is the HWND of a specific host window to scope enrichment to,
// or NULL for all.
// Returns nonzero on success.
//
// This one-shot path always works and is what every v1 plugin implements.
// A plugin that also implements the v2 functions below still needs this one:
// it is used by one-shot CLI commands, and remains the watch/MCP fallback for
// plugins that do not implement the complete persistent lifetime group.
// Once a long-running caller explicitly selects v2 for a capable plugin, an
// open/refresh failure is surfaced for reconnection instead of silently
// reinjecting through this function on every refresh.
typedef int (*LvtEnrichTreeFn)(HWND hwnd, DWORD pid, const char* element_class_filter, char** json_out);
// Free memory allocated by the plugin (e.g. json_out from LvtEnrichTreeFn).
typedef void (*LvtPluginFreeFn)(void* ptr);
// ---------- Persistent connections (optional, API v2) ----------
//
// Mirrors src/providers/framework_connection.h's IFrameworkConnection: a
// plugin that implements these lets lvt core (see connection_registry.h)
// establish a connection ONCE and reuse it for many tree refreshes across a
// watch session or an MCP session, instead of calling lvt_enrich_tree fresh
// every single time - the same problem this whole mechanism exists to avoid
// for XAML/WinUI3 (see docs/tap-dll-design.md's connection lifecycle).
//
// The persistent tree path is enabled only when lvt_connection_open,
// lvt_connection_get_tree, lvt_connection_close, and the existing
// lvt_plugin_free export are all present: every successful open must be
// closeable, and every JSON result must be releasable by its allocating
// module. Polling is a separate optional pair:
// lvt_connection_poll_events is used only with
// lvt_connection_events_free. An incomplete v2 group is treated as v1 and
// keeps working through lvt_enrich_tree.
struct LvtConnectionEvent {
uint32_t struct_size;
const char* mutation; // "add" | "remove"
uintptr_t handle;
uintptr_t parent_handle;
int32_t child_index;
const char* element_type; // only meaningful for "add"
const char* name; // only meaningful for "add"
};
// Establishes a persistent connection to (hwnd, pid). Returns an opaque,
// plugin-owned handle, or NULL if unsupported or the connection could not
// be established. One-shot callers continue to use lvt_enrich_tree. Watch
// and MCP retain a missing connection slot and retry open rather than
// silently switching a v2-capable plugin to repeated one-shot enrichment.
typedef void* (*LvtConnectionOpenFn)(HWND hwnd, DWORD pid);
// Re-collects the current tree over `conn` (no re-injection) and yields it
// the same way lvt_enrich_tree does: a malloc'd JSON string in `json_out`,
// freed by the caller via lvt_plugin_free.
typedef int (*LvtConnectionGetTreeFn)(void* conn, const char* element_class_filter, char** json_out);
// Non-blocking: fills `events_out`/`count_out` with whatever incremental
// Add/Remove notifications the plugin has observed since the last call.
// Returns nonzero on success (including "success, zero events"); a plugin
// that never implements real incremental tracking can simply always report
// zero events here - callers always have lvt_connection_get_tree as a full
// refresh fallback, so this is never the only way to get current data.
typedef int (*LvtConnectionPollEventsFn)(void* conn, LvtConnectionEvent** events_out, uint32_t* count_out);
// Frees an array returned by lvt_connection_poll_events.
typedef void (*LvtConnectionEventsFreeFn)(LvtConnectionEvent* events, uint32_t count);
// Closes a connection opened by lvt_connection_open - the plugin's chance
// to do whatever clean teardown its underlying mechanism needs, exactly
// once, when the connection actually ends (not per refresh).
typedef void (*LvtConnectionCloseFn)(void* conn);
// Exported function names (for GetProcAddress)
#define LVT_PLUGIN_INFO_FUNC "lvt_plugin_info"
#define LVT_PLUGIN_DETECT_FUNC "lvt_detect_framework"
#define LVT_PLUGIN_ENRICH_FUNC "lvt_enrich_tree"
#define LVT_PLUGIN_FREE_FUNC "lvt_plugin_free"
// v2, all optional - see "Persistent connections" above.
#define LVT_PLUGIN_CONNECTION_OPEN_FUNC "lvt_connection_open"
#define LVT_PLUGIN_CONNECTION_GET_TREE_FUNC "lvt_connection_get_tree"
#define LVT_PLUGIN_CONNECTION_POLL_EVENTS_FUNC "lvt_connection_poll_events"
#define LVT_PLUGIN_CONNECTION_EVENTS_FREE_FUNC "lvt_connection_events_free"
#define LVT_PLUGIN_CONNECTION_CLOSE_FUNC "lvt_connection_close"
#ifdef __cplusplus
}
#endif