☰
WSL C SDK 镜像标记指南:深入解析 WslcTagSessionImage 的用法、参数与底层实现
2026/9/30 11:16:34 网站建设 项目流程

WSL C SDK 镜像标记指南:深入解析 WslcTagSessionImage 的用法、参数与底层实现

【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL

导读

WslcTagSessionImage是 Windows Subsystem for Linux(WSL)C SDK(WslcSDK)中负责为容器镜像创建新标签(tag)的核心 API。在 WSL 容器工作流中,拉取镜像(WslcPullSessionImage)之后、推送镜像(WslcPushSessionImage)之前,通常需要先用它给镜像打上目标仓库前缀与语义化标签,才能在本地镜像库中定位并发布镜像。本文将围绕该 API 的签名、参数、选项结构体、返回值与错误处理展开,并结合本仓库的 C 层实现(wslcsdk.cpp)与单元测试(WslcSdkTests.cpp)剖析其底层调用链,最终给出可直接复制的完整 C 示例代码,帮助你快速掌握在 C/C++ 项目中为 WSL 容器镜像打标签的实战方法。

API 签名与参数说明

WslcTagSessionImage的完整函数签名如下(声明见 wslcsdk.h):

STDAPI WslcTagSessionImage( _In_ WslcSession session, _In_ const WslcTagImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);
参数类型方向说明
sessionWslcSessionin目标 WSL 容器会话句柄,由WslcCreateSession创建
optionsconst WslcTagImageOptions*in标记配置,指定源镜像名/ID、目标仓库与目标标签
errorMessagePWSTR*out, optional失败时返回的本地化错误信息(UTF-16 字符串),可为NULL

返回值:HRESULT。S_OK表示标记成功;失败时返回对应的错误码,并通过errorMessage提供可读错误描述。

参数语义

  • session:必须是有效会话。在 wslcsdk.cpp 的实现中,函数首先通过CheckAndGetInternalType(session)解析句柄,若底层会话对象为空,立即返回HRESULT_FROM_WIN32(ERROR_INVALID_STATE)——这也提醒调用方:任何图像管理 API 都必须先成功创建会话,不能对无效会话调用。
  • options:指向WslcTagImageOptions结构体的指针。实现中会校验其三个字段image、repo、tag均非空,任何一个为NULL都返回E_INVALIDARG(详见后文错误处理)。
  • errorMessage:可选输出参数。若传入非空指针,SDK 会通过内部ErrorInfoWrapper捕获底层错误并将可读信息写入该缓冲区;调用方应使用CoTaskMemFree释放。

选项结构体 WslcTagImageOptions

标记行为完全由WslcTagImageOptions结构体驱动(定义见 wslctagimageoptions.md):

