☰
WSL 容器 C API 镜像导入实战:WslcImportSessionImageFromFile 从文件导入镜像完整指南
2026/10/13 2:54:12 网站建设 项目流程

WSL 容器 C API 镜像导入实战:WslcImportSessionImageFromFile 从文件导入镜像完整指南

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

导读

WslcImportSessionImageFromFile是 WSL 容器 C API(Wslc SDK)中用于将本地 tar 格式容器镜像直接导入到 WSL 会话的核心接口。本文基于该 API 的官方参考文档,结合仓库源码(SDK 封装层、服务端实现与 Docker HTTP 客户端)与测试用例,系统讲解其函数签名、参数语义、调用示例、底层工作原理与错误处理,帮助开发者把离线分发的镜像文件快速变为 WSL 会话中可运行的容器镜像。


1. API 概览:函数签名与定位

WslcImportSessionImageFromFile属于 WSL 容器 C API 中 Image APIs 家族,其作用是将位于 Windows 文件系统上的镜像归档文件(tar 格式)导入到指定的WslcSession会话中,使其成为会话内可被容器引用的镜像。

完整的函数声明如下(见 关联文档):

STDAPI WslcImportSessionImageFromFile( _In_ WslcSession session, _In_z_ PCSTR imageName, _In_z_ PCWSTR path, _In_opt_ const WslcImportImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);

参数说明

参数类型方向说明
sessionWslcSessionin目标会话句柄,由WslcCreateSession创建
imageNamePCSTRin导入后镜像的引用名称,格式为repository:tag(UTF-8/ANSI 字符串)
pathPCWSTRin指向本地镜像 tar 文件的宽字符路径,如L"C:\\images\\demo-import.tar"
optionsconst WslcImportImageOptions*in, optional可选导入选项,可传NULL或指向WslcImportImageOptions的指针
errorMessagePWSTR*out, optional出错时返回的宽字符错误信息指针,由CoTaskMemFree释放;可传NULL

返回值:HRESULT,S_OK表示成功,失败时可通过errorMessage获取人类可读的错误描述。

头文件与链接库:该 API 声明于src/windows/WslcSDK/wslcsdk.h,导出符号位于src/windows/WslcSDK/wslcsdk.def,链接时使用wslcsdk.lib(运行时对应wslcsdk.dll)。更多背景可参阅 WSL container API C reference 总览。

PREVIEW 提示:根据 API 参考索引 的声明,该 API 目前处于preview 阶段,未来版本可能发生破坏性变更(函数签名、行为等),预览期内不要依赖其 API 稳定性承载生产负载。


2. 可选的导入选项:WslcImportImageOptions

options参数指向 WslcImportImageOptions 结构体,用于在导入过程中接收进度回调:

typedef struct WslcImportImageOptions { _In_opt_ WslcContainerImageProgressCallback progressCallback; _In_opt_ PVOID progressCallbackContext; } WslcImportImageOptions;
字段类型说明
progressCallbackWslcContainerImageProgressCallback镜像导入进度回调函数指针,可选
progressCallbackContextPVOID透传给回调的上下文指针,可选

如果不需要进度通知,可以传NULL或零初始化一个结构体:

WslcImportImageOptions importOptions = { 0 };

在 SDK 实现中(wslcsdk.cpp),ProgressCallback::CreateIf(options)会在options非空时包装回调,将导入进度转发给调用方。


3. 最小可运行示例

官方文档给出的调用示例如下:

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

调用成功后,demo/imported:latest即成为当前会话内可用的镜像,随后可通过WslcCreateContainer以该镜像名创建容器。注意imageName必须包含 tag(如:latest),否则服务端会拒绝导入(详见第 5 节)。


4. 从文件导入与从句柄导入:两种入口的对比

Image APIs 家族提供了两种导入镜像的入口,WslcImportSessionImageFromFile是其中面向"路径"的便捷变体:

能力WslcImportSessionImageFromFileWslcImportSessionImage
输入方式镜像 tar 的宽字符文件路径PCWSTR path已打开文件的HANDLE+ 字节长度uint64_t
文件打开SDK 内部完成调用方自行CreateFileW/GetFileSizeEx并管理句柄生命周期
典型场景直接导入磁盘上的镜像归档从管道、内存映射等非路径来源流式导入

二者的底层都汇聚到同一个内部实现WslcImportSessionImageImpl(见 wslcsdk.cpp),区别仅在于输入来源的归一化方式。

内部实现:ImageFileResolver 归一化输入

从源码结构看,SDK 定义了一个ImageFileResolver辅助类型(wslcsdk.cpp),它的职责是把"路径"或"句柄+长度"两种输入统一归一化为HANDLE + 长度:

  • 传入PCWSTR path时,内部调用:
CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)

