首页
/ WSL 容器镜像进度回调 WslcContainerImageProgressCallback:从 SDK 签名到底层实现全解析

WSL 容器镜像进度回调 WslcContainerImageProgressCallback:从 SDK 签名到底层实现全解析

2026-09-08 21:13:16作者:裴麒琰

导读

WslcContainerImageProgressCallback 是 WSL(Windows Subsystem for Linux)容器 SDK(WSLC)中用于接收容器镜像拉取(Pull)/推送(Push)进度通知的回调函数类型。在 WslcPullSessionImageWslcPushSessionImage 等镜像管理 API 中,调用方通过该回调实时获取每个镜像层的下载/解压状态与字节进度,从而驱动进度条、日志等 UI 展示。读完本文,你将掌握该回调的类型签名、进度消息结构与状态枚举的完整定义,学会在 C 代码中正确挂接回调并解析进度数据,并了解 SDK 底层如何把引擎字符串状态转换为枚举、如何通过 IWSLCCompatProgressCallback 适配层将进度转发到你的函数。

一、回调类型签名与参数说明

该回调是 SDK 公开 C API 的一部分,完整定义位于 wslcsdk.h,同时也是官方 API 参考文档 wslccontainerimageprogresscallback.md 的主题:

typedef HRESULT(CALLBACK* WslcContainerImageProgressCallback)(const WslcImageProgressMessage* progress, PVOID context);
参数 类型 说明
progress const WslcImageProgressMessage* 单次进度事件的完整消息,包含层 ID、状态与字节进度,见下文"进度消息结构"
context PVOID 调用方自定义上下文指针,原样透传,通常指向一个用户状态结构
  • 返回值为 HRESULT。在 SDK 底层实现中,回调的返回值会被直接作为进度分发的返回值返回给上层(详见"五、底层实现"),因此建议始终返回 S_OK,除非你确实需要中断进度分发。
  • 参数 context 与镜像操作选项结构中的 progressCallbackContext 字段一一对应,SDK 不会解析或修改它,仅做透传,可用于携带回调状态(如累计下载量、是否已收到完成事件等)。

二、进度消息结构 WslcImageProgressMessage

回调收到的 progress 参数指向如下结构(官方文档见 wslcimageprogressmessage.md,源码定义见 wslcsdk.h):

typedef struct WslcImageProgressMessage
{
    _Out_ PCSTR id;                       // layer ID or digest
    _Out_ WslcImageProgressStatus status; // "Downloading", "Extracting", etc.
    _Out_ WslcImageProgressDetail detail;
} WslcImageProgressMessage;
字段 类型 含义
id PCSTR 镜像层 ID(layer ID)或摘要(digest),用于区分不同层的事件
status WslcImageProgressStatus 该层当前所处的进度阶段(枚举值,见下节)
detail WslcImageProgressDetail 字节级进度详情

其中 WslcImageProgressDetail 是一个仅含两个 uint64_t 字段的小结构(wslcsdk.h):

typedef struct WslcImageProgressDetail
{
    _Out_ uint64_t currentBytes; // bytes downloaded so far
    _Out_ uint64_t totalBytes;   // total bytes expected
} WslcImageProgressDetail;
  • currentBytes:当前已传输(下载/上传)的字节数;
  • totalBytes:预期总字节数。注意某些阶段(如 Waiting)可能尚未获知总量,渲染进度条时应处理 totalBytes == 0 的边界情况(可显示为"传输中/未知总量")。

三、进度状态枚举 WslcImageProgressStatus

status 字段的取值来自枚举 WslcImageProgressStatus,完整定义见 wslcsdk.h

