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);参数说明
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
session | WslcSession | in | 目标会话句柄,由WslcCreateSession创建 |
imageName | PCSTR | in | 导入后镜像的引用名称,格式为repository:tag(UTF-8/ANSI 字符串) |
path | PCWSTR | in | 指向本地镜像 tar 文件的宽字符路径,如L"C:\\images\\demo-import.tar" |
options | const WslcImportImageOptions* | in, optional | 可选导入选项,可传NULL或指向WslcImportImageOptions的指针 |
errorMessage | PWSTR* | 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;| 字段 | 类型 | 说明 |
|---|---|---|
progressCallback | WslcContainerImageProgressCallback | 镜像导入进度回调函数指针,可选 |
progressCallbackContext | PVOID | 透传给回调的上下文指针,可选 |
如果不需要进度通知,可以传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是其中面向"路径"的便捷变体:
| 能力 | WslcImportSessionImageFromFile | WslcImportSessionImage |
|---|---|---|
| 输入方式 | 镜像 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 中可以看到:
- 若
ImageName非空,其长度不得超过WSLC_MAX_IMAGE_NAME_LENGTH,否则返回E_INVALIDARG; - 通过
wslutil::ImageReference::Parse(ImageName)解析名称; - 必须包含 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为NULL | E_POINTER |
path为NULL | E_POINTER |
| 镜像名长度超限 / 缺少 tag | E_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. 使用建议与注意事项
- 务必携带 tag:
imageName必须形如repo:tag,无 tag 会导入失败(服务端强制校验); - 路径使用宽字符:
path是PCWSTR,Windows 路径建议使用L"..."前缀并转义反斜杠(如L"C:\\images\\demo-import.tar"); - 进度回调可选:需要导入进度时传入
WslcImportImageOptions并设置progressCallback;不需要时传NULL即可; - 错误信息生命周期:
errorMessage输出的字符串由调用方负责CoTaskMemFree,每次调用后应及时释放; - 预览 API 风险:当前 API 处于 preview 阶段,签名与行为可能随版本变化,正式对接前请核对所绑定 SDK 版本(
WslcGetVersion可查询版本,见 End-to-End Example); - 依赖 Docker 运行时:导入最终由会话内置的 Docker Engine 处理(
/images/create),若运行时不可用,调用会以ERROR_INVALID_STATE失败,调用前可先确认环境满足前置条件。
通过上述内容,开发者可以完整掌握WslcImportSessionImageFromFile的用法、底层实现与边界行为,并将其安全地集成到基于 WSL 容器的镜像管理与离线分发工作流中。
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考