首页
/ WSL 容器镜像导入实战:深入解析 WslcImportSessionImage C API

WSL 容器镜像导入实战:深入解析 WslcImportSessionImage C API

2026-09-09 13:41:08作者:裴锟轩Denise

导读

WslcImportSessionImage 是 Windows Subsystem for Linux(WSL)容器 SDK(WslcSDK)中用于把本地打包好的容器镜像(tar 归档)直接导入到 WSL 会话内的核心 C API。本文围绕该 API 的完整签名、参数语义、底层实现与配套选项结构展开,结合仓库源码给出可复制、可运行的 C 代码示例,并对比其姊妹接口 WslcImportSessionImageFromFile,帮助开发者掌握"从本地镜像文件到 WSL 会话可用镜像"的完整流程。

WslcImportSessionImage 是什么

在 WSL 的容器化场景中,镜像的来源通常有两种:一种是从镜像仓库(如 docker.io/library/alpine:latest)通过网络拉取(对应 WslcPullSessionImage);另一种则是本地已有的 tar 归档镜像文件,需要通过导入(import)接口注册进当前会话。WslcImportSessionImage 正是后者在 C 层面的实现入口。

该 API 声明位于仓库头文件 src/windows/WslcSDK/wslcsdk.h,并通过 src/windows/WslcSDK/wslcsdk.def 导出,属于 WslcSDK 公共接口。其完整签名如下:

STDAPI WslcImportSessionImage(
    _In_ WslcSession session,
    _In_z_ PCSTR imageName,
    _In_ HANDLE imageContent,
    _In_ uint64_t imageContentBytes,
    _In_opt_ const WslcImportImageOptions* options,
    _Outptr_opt_result_z_ PWSTR* errorMessage);

参数逐一解析

参数 类型 方向 说明
session WslcSession in 目标会话句柄,由 WslcCreateSession 创建
imageName PCSTR in 导入后在会话内的镜像名称,采用 repository:tag 风格,如 demo/imported:latest
imageContent HANDLE in 镜像内容源句柄,通常是已打开文件的句柄
imageContentBytes uint64_t in 镜像内容的字节总数
options const WslcImportImageOptions* in, optional 导入选项,可传 NULL
errorMessage PWSTR* out, optional 失败时返回的可读错误信息,调用方需用 CoTaskMemFree 释放

返回值类型为 HRESULTS_OK 表示导入成功;失败时可通过 errorMessage 获取详细原因(如果传入非空指针)。

关键注意点:imageContent 是 HANDLE 而非 void*

原文档特别强调了一个容易被忽视的细节:头文件中 imageContent 的声明类型是 HANDLE,而不是常见的 void*。这意味着调用方必须传入一个有效的 Windows 内核句柄(通常由 CreateFileW 获得),而不是普通内存缓冲区指针。这也是该 API 与直接接受文件路径的变体在数据传递方式上的本质区别。

从文件句柄导入镜像:完整示例

以下示例演示了"打开本地 tar 归档 → 获取文件大小 → 导入会话"的完整流程,直接取自原文档并补充了错误处理:

#include <windows.h>
#include <stdint.h>
#include <wslcsdk.h>

HANDLE imageContent = CreateFileW(
    L"C:\\images\\demo-import.tar",
    GENERIC_READ,          // 只读访问
    FILE_SHARE_READ,       // 允许其他进程并发读取
    NULL,
    OPEN_EXISTING,         // 文件必须已存在
    FILE_ATTRIBUTE_NORMAL,
    NULL);
if (imageContent == INVALID_HANDLE_VALUE) {
    // 处理文件打开失败(GetLastError 查看原因)
    return 1;
}

LARGE_INTEGER size = { 0 };
if (!GetFileSizeEx(imageContent, &size)) {
    CloseHandle(imageContent);
    return 1;
}

WslcImportImageOptions importOptions = { 0 };
HRESULT hr = WslcImportSessionImage(
    session,
    "demo/imported:latest",
    imageContent,
    (uint64_t)size.QuadPart,
    &importOptions,
    NULL);
if (FAILED(hr)) {
    // 导入失败处理
}

CloseHandle(imageContent);

要点说明:

  • GENERIC_READ + FILE_SHARE_READ:导入过程只需读取镜像内容,同时允许其他读取者共享访问;
  • GetFileSizeEx 返回的 64 位文件大小需转换为 uint64_t 后作为 imageContentBytes 传入,确保大文件(超过 4GB)也能被正确处理;
  • 导入完成后及时 CloseHandle 释放文件句柄;
  • 原文档中错误处理传 NULL,实际生产代码建议传入 &errorMessage 以便定位失败原因。

配置导入行为:WslcImportImageOptions 与进度回调

options 参数的类型是 WslcImportImageOptions,定义同样位于 src/windows/WslcSDK/wslcsdk.h

typedef struct WslcImportImageOptions
{
    _In_opt_ WslcContainerImageProgressCallback progressCallback;
    _In_opt_ PVOID progressCallbackContext;
} WslcImportImageOptions;
字段 类型 说明
progressCallback WslcContainerImageProgressCallback 导入进度回调,可为 NULL
progressCallbackContext PVOID 回调上下文指针,原样透传给回调

