C# 适配 / 绑定(MVP)
www 工作副本 · M5(Arden · 2026-10-21 Asia/Shanghai)
双轨:本页已迁入 Vyntekwww;mvdocs csharp-binding 仍在线对照。
M5-10(Alive 已拍):MVP 显示封装 只认 Controls 轨;Skia/Avalonia 不双开(后续可选宿主)。
实现边界:对拍 bindings tip769d997。Vyntek.Bindings含PixelImageInfo与IGray8/IRgb24/IBgr24/IDepth16(PixelImageHandle实现它们)。Vyntek.Controls有 Share/OpenRead、预算、TryGet*AtView、Unload/Remount,无真实渲染。缺 DLL →DllNotFoundException;缺符号 →EntryPointNotFoundException。host-integration 全文仍在 mvdocs。
关联:image-display · cpp-headers · host-integration(mvdocs) · TC-DISP 薄摘 · 预览 http://127.0.0.1:8792
本文是独立短文,避免把绑定细则塞进 cpp-headers。与 overview / cpp-headers 已有「PInvoke 倾向」表述一致,不另立第二套绑定默认。
定位
| 层 | 语言 | 职责 |
|---|---|---|
vyntek::toolflow / vyntek::imaging | C++ | 编排与像素/句柄权威 |
| 本绑定(MVP) | PInvoke 薄层 | 把公开 C API / 导出入口投影到托管;不复制执行语义 |
| ImageDisplay 等 | C# | UI/显示封装;只消费绑定交出的句柄/投影 |
| C++/CLI | — | 非默认;不作为 MVP 并列路径 |
依赖方向:
ImageDisplay / 编辑器 / Runner(C#)
│
▼
PInvoke 绑定(opaque handle + Dispose)
│
▼
C++ vyntek::imaging / vyntek::toolflow(公开头)C++ 不 #include UI;绑定 不 在托管侧重写 ToolFlow 执行器或第二套 Imaging。
MVP:PInvoke 规则
- 薄:每个导出入口对应一个明确的原生函数;托管侧少逻辑,复杂编排仍在 C++。
- 可控:显式入口、显式错误码/HRESULT 风格约定;避免隐式最终化器代替业务 Release。
- 与头文件对齐:可绑定的符号须能从 cpp-headers.md 公开头推出;
detail/不对绑定暴露。 - C++/CLI 非默认:若未来需要,须单独论证;不得与 PInvoke 并列为 MVP「随便选一个」。
句柄跨边界
| 规则 | 说明 |
|---|---|
| Opaque handle | 托管侧持有 IntPtr / 强类型 SafeHandle 包装的不透明值;不把 C++ 对象布局、vtable、STL 容器直接暴露给 C# |
| 所有权清晰 | 绑定返回的句柄:要么「调用方拥有、须 Release/Dispose」,要么「借用、禁止 Release」——二者在 API 名与文档中写死;禁止共享所有权模糊期 |
| Release / Dispose | 拥有型句柄实现 IDisposable(或等价);Dispose 恰好一次调用原生 Release;重复 Dispose 无害;未 Dispose 不得依赖 GC 最终器作为主路径(可作诊断兜底,不作正确性依赖) |
| 投影类型 | 可选 IPixelImage 等为句柄的托管投影(见 overview);语义仍以 C++ 为准,投影不得放宽 ReadOnly / 寿命 |
| 观察与执行分离 | 经绑定订阅 LastRun / 输出观察(见 output-inspection.md)永不隐式 Run;与显示只观察一致 |
示意(非已发布 ABI):
// 示意:拥有型 opaque handle;Dispose = 原生 Release 恰好一次
public sealed class PixelImageHandle : SafeHandle
{
// IsInvalid / ReleaseHandle → native vyntek_imaging_handle_release(...)
// 禁止把内部指针交给第二处「也负责释放」的所有者
}
// 借用:TryOpen 得到的临时读视图另有 View.Dispose,不释放底层图像所有权ImageDisplay(C#)如何消费
- image-display.md 保持 C# API(
SetImage等)。 - 像素来自 C++
PixelImageHandle,经本绑定投影后交给控件;控件申请读/快照/脱离仍遵守成像/内存专题。 - 不在 C++ 写 Avalonia/Skia UI;不让 ImageDisplay 成为编排 Cancel / 停相机的入口(toolflow §7.4.3)。
与相关文档的对齐
| 文档 | 对齐点 |
|---|---|
| overview.md | 「MVP 托管绑定倾向 PInvoke;C++/CLI 非默认」;Imaging 权威在 C++ |
| cpp-headers.md | 绑定层仅桥公开头;本文展开句柄跨边界,cpp-headers 保持 include 树不膨胀 |
| toolflow.md | 进程内 C++ 库 + PInvoke;观察钩子不驱动执行 |
| examples.md | 编排/成像示例 C++;ImageDisplay 示例 C#(T12) |
| output-inspection.md | 观察事件经绑定上抛时仍用 ToolId;不驱动 Run |
| host-integration.md | R7:headless / C# 显示宿主同核;示意 vyntek_toolflow_* / vyntek_imaging_* 与本文 PInvoke 对齐;停止矩阵宿主侧分派 |
明确不做(MVP)
- 以 C++/CLI 作为默认或并列默认绑定。
- 托管与原生「共同拥有」同一句柄且无唯一 Release 点。
- 在绑定层实现第二套 ToolFlow / 像素池。
- 把 MPF / 旧 DAG /
.vpp术语带入绑定 API。
文档状态:设计草案(2026-10-21,Asia/Shanghai)。T11 Alive 拍板:MVP=PInvoke;C++/CLI 非默认;opaque handle + Release/Dispose;ImageDisplay 仅 C# 经本绑定消费。与 overview / cpp-headers / toolflow v1.9 / host-integration.md(R7)对齐。
实现对拍(bindings tip 769d997 · 按实)
| 表面 | 按实 |
|---|---|
| 布局 | bindings/csharp/{Vyntek.Native, Vyntek.Bindings, Vyntek.Controls, Vyntek.Controls.Tests, Vyntek.Smoke} · net10.0 |
| 双库名 | vyntek_toolflow / vyntek_imaging |
| 契约头 | include/vyntek/capi/vyntek_exports.h(NON-STABLE) |
| 句柄 | PixelImageHandle : SafeHandle, IPixelImage;Dispose→handle_release;Share 独立拥有 |
| 像素取样 | Imaging.TryGet* → try_get_*;Depth16 返回 (ok, raw, isValid) |
| 会话预览 | AcquisitionSession.TryLatest;空 = OK + null |
| ImageDisplay | 见 image-display.md;无 C++ UI;MVP = Controls(M5-10) |
仍缺口:无真实渲染;TC-DISP 未验收。Skia/Avalonia 接通属 M5-10 非拦。
文档状态:www 工作副本(2026-10-21 Asia/Shanghai)。T11 MVP=PInvoke。bindings tip 769d997。