以只读共享方式打开文件,并通过GetFileSizeEx获取文件大小(ULONGLONG),随后句柄由HandleWrapper管理、自动释放;

  • 传入HANDLE + uint64_t时,会校验句柄有效且长度非零(E_INVALIDARG)。

这解释了文档中WslcImportSessionImageFromFile为何不需要调用方自行打开文件:文件打开、大小探测与句柄生命周期管理均由 SDK 内部完成,调用方只需保证路径下存在可读的 tar 文件。

服务端调用链

归一化后的HANDLE + 长度会一路传递到服务端会话层。完整调用链为:

WslcImportSessionImageFromFile → WslcImportSessionImageImpl (src/windows/WslcSDK/wslcsdk.cpp) → Session::ImportImage (WinRT 会话封装层) → WSLCSession::ImportImage (src/windows/wslcsession/WSLCSession.cpp#L1560) → DockerHTTPClient::ImportImage (src/windows/wslcsession/DockerHTTPClient.cpp#L161) → HTTP POST /images/create?tag=...&repo=...&fromSrc=-

其中 WinRT 封装层(Session.cpp)会先校验path与imageName非空(为空抛出hresult_invalid_argument),确认会话已启动(EnsureStarted)后调用 C 导出函数。


5. 镜像命名与 tag 约束

WslcImportSessionImageFromFile对imageName有严格的格式要求,这一点由服务端强制校验。在 WSLCSession::ImportImage 中可以看到:

  1. 若ImageName非空,其长度不得超过WSLC_MAX_IMAGE_NAME_LENGTH,否则返回E_INVALIDARG;
  2. 通过wslutil::ImageReference::Parse(ImageName)解析名称;
  3. 必须包含 tag(或 digest),否则抛出E_INVALIDARG,错误信息为"Expected tag for image import"。

因此形如"demo/imported:latest"的写法是正确的;若只传"demo/imported"(无 tag),导入会被拒绝。

服务端随后从解析结果中拆出repo与tag,构造 Docker 导入请求(见 DockerHTTPClient.cpp):

auto url = URL::Create("/images/create"); url.SetParameter("tag", Tag); url.SetParameter("repo", Repo); url.SetParameter("fromSrc", "-"); // POST,Content-Type: application/x-tar,Content-Length: ContentLength

这与"加载镜像"(LoadImage走/images/load)走的是不同的 Docker Engine 端点:import 对应/images/create?fromSrc=-(从标准输入构建镜像),load 对应/images/load(加载 tar 归档)。从源码可以推断,import 与 load 在 Docker Engine 层面的语义不同:import 会按repo:tag建立新的镜像引用,而 load 直接恢复归档中的镜像集合。


6. 错误处理与错误码约定

HRESULT 与 errorMessage

所有 Wslc SDK API 统一采用HRESULT返回值,失败时可通过errorMessage(PWSTR*)获取详细错误文本。SDK 内部通过ErrorInfoWrapper捕获错误并格式化(见 wslcsdk.cpp):

PWSTR error = nullptr; HRESULT hr = WslcImportSessionImageFromFile(session, "demo/imported:latest", L"C:\\images\\demo-import.tar", NULL, &error); if (FAILED(hr)) { if (error) { wprintf(L"Import failed: %s\n", error); CoTaskMemFree(error); // 错误信息由调用方释放 } }

常见的 HRESULT 失败分支

结合 SDK 实现与测试用例(WslcSdkTests.cpp),可归纳以下典型失败场景:

场景返回 HRESULT
imageName为NULLE_POINTER
path为NULLE_POINTER
镜像名长度超限 / 缺少 tagE_INVALIDARG
传入内容长度为 0(句柄入口)E_INVALIDARG
会话无效(session内部状态异常)HRESULT_FROM_WIN32(ERROR_INVALID_STATE)
服务端 Docker 运行时不可用HRESULT_FROM_WIN32(ERROR_INVALID_STATE)(见 WSLCSession.cpp)
Docker Engine 返回非 200 响应解析 JSON 错误体并抛出异常(E_UNEXPECTED等)

另外,镜像操作相关的语义错误码定义在 Error Codes 中,如WSLC_E_IMAGE_NOT_FOUND(0x80040601)。若要删除、枚举或重打标签,可配合WslcDeleteSessionImage、WslcListSessionImages、WslcTagSessionImage使用。


7. 与其他 Image API 的协同

WslcImportSessionImageFromFile只是镜像生命周期管理的一环。完整的 Image APIs 家族包括:

  • 导入:WslcImportSessionImage(句柄+长度)、WslcImportSessionImageFromFile(路径)
  • 加载:WslcLoadSessionImage、WslcLoadSessionImageFromFile
  • 拉取/推送:WslcPullSessionImage、WslcPushSessionImage
  • 管理:WslcListSessionImages、WslcDeleteSessionImage、WslcTagSessionImage

典型离线分发场景:在构建机上导出 tar → 拷贝到目标 Windows 机器 →WslcImportSessionImageFromFile导入 →WslcListSessionImages确认 →WslcCreateContainer创建容器运行。测试代码正是这样验证的:导入导出的 tar 后直接运行容器并断言输出(见 WslcSdkTests.cpp,输出包含"Hello from Docker!")。


8. 测试用例佐证:正反路径全覆盖

仓库测试对WslcImportSessionImageFromFile的验证相当完整(WslcSdkTests.cpp):

  • 正向:用HelloWorldExported.tar测试数据,先走句柄入口导入my-hello-world-handle:test,再走路径入口导入my-hello-world-path:test,均能成功运行容器并捕获预期输出;
  • 负向:imageName = NULL与path = NULL均断言返回E_POINTER;零长度内容断言返回E_INVALIDARG;
  • WinRT 层测试(WslcSdkWinRTTests.cpp)验证空路径/空镜像名抛出E_INVALIDARG,对非 tar 文件导入失败。

此外,服务端测试 WSLCTests.cpp 覆盖了无 tag 导入失败、超大文件、输入管道提前关闭(EOF)以及会话终止时导入被中止等边界情况,可作为编写健壮调用代码时的参考。


9. 完整生命周期示例

将导入操作嵌入完整会话生命周期(参考 End-to-End Example),可以得到一个可运行的骨架:

#include <windows.h> #include <objbase.h> #include <stdio.h> #include "wslcsdk.h" #pragma comment(lib, "ole32.lib") #pragma comment(lib, "wslcsdk.lib") int main() { CoInitializeEx(nullptr, COINIT_MULTITHREADED); // 1. 检查平台组件 WslcComponentFlags missing = WSLC_COMPONENT_FLAG_NONE; if (FAILED(WslcGetMissingComponents(&missing)) || missing != WSLC_COMPONENT_FLAG_NONE) { printf("WSL components are missing. Run: wsl --install\n"); CoUninitialize(); return 1; } // 2. 创建会话 WslcSessionSettings sessionSettings; WslcInitSessionSettings(L"ImportDemo", L"C:\\wslc-storage", &sessionSettings); WslcSetSessionSettingsCpuCount(&sessionSettings, 4); WslcSetSessionSettingsMemory(&sessionSettings, 4096); PWSTR error = nullptr; WslcSession session = nullptr; HRESULT hr = WslcCreateSession(&sessionSettings, &session, &error); if (FAILED(hr)) { wprintf(L"Session creation failed: %s\n", error ? error : L"unknown"); CoTaskMemFree(error); CoUninitialize(); return 1; } // 3. 从文件导入镜像 hr = WslcImportSessionImageFromFile( session, "demo/imported:latest", L"C:\\images\\demo-import.tar", NULL, &error); if (FAILED(hr)) { wprintf(L"Import failed: %s\n", error ? error : L"unknown"); CoTaskMemFree(error); WslcTerminateSession(session); WslcReleaseSession(session); CoUninitialize(); return 1; } printf("Image imported successfully.\n"); // 4. 基于导入的镜像创建并启动容器(略,参考 end-to-end-example) // WslcContainerSettings settings; WslcInitContainerSettings("demo/imported:latest", &settings); ... // 5. 清理 WslcTerminateSession(session); WslcReleaseSession(session); CoUninitialize(); return 0; }

注意:示例中的WslcCreateSession、WslcInitSessionSettings等接口的完整用法可参考 End-to-End Example;CoTaskMemFree用于释放errorMessage返回的错误文本。


10. 使用建议与注意事项

  1. 务必携带 tag:imageName必须形如repo:tag,无 tag 会导入失败(服务端强制校验);
  2. 路径使用宽字符:path是PCWSTR,Windows 路径建议使用L"..."前缀并转义反斜杠(如L"C:\\images\\demo-import.tar");
  3. 进度回调可选:需要导入进度时传入WslcImportImageOptions并设置progressCallback;不需要时传NULL即可;
  4. 错误信息生命周期:errorMessage输出的字符串由调用方负责CoTaskMemFree,每次调用后应及时释放;
  5. 预览 API 风险:当前 API 处于 preview 阶段,签名与行为可能随版本变化,正式对接前请核对所绑定 SDK 版本(WslcGetVersion可查询版本,见 End-to-End Example);
  6. 依赖 Docker 运行时:导入最终由会话内置的 Docker Engine 处理(/images/create),若运行时不可用,调用会以ERROR_INVALID_STATE失败,调用前可先确认环境满足前置条件。

通过上述内容,开发者可以完整掌握WslcImportSessionImageFromFile的用法、底层实现与边界行为,并将其安全地集成到基于 WSL 容器的镜像管理与离线分发工作流中。

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

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

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

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

立即咨询