两个字段均可置空({ 0 } 初始化即可),实现"静默导入"。若需要向用户展示进度,可设置进度回调。回调类型 WslcContainerImageProgressCallback 定义为:

typedef HRESULT(CALLBACK* WslcContainerImageProgressCallback)(
    const WslcImageProgressMessage* progress, PVOID context);

参考 WslcPullSessionImage 文档中的回调写法,导入场景可照搬同一模式:

HRESULT CALLBACK OnImportProgress(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;
}

WslcImportImageOptions importOptions = { 0 };
importOptions.progressCallback = OnImportProgress;
importOptions.progressCallbackContext = NULL;

从源码结构看,进度消息 WslcImageProgressMessage 中的 detail 字段(WslcImageProgressDetail)携带 currentBytestotalBytes,可用于渲染百分比进度条。

更简洁的替代:WslcImportSessionImageFromFile

如果镜像数据已经是一个本地文件,仓库还提供了更便捷的变体 WslcImportSessionImageFromFile,它直接接受宽字符串文件路径,省去了 CreateFileW/GetFileSizeEx/CloseHandle 三步样板代码:

WslcImportImageOptions importOptions = { 0 };
HRESULT hr = WslcImportSessionImageFromFile(
    session,
    "demo/imported:latest",
    L"C:\\images\\demo-import.tar",
    &importOptions,
    NULL);

两者本质是同一导入流程的两种数据通道:WslcImportSessionImage 接受已打开的 HANDLE,适合镜像内容来自非文件源(如管道、内存映射、网络流)的场景;WslcImportSessionImageFromFile 接受 PCWSTR 路径,代码更简洁。WinRT 层的封装 src/windows/WslcSDK/winrt/Session.cpp 也印证了这一点:其 ImportImage/ImportImageAsync 内部统一调用 WslcImportSessionImageFromFile,异步版本会设置 ImageProgressCallback 以透传进度事件。

镜像命名规则与会话内管理

imageName 参数采用 repository:tag 形式,例如示例中的 demo/imported:latest。导入成功后,该镜像会以这个名字登记在当前会话中,可供后续创建容器时引用(如 WslcInitContainerSettings("demo/imported:latest", ...))。

镜像名称的长度受限于 src/windows/WslcSDK/wslcsdk.h 中定义的常量:

#define WSLC_IMAGE_NAME_LENGTH 256 // 255 chars + null

即镜像名最多 255 个字符(不含结尾空字符)。会话内已导入的镜像可通过 WslcListSessionImages 枚举,其返回的 WslcImageInfo 结构携带镜像名(CHAR name[WSLC_IMAGE_NAME_LENGTH])、SHA-256 摘要(uint8_t sha256[32])、大小(sizeBytes)和创建时间(createdUnixTime)等信息;不再需要的镜像可调用 WslcDeleteSessionImage 删除。由此可以推断,导入、列表、删除共同构成了会话级镜像的本地管理闭环,而 WslcTagSessionImageWslcPushSessionImage 则负责镜像的打标与向远端仓库发布。

集成到完整会话生命周期

导入接口不能独立工作,它依赖一个已创建的 WslcSession。参考仓库中的 端到端示例,一个最小可用的导入流程骨架如下:

// 1. 初始化 COM(WslcSDK 依赖 COM 互操作)
CoInitializeEx(nullptr, COINIT_MULTITHREADED);

// 2. 初始化会话设置并创建会话
WslcSessionSettings sessionSettings;
WslcInitSessionSettings(L"MyApp", storagePath, &sessionSettings);
WslcSession session = nullptr;
HRESULT hr = WslcCreateSession(&sessionSettings, &session, &error);
if (FAILED(hr)) { /* 释放 error 后退出 */ }

// 3. 导入镜像(见上文示例)
hr = WslcImportSessionImage(session, "demo/imported:latest",
                            imageContent, (uint64_t)size.QuadPart,
                            &importOptions, &error);
if (FAILED(hr)) {
    wprintf(L"Import failed: %s\n", error ? error : L"unknown");
    CoTaskMemFree(error);
    WslcTerminateSession(session);
    WslcReleaseSession(session);
    CoUninitialize();
    return 1;
}

// 4. 清理
CoTaskMemFree(error);
WslcTerminateSession(session);
WslcReleaseSession(session);
CoUninitialize();

两个实践要点:

  • 错误信息释放errorMessage 由 SDK 通过 COM 分配,读取后必须调用 CoTaskMemFree 释放,避免内存泄漏;
  • 会话清理顺序:导入失败时应先 CoTaskMemFree(error),再依次 WslcTerminateSessionWslcReleaseSessionCoUninitialize,与仓库端到端示例中的清理路径保持一致。

小结

WslcImportSessionImage 为 WSL 容器 SDK 提供了基于句柄的镜像导入通道,配合 WslcImportImageOptions 进度回调可实现带进度反馈的本地镜像导入;需要更简洁用法时可选用 WslcImportSessionImageFromFile。掌握该接口后,开发者即可把任意符合 WSL 容器格式的 tar 镜像离线注入会话,结合 Image APIs 索引 中的拉取、加载、打标、推送与删除接口,构建完整的本地镜像管理管线。头文件 wslcsdk.h 是查阅全部相关结构体与常量的一手依据,建议在编码前通读。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
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
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
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
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525