
WSL 容器 C API 详解WslcImportImageOptions 结构体与自定义容器镜像导入的进度回调配置【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL本篇技术指南聚焦 Windows Subsystem for Linux 容器 SDKWSLc SDK中用于镜像导入配置的WslcImportImageOptions结构体讲解其字段语义、与WslcImportSessionImage/WslcImportSessionImageFromFile两个导入 API 的配合用法并结合仓库源码wslcsdk.cpp、Session.cpp、WslcSdkTests.cpp深入其底层实现与测试验证。读完本文你将掌握如何在自定义容器镜像导入场景中挂接进度回调、解读进度消息并避开常见的参数校验陷阱。一、结构体定位镜像导入操作的可选配置WslcImportImageOptions是 WSL 容器 C API 中定义镜像导入行为的一个可选配置结构体位于 API 参考的 structures 目录 下。它的唯一职责是为导入操作挂接一个进度回调让调用方宿主机进程在导入容器镜像期间实时感知底层执行状态——例如当前处理到哪个 layer、已经传输了多少字节。该结构体本身并不定义镜像来源或目标名称这些由调用它的导入函数参数提供它只负责如何报告进度。在 wslcimportsessionimage.md 与 wslcimportsessionimagefromfile.md 中该结构体以_In_opt_方式作为第三个/第四个参数传入允许传NULL表示不关心进度。二、结构体定义与字段说明原文档给出完整声明如下typedef struct WslcImportImageOptions { _In_opt_ WslcContainerImageProgressCallback progressCallback; _In_opt_ PVOID progressCallbackContext; } WslcImportImageOptions;字段类型说明progressCallbackWslcContainerImageProgressCallback导入过程中的进度回调函数指针可为NULLprogressCallbackContextPVOID透传给回调函数的调用方上下文指针可为NULL两个字段均以_In_opt_标注即全部可选不关心进度时可直接将该结构体整体初始化为零{ 0 }传入甚至直接传NULL指针给导入函数。两个字段成对使用——回调函数负责做什么上下文指针负责你是谁的数据例如指向某个进度条对象或日志器回调触发时原样回传避免使用全局变量。同族结构体对比从 structures 目录 可以看到SDK 为每个镜像操作都定义了平行结构体WslcPullImageOptions、WslcPushImageOptions、WslcLoadImageOptions、WslcTagImageOptions、WslcImportImageOptions等。它们的共同模式是携带progressCallback/progressCallbackContext两个字段区别仅在各自操作特有的参数如WslcPullImageOptions的uri、registryAuth印证了该 SDK 统一采用操作函数 选项结构体 可选进度回调的 API 设计范式。三、回调类型与进度消息结构progressCallback的类型WslcContainerImageProgressCallback定义于 wslccontainerimageprogresscallback.mdtypedef HRESULT(CALLBACK* WslcContainerImageProgressCallback)(const WslcImageProgressMessage* progress, PVOID context);回调接收两个参数当前进度消息WslcImageProgressMessage以及构造结构体时传入的progressCallbackContext。回调返回HRESULT——注意这一设计意味着调用方可以通过返回失败码向上传递取消或错误信号。进度消息本身是一个三层嵌套结构相关定义同样位于 structures 目录WslcImageProgressMessage见 wslcimageprogressmessage.md由idlayer ID 或 digest、statusWslcImageProgressStatus枚举、detailWslcImageProgressDetail三部分组成WslcImageProgressDetail见 wslcimageprogressdetail.mdcurrentBytes表示已传输/处理字节数totalBytes表示总字节数可用于计算百分比进度WslcImageProgressStatus见 wslcimageprogressstatus.md描述镜像处理所处阶段枚举值数值语义WSLC_IMAGE_PROGRESS_STATUS_UNKNOWN0未知状态WSLC_IMAGE_PROGRESS_STATUS_PULLING1Pulling fs layer拉取文件系统层WSLC_IMAGE_PROGRESS_STATUS_WAITING2Waiting排队等待WSLC_IMAGE_PROGRESS_STATUS_DOWNLOADING3Downloading下载中WSLC_IMAGE_PROGRESS_STATUS_VERIFYING4Verifying Checksum校验和验证WSLC_IMAGE_PROGRESS_STATUS_EXTRACTING5Extracting解压中WSLC_IMAGE_PROGRESS_STATUS_COMPLETE6Pull complete完成这些状态与 Docker 生态的镜像层拉取阶段一一对应说明 WSL 容器的镜像导入内部沿用了 OCI 镜像层的处理管线。虽然导入Import不涉及网络拉取但 SDK 复用了同一套进度模型因此回调中仍可能出现EXTRACTING、COMPLETE等阶段。四、实战在导入 API 中挂接进度回调WslcImportImageOptions只有与导入函数搭配才有意义。SDK 提供两个导入入口均接受该结构体作为可选参数。4.1 WslcImportSessionImage从 HANDLE 导入该函数从调用方持有的句柄导入镜像内容签名见 wslcimportsessionimage.mdSTDAPI 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);原文档示例完整复现如下imageContent为文件句柄同时显式传入文件大小HANDLE imageContent CreateFileW( LC:\\images\\demo-import.tar, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); LARGE_INTEGER size { 0 }; GetFileSizeEx(imageContent, size); WslcImportImageOptions importOptions { 0 }; HRESULT hr WslcImportSessionImage( session, demo/imported:latest, imageContent, (uint64_t)size.QuadPart, importOptions, NULL); CloseHandle(imageContent);重要提示原文档特别强调头文件中将imageContent声明为HANDLE而非void*调用方必须传入真实的内核句柄如CreateFileW返回值且句柄需处于可读状态imageContentBytes必须与句柄对应内容的实际大小一致。4.2 WslcImportSessionImageFromFile从文件路径导入更简单的形式是直接传路径由 SDK 内部打开文件见 wslcimportsessionimagefromfile.mdSTDAPI WslcImportSessionImageFromFile( _In_ WslcSession session, _In_z_ PCSTR imageName, _In_z_ PCWSTR path, _In_opt_ const WslcImportImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);WslcImportImageOptions importOptions { 0 }; HRESULT hr WslcImportSessionImageFromFile( session, demo/imported:latest, LC:\\images\\demo-import.tar, importOptions, NULL);注意两个函数的镜像名参数都是PCSTRUTF-8/ANSI 字符串而文件路径是PCWSTR宽字符串。4.3 挂接回调的完整写法在上述任一调用中只需为importOptions的两个字段赋值即可实时接收进度static HRESULT CALLBACK OnImportProgress(const WslcImageProgressMessage* progress, PVOID context) { // context 可以是自定义结构体指针例如指向控制台进度条或日志上下文 auto* ctx static_castMyProgressContext*(context); if (progress-status WSLC_IMAGE_PROGRESS_STATUS_DOWNLOADING || progress-status WSLC_IMAGE_PROGRESS_STATUS_EXTRACTING) { double percent progress-detail.totalBytes 0 ? (double)progress-detail.currentBytes / progress-detail.totalBytes * 100.0 : 0.0; ctx-Report(progress-id, progress-status, percent); } return S_OK; } WslcImportImageOptions importOptions { 0 }; importOptions.progressCallback OnImportProgress; importOptions.progressCallbackContext myContext; HRESULT hr WslcImportSessionImageFromFile( session, demo/imported:latest, LC:\\images\\demo-import.tar, importOptions, nullptr);若回调返回非成功HRESULT可以推断 SDK 内部会据此中断或上报错误THROW_MSG_IF_FAILED模式见下文源码分析。五、源码级原理回调如何被消费5.1 SDK 公共导出层参数校验与分发在 src/windows/WslcSDK/wslcsdk.cpp 中WslcImportSessionImage的实现清晰展示了参数校验逻辑STDAPI WslcImportSessionImage( _In_ WslcSession session, _In_z_ PCSTR imageName, _In_ HANDLE imageContent, _In_ uint64_t imageContentLength, _In_opt_ const WslcImportImageOptions* 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); THROW_HR_IF_NULL(E_POINTER, imageName); return WslcImportSessionImageImpl(internalType, imageName, options, errorInfoWrapper, {imageContent, imageContentLength}); } CATCH_RETURN();关键点session必须是有效的已认证会话imageName不允许为NULL返回E_POINTER句柄与长度被包装成结构传入内部实现WslcImportSessionImageImpl。options可为NULL内部实现ProgressCallback.h的CreateIf会对空选项做保护性判断。5.2 进度回调的桥接ProgressCallback 模板src/windows/WslcSDK/ProgressCallback.h 揭示了选项结构体与底层回调通道的桥接逻辑template typename Options static winrt::com_ptrProgressCallback CreateIf(const Options* options) { if (options options-progressCallback) { return winrt::make_selfProgressCallback(options-progressCallback, options-progressCallbackContext); } else { // 未提供回调时返回空实现 } }也就是说只有当options非空且progressCallback字段有效时SDK 才会创建桥接对象否则走无进度路径。progressCallbackContext被原样存入桥接对象在每次回调触发时回传给用户函数。5.3 WinRT 层从 C API 到异步进度在 WinRT 封装层 src/windows/WslcSDK/winrt/Session.cpp 中C#/WinRT 调用方通过IAsyncActionWithProgress获得进度其内部正是把 WinRT 的进度 token 桥接为 C 结构体回调auto context ProgressCallbackHelper...{co_await winrt::get_progress_token()}; WslcImportImageOptions importOptions{}; importOptions.progressCallback ImageProgressCallback; importOptions.progressCallbackContext context; wil::unique_cotaskmem_string errorMessage; auto hr WslcImportSessionImageFromFile(ToHandle(), name.c_str(), path.c_str(), importOptions, errorMessage.put()); THROW_MSG_IF_FAILED(hr, errorMessage);注意这里WslcImportImageOptions直接以{}值初始化后仅覆盖两个回调字段其余保持零值——再次印证该结构体只需关心回调配置没有其他必填字段。THROW_MSG_IF_FAILED会把errorMessage中的错误描述附加到异常中抛出这就是errorMessage输出参数的消费方式。六、测试验证参数边界与负向用例仓库测试 test/windows/WslcSdkTests.cpp 的WSLC_TEST_METHOD(ImportImage)同时覆盖正向与负向路径可作为结构体用法的权威参照// 正向从 HANDLE 导入 VERIFY_SUCCEEDED(WslcImportSessionImage( m_defaultSession, c_handleImportedImageName, imageTarFileHandle.get(), static_castuint64_t(fileSize.QuadPart), nullptr, nullptr)); // 正向从文件路径导入 VERIFY_SUCCEEDED(WslcImportSessionImageFromFile(m_defaultSession, c_pathImportedImageName, exportedImageTar.c_str(), nullptr, nullptr)); // 构造显式选项结构体含进度回调字段参与负向测试 WslcImportImageOptions opts{}; // 负向镜像名为 NULL 必须失败 VERIFY_ARE_EQUAL(WslcImportSessionImageFromFile(m_defaultSession, nullptr, exportedImageTar.c_str(), opts, nullptr), E_POINTER); // 负向文件路径为 NULL 必须失败 VERIFY_ARE_EQUAL(WslcImportSessionImageFromFile(m_defaultSession, missing-file-input:test, nullptr, opts, nullptr), E_POINTER); // 负向内容长度为 0 必须失败 VERIFY_ARE_EQUAL(WslcImportSessionImage(m_defaultSession, zero-length:test, GetCurrentThreadEffectiveToken(), 0, opts, nullptr), E_INVALIDARG);同文件还有WSLC_TEST_METHOD(ImportImageNonTar)非 tar 文件导入的负向用例。这些测试确认了以下可验证的事实约束WslcImportSessionImage与WslcImportSessionImageFromFile均接受nullptr作为 options无进度回调场景镜像名、文件路径为空时返回E_POINTERimageContentBytes为 0 时返回E_INVALIDARG选项结构体本身以{}或{ 0 }初始化即可安全使用。七、使用建议与注意事项结构体可整体置零不关心进度时WslcImportImageOptions opts { 0 };或直接传NULL均可两个字段都标了_In_opt_。回调必须成对设置要接收进度必须同时设置progressCallback与progressCallbackContext仅设其一则回调永远不会被触发见 ProgressCallback.h 的CreateIf逻辑。上下文指针生命周期progressCallbackContext是裸指针透传SDK 不负责管理其生命周期调用方必须保证其在导入操作完成前有效。进度数据单位currentBytes/totalBytes为uint64_t计算百分比前先判totalBytes 0避免除零。句柄导入注意HANDLE语义WslcImportSessionImage的imageContent是真实句柄而非void*且长度参数必须与实际内容一致否则触发E_INVALIDARG。导入内容格式测试表明镜像内容应为 tar 归档HelloWorldExported.tar非 tar 输入会走失败路径详见ImportImageNonTar测试。八、延伸阅读镜像操作族 APIimage-apis 目录WslcPullSessionImage、WslcPushSessionImage、WslcLoadSessionImage、WslcDeleteSessionImage等均接受同族选项结构体回调类型wslccontainerimageprogresscallback.md进度消息结构wslcimageprogressmessage.md、wslcimageprogressdetail.md状态枚举wslcimageprogressstatus.mdC API 端到端示例end-to-end-example.mdC# 示例使用 WinRT 封装的异步进度WSLC-HelloWorld【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考