typedef enum WslcImageProgressStatus
{
    WSLC_IMAGE_PROGRESS_STATUS_UNKNOWN = 0,     // 未知/未识别状态
    WSLC_IMAGE_PROGRESS_STATUS_PULLING = 1,     // "Pulling fs layer"
    WSLC_IMAGE_PROGRESS_STATUS_WAITING = 2,     // "Waiting"
    WSLC_IMAGE_PROGRESS_STATUS_DOWNLOADING = 3, // "Downloading"
    WSLC_IMAGE_PROGRESS_STATUS_VERIFYING = 4,   // "Verifying Checksum"
    WSLC_IMAGE_PROGRESS_STATUS_EXTRACTING = 5,  // "Extracting"
    WSLC_IMAGE_PROGRESS_STATUS_COMPLETE = 6     // "Pull complete"
} WlcImageProgressStatus;

从枚举注释可以看出,这些枚举值与镜像引擎(Docker/Moby 风格)输出的状态字符串一一对应,一个典型镜像层的生命周期大致为:

Pulling fs layer → Waiting → Downloading → Verifying Checksum → Extracting → Pull complete

在实际渲染进度 UI 时,WSLC_IMAGE_PROGRESS_STATUS_COMPLETE 是判断某一层完成的可靠信号;而 WSLC_IMAGE_PROGRESS_STATUS_UNKNOWN 表示 SDK 未能将引擎字符串映射为已知状态(见第五节"状态映射"),业务代码可将其当作通用进度处理。

四、在镜像操作选项中使用回调

该回调并非独立注册,而是作为镜像操作选项结构的一个字段传入。以拉取镜像为例,选项结构 WslcPullImageOptionswslcsdk.h)定义如下:

typedef struct WslcPullImageOptions
{
    _In_z_ PCSTR uri;
    WslcContainerImageProgressCallback progressCallback;
    PVOID progressCallbackContext;
    _In_opt_z_ PCSTR registryAuth;
} WslcPullImageOptions;
  • uri:要拉取的镜像引用,如 docker.io/library/alpine:latest
  • progressCallback:进度回调函数指针,可置 NULL 表示不接收进度;
  • progressCallbackContext:透传给回调的自定义上下文;
  • registryAuth:可选,私有仓库的认证头(registry auth header)。

推送镜像的选项结构 WslcPushImageOptions 同样包含 progressCallbackprogressCallbackContext 两个字段。SDK 侧通过 ProgressCallback::CreateIf(options) 判断:仅当选项非空且 progressCallbackNULL 时才创建内部进度转发对象(见 ProgressCallback.h)。

五、完整示例:拉取镜像并打印进度

官方 API 文档 wslcpullsessionimage.md 给出了可直接编译的完整示例,回调写法如下:

HRESULT CALLBACK OnImageProgress(const WslcImageProgressMessage* progress, PVOID context)
{
    UNREFERENCED_PARAMETER(context);
    printf("%s %llu/%llu\n",
        progress->id,
        (unsigned long long)progress->detail.currentBytes,
        (unsigned long long)progress->detail.totalBytes);
    return S_OK;
}

WslcPullImageOptions pullOptions = { 0 };
pullOptions.uri = "docker.io/library/alpine:latest";
pullOptions.progressCallback = OnImageProgress;
pullOptions.progressCallbackContext = NULL;
pullOptions.registryAuth = NULL;

HRESULT hr = WslcPullSessionImage(session, &pullOptions, NULL);

在此基础上,可以进一步利用 progress->status 枚举做状态感知的 UI:

HRESULT CALLBACK OnImageProgress(const WslcImageProgressMessage* progress, PVOID context)
{
    const char* stage = "?";
    switch (progress->status)
    {
    case WSLC_IMAGE_PROGRESS_STATUS_PULLING:     stage = "pulling layer";    break;
    case WSLC_IMAGE_PROGRESS_STATUS_WAITING:     stage = "waiting";          break;
    case WSLC_IMAGE_PROGRESS_STATUS_DOWNLOADING: stage = "downloading";      break;
    case WSLC_IMAGE_PROGRESS_STATUS_VERIFYING:   stage = "verifying";        break;
    case WSLC_IMAGE_PROGRESS_STATUS_EXTRACTING:  stage = "extracting";       break;
    case WSLC_IMAGE_PROGRESS_STATUS_COMPLETE:    stage = "complete";         break;
    default:                                     stage = "unknown";          break;
    }
    printf("[%s] %s: %llu / %llu bytes\n",
        progress->id, stage,
        (unsigned long long)progress->detail.currentBytes,
        (unsigned long long)progress->detail.totalBytes);
    return S_OK;
}