typedef struct WslcTagImageOptions { _In_z_ PCSTR image; // Source image name or ID. _In_z_ PCSTR repo; // Target repository name. _In_z_ PCSTR tag; // Target tag name. } WslcTagImageOptions;
字段类型说明
imagePCSTR源镜像名称或 ID,例如docker.io/library/alpine:latest
repoPCSTR目标仓库名称,例如demo/alpine或带注册表地址的localhost:5000/demo/alpine
tagPCSTR目标标签名称,例如stable

三个字段组合后形成的新镜像引用即repo:tag。注意:

  • 使用{ 0 }初始化结构体是一个好习惯,能保证未赋值的字段为空指针,从而让 SDK 的参数校验(E_INVALIDARG)在字段缺失时立即生效,而不是携带未定义内存内容继续执行。
  • 字段均为 UTF-8 编码的 C 字符串(PCSTR),而errorMessage是 UTF-16(PWSTR),混合使用时要留意字符集差异。

最小可运行示例

文档给出的经典示例可直接编译运行(前提是已链接wslcsdk.lib并完成 COM 初始化与会话创建):

WslcTagImageOptions tagOptions = { 0 }; tagOptions.image = "docker.io/library/alpine:latest"; tagOptions.repo = "demo/alpine"; tagOptions.tag = "stable"; HRESULT hr = WslcTagSessionImage(session, &tagOptions, NULL); if (FAILED(hr)) { // 处理失败,可读取 errorMessage 获取详情 }

在完整生命周期中的位置

WslcTagSessionImage通常与镜像拉取、列表、推送、删除 API 配合使用。完整的生命周期示例见 end-to-end-example.md,其典型顺序为:

  1. 调用WslcInitSessionSettings/WslcCreateSession创建会话;
  2. 调用WslcPullSessionImage拉取基础镜像;
  3. 调用WslcTagSessionImage为镜像添加目标仓库前缀与新标签(便于后续推送);
  4. 调用WslcPushSessionImage推送到注册表;
  5. 调用WslcListSessionImages校验结果,调用WslcDeleteSessionImage清理不再需要的标签;
  6. 最后WslcTerminateSession/WslcReleaseSession释放资源。

错误处理与参数校验(源码级)

在 wslcsdk.cpp 中,WslcTagSessionImage的实现按顺序执行如下校验:

STDAPI WslcTagSessionImage(_In_ WslcSession session, _In_ const WslcTagImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage) try { ErrorInfoWrapper errorInfoWrapper{errorMessage}; auto internalType = CheckAndGetInternalType(session); RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->session); RETURN_HR_IF_NULL(E_POINTER, options); RETURN_HR_IF_NULL(E_INVALIDARG, options->image); RETURN_HR_IF_NULL(E_INVALIDARG, options->repo); RETURN_HR_IF_NULL(E_INVALIDARG, options->tag); WSLCCompatTagImageOptions runtimeOptions{}; runtimeOptions.Image = options->image; runtimeOptions.Repo = options->repo; runtimeOptions.Tag = options->tag; return errorInfoWrapper.CaptureResult(internalType->session->TagImage(&runtimeOptions)); } CATCH_RETURN();

校验顺序与返回码对应关系如下:

条件返回码含义
会话无效或未启动HRESULT_FROM_WIN32(ERROR_INVALID_STATE)底层session为空
options为NULLE_POINTER选项指针为空
options->image为NULLE_INVALIDARG源镜像未指定
options->repo为NULLE_INVALIDARG目标仓库未指定
options->tag为NULLE_INVALIDARG目标标签未指定

校验通过后,函数将公开结构体转换为内部运行时结构体WSLCCompatTagImageOptions,再委托给会话对象的TagImage方法执行实际标记操作,最后通过errorInfoWrapper.CaptureResult把底层错误连同可读消息一并返回给调用方。所有 C 层异常都会由CATCH_RETURN()统一转换为HRESULT,避免 C++ 异常泄漏到 C 调用边界。

测试用例佐证

上述错误码行为与 WslcSdkTests.cpp 中的TagImage测试方法完全一致:

WSLC_TEST_METHOD(TagImage) { // Positive: tag an existing image. { WslcTagImageOptions opts{}; opts.image = "debian:latest"; opts.repo = "debian"; opts.tag = "sdk-test-tag"; VERIFY_SUCCEEDED(WslcTagSessionImage(m_defaultSession, &opts, nullptr)); // Verify the tag is present. VERIFY_IS_TRUE(HasImage("debian:sdk-test-tag")); // Cleanup: delete the tag. WslcDeleteSessionImage(m_defaultSession, "debian:sdk-test-tag", nullptr); } // Negative: null options must fail. VERIFY_ARE_EQUAL(WslcTagSessionImage(m_defaultSession, nullptr, nullptr), E_POINTER); // Negative: null fields must fail. { WslcTagImageOptions opts{}; opts.image = nullptr; opts.repo = "debian"; opts.tag = "test"; VERIFY_ARE_EQUAL(WslcTagSessionImage(m_defaultSession, &opts, nullptr), E_INVALIDARG); } // ... repo / tag 为 NULL 的用例同理 }

测试验证了三个关键事实:

  1. 标记成功后,新标签立即在镜像列表中可见(HasImage("debian:sdk-test-tag")为真);
  2. options为NULL返回E_POINTER;
  3. image、repo、tag任一字段为NULL均返回E_INVALIDARG。

典型实战场景:标记后推送镜像

WslcTagSessionImage最常见的用途是配合本地注册表完成"拉取 → 标记 → 推送"。在 WslcSdkTests.cpp 的PushImageToRegistry辅助方法中可以看到完整模式:

// Tags and pushes an image to a local registry via the SDK APIs. void PushImageToRegistry(const std::string& repo, const std::string& tag, const std::string& registryAddress, const std::string& registryAuth) { auto imageName = std::format("{}:{}", repo, tag); auto registryImage = std::format("{}/{}:{}", registryAddress, repo, tag); auto registryRepo = std::format("{}/{}", registryAddress, repo); VERIFY_IS_TRUE(HasImage(imageName)); // Tag the image with the registry address so it can be pushed. WslcTagImageOptions tagOptions{}; tagOptions.image = imageName.c_str(); tagOptions.repo = registryRepo.c_str(); tagOptions.tag = tag.c_str(); VERIFY_SUCCEEDED(WslcTagSessionImage(m_defaultSession, &tagOptions, nullptr)); // Ensures the registry-prefixed tag is removed after the push. auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { LOG_IF_FAILED(WslcDeleteSessionImage(m_defaultSession, registryImage.c_str(), nullptr)); }); WslcPushImageOptions pushOptions{}; pushOptions.image = registryImage.c_str(); pushOptions.registryAuth = registryAuth.c_str(); VERIFY_SUCCEEDED(WslcPushSessionImage(m_defaultSession, &pushOptions, nullptr)); }

这里的关键点:

  • 本地镜像名为repo:tag(如debian:latest),要推送到注册表,必须先用WslcTagSessionImage生成带注册表地址的镜像名localhost:5000/debian:latest(即registryRepo = registryAddress/repo),否则推送 API 无法定位远端仓库;
  • 推送完成后立即用WslcDeleteSessionImage删除注册表前缀标签,保持本地镜像库干净;
  • WslcPushSessionImage需要registryAuth字段提供注册表认证信息(如 Docker 的 Base64 认证串),参见 wslcpushsessionimage.md。

底层调用链:从 C API 到 WinRT 封装

WslcTagSessionImage并不直接操作镜像存储,而是将工作委托给会话对象的TagImage方法。该 API 同时被 WinRT 层复用:在 Session.cpp 中,WinRT 的Session::TagImage方法在完成空指针检查与EnsureStarted()(确保会话已启动)后,直接调用 C 层WslcTagSessionImage:

void Session::TagImage(winrt::Microsoft::WSL::Containers::TagImageOptions const& options) { if (!options) { throw winrt::hresult_error(E_POINTER, L"Tag image options cannot be null"); } EnsureStarted(); wil::unique_cotaskmem_string errorMessage; auto hr = WslcTagSessionImage(ToHandle(), GetStructPointer(options), errorMessage.put()); THROW_MSG_IF_FAILED(hr, errorMessage); }

由此可以推断出完整的调用链:

WslcTagSessionImage (C API) └─> session->TagImage(&runtimeOptions) // C++ 内部实现 └─> WinRT Session::TagImage // WinRT 封装(可选路径) └─> WslcTagSessionImage // 复用同一 C 入口

该函数通过 wslcsdk.def 导出,是 wslcsdk.dll 对外公开的稳定 ABI 接口之一;同时它也作为 WinRTMicrosoft.WSL.Containers命名空间的底层实现存在(选项结构体的 WinRT 版本见 TagImageOptions.cpp)。也就是说,无论是纯 C 调用方还是 WinRT/C# 调用方,最终都收敛到同一个标记实现,行为完全一致。

常见问题与最佳实践

  1. 忘记初始化结构体:务必用{ 0 }初始化WslcTagImageOptions,否则未赋值的字段可能包含垃圾值,导致校验行为不可预期。
  2. 标签命名:标签应遵循 OCI/Docker 标签规范(字母、数字、_、.、-,且以字母或数字开头结尾),虽然 SDK 本身依赖底层运行时校验,但提前遵循规范可以避免推送阶段失败。
  3. 标记后验证:调用WslcListSessionImages确认新标签出现在镜像列表中,测试代码中的HasImage即为此模式。
  4. 释放错误信息:当errorMessage输出非空时,使用CoTaskMemFree释放;这也是 WslcListSessionImages 等 API 的共同约定。
  5. 会话生命周期:标记操作必须在会话存活期间执行;会话终止后句柄失效,再次调用会得到ERROR_INVALID_STATE。
  6. C 调用方需初始化 COM:与 SDK 中其他 API 一致,使用前应调用CoInitializeEx,结束时CoUninitialize(参见 end-to-end-example.md)。

相关 API 一览

WslcTagSessionImage属于图像管理 API 家族,完整的成员列表见 image-apis/index.md:

API功能
WslcPullSessionImage从注册表拉取镜像到会话
WslcImportSessionImage/WslcImportSessionImageFromFile导入镜像(含从文件导入)
WslcLoadSessionImage/WslcLoadSessionImageFromFile加载镜像(含从文件加载)
WslcListSessionImages列出会话中的镜像
WslcTagSessionImage为镜像创建新标签(本文主题)
WslcDeleteSessionImage删除镜像或某个标签
WslcPushSessionImage推送镜像到注册表

这些 API 共用一个WslcSession会话句柄(句柄类型见 handle-types.md),构成了 WSL 容器镜像从拉取、标记、推送到清理的完整闭环。结合 end-to-end-example.md 与 WslcSdkTests.cpp 中的测试代码,你可以在自己的 C/C++ 项目中安全地复刻这一工作流。

【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询