六、底层实现:SDK 如何把进度转发给你的回调

要理解该回调的真实调用时机与数据来源,需要阅读 SDK 的进度适配层实现 ProgressCallback.cpp

  1. COM 适配层ProgressCallback 类实现了内部接口 IWSLCCompatProgressCallback(见 ProgressCallback.h),构造函数保存用户回调 m_callback 与上下文 m_context,SDK 镜像操作(如拉取/推送)内部通过该 COM 接口统一接收引擎进度事件。

  2. 数据组装OnProgress(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total) 将引擎上报的原始参数组装为 WslcImageProgressMessage

    • message.id = Id(层 ID 或 digest);
    • message.status = ConvertStatus(Status)(引擎字符串 → 枚举);
    • message.detail.currentBytes = Currentmessage.detail.totalBytes = Total

    然后调用用户回调:return m_callback(&message, m_context);(见 ProgressCallback.cpp)。

  3. 状态字符串 → 枚举映射ConvertStatus 通过精确字符串匹配与前缀匹配把引擎输出(如 "Pulling from ""Pulling fs layer""Waiting""Downloading""Verifying Checksum""Extracting""Pull complete" 等)转换为上文的枚举值(ProgressCallback.cpp)。无法识别时记录调试日志并返回 WSLC_IMAGE_PROGRESS_STATUS_UNKNOWN。源码注释中也明确提到该字符串映射方案"较为脆弱"(fragile),且引擎字符串本身未做本地化,因此业务代码不应假设所有引擎输出都能被枚举覆盖,对 UNKNOWN 状态要有兜底渲染。

七、WinRT 侧封装与测试验证

  • WinRT 封装:SDK 同时提供 WinRT 版本 Microsoft.WSL.Containers.ImageProgress,其属性 IdStatusCurrentBytesTotalBytes 与 C 结构的 idstatusdetail.currentBytesdetail.totalBytes 一一对应(见 ImageProgress.h),C#/WinRT 调用方可直接绑定到 XAML 进度控件。
  • 测试验证:SDK 单元测试 ImageProgressCallbackWslcSdkTests.cpp)实测了回调行为:测试在本地 registry 上先推送再拉取 hello-world:latest 镜像,回调中记录 invoked = true,并断言回调确实被调用(VERIFY_IS_TRUE(ctx.invoked)),且在拉取场景下收到过非 UNKNOWN 的已知状态(VERIFY_IS_TRUE(ctx.sawKnownStatus))。这从测试侧印证了:只要在选项结构中设置了 progressCallback,拉取/推送镜像过程中该回调就会被可靠触发,且 context 指针可用于在多次回调之间携带状态(测试中的 ProgressContext 即为一例)。

八、使用注意事项小结

  1. 回调一定是在镜像操作(拉取/推送)过程中被同步触发,实现应保持轻量,避免在回调内做耗时操作阻塞操作流程。
  2. 多个层会各自上报进度progress->id 区分不同层,同一层会经历 Pulling → Waiting → Downloading → Verifying → Extracting → Complete 多个阶段事件,UI 应按 id 聚合展示。
  3. 处理 totalBytes 未知的情况:Waiting、Verifying 等阶段可能尚无总量信息,进度条需有"不确定进度"形态。
  4. WSLC_IMAGE_PROGRESS_STATUS_UNKNOWN 兜底:引擎字符串与枚举的映射由 ProgressCallback.cpp 中的固定规则决定,未来引擎输出变化时可能落入 UNKNOWN。
  5. context 是唯一允许携带用户状态的地方:与 progressCallbackContext 配套使用,SDK 不解析、不释放该指针,生命周期由调用方管理。

相关资源索引

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
docsdocs
暂无描述
Markdown
899
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
525
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395