WSL 容器 API 的 Session APIs 全面指南:用 Wslc 系列函数管理容器会话生命周期
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
本指南以 WSL 容器 API(WSL Container API)C 语言参考中的 Session APIs 为绝对核心,完整讲解从会话初始化、资源配额设置、会话创建、终止监听、崩溃转储订阅到会话清理的全部 14 个 API 函数。你将掌握如何在 Windows 上以编程方式创建、配置、监控和销毁一个容器会话,并深入理解WslcSessionSettings不透明结构的内部布局与wslcsdk实现层的默认值行为。文章末尾还给出可编译运行的完整生命周期示例,帮你把每个 API 串成一条可落地的调用链。
适用前提:本 API 属于 Windows Subsystem for Linux(WSL)的容器 SDK,当前处于Preview 阶段(见 C API 参考入口),函数签名与行为可能在后续版本中无通知变更,请勿在正式生产负载中依赖其稳定性。编译时需要
wslcsdk.h头文件与wslcsdk.lib/wslcsdk.dll库(头文件声明见 wslcsdk.h,导出符号见 wslcsdk.def)。
一、Session APIs 全貌:14 个函数的职责分组
会话(Session)是 WSL 容器 API 中最顶层的资源抽象:一个会话对应一台面向 Linux 容器负载的虚拟机运行环境,容器(Container)创建在会话之内,进程(Process)又运行在容器之内。Session APIs 负责回答"如何把这样一台虚拟机拉起来、配好资源、监视其存亡、最后干净地关掉"。
Session APIs 索引 将全部 14 个函数分为五类:
| 类别 | 函数 | 职责 |
|---|---|---|
| 会话设置初始化 | WslcInitSessionSettings | 创建并填充WslcSessionSettings结构(必调,第一步) |
| 会话设置微调 | WslcSetSessionSettingsCpuCount | 设置 CPU 核数 |
WslcSetSessionSettingsMemory | 设置内存上限(MB) | |
WslcSetSessionSettingsTimeout | 设置引导超时(毫秒) | |
WslcSetSessionSettingsVhd | 设置 VHD 存储需求 | |
WslcSetSessionSettingsFeatureFlags | 设置会话特性开关(如 GPU) | |
| 会话生命周期 | WslcCreateSession | 基于设置创建会话,返回WslcSession句柄 |
WslcTerminateSession | 终止会话 | |
WslcReleaseSession | 释放会话句柄 | |
| 会话状态监控 | WslcGetSessionTerminationEvent | 获取会话终止事件句柄(HANDLE) |
WslcGetSessionTerminationReason | 查询终止原因 | |
| 崩溃转储订阅 | WslcRegisterSessionCrashDumpCallback | 注册崩溃转储回调 |
WslcReleaseCrashDumpSubscription | 取消崩溃转储订阅 | |
| 会话内认证 | WslcSessionAuthenticate | 向会话内服务完成身份认证,获取身份令牌 |
典型调用顺序:WslcInitSessionSettings→(可选)各WslcSetSessionSettings*→WslcCreateSession→ 使用会话创建容器/拉取镜像 → 监控终止事件 →WslcTerminateSession→WslcReleaseSession。
二、会话设置初始化:WslcInitSessionSettings
STDAPI WslcInitSessionSettings(_In_ PCWSTR name, _In_ PCWSTR storagePath, _Out_ WslcSessionSettings* sessionSettings);| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
name | PCWSTR | in | 待创建会话的名称 |
storagePath | PCWSTR | in | 会话存储写入路径;路径不存在时会自动创建 |
sessionSettings | WslcSessionSettings* | out | 接收设置的指针 |
返回值:HRESULT。
该函数是会话编程的强制入口:必须先调用它拿到一个合法的WslcSessionSettings,之后才能调用任何WslcSetSessionSettings*系列函数或WslcCreateSession。若直接传入未初始化的栈结构,底层实现会因内部类型指针无效而失败。
2.1 会话名称的机器级可见性与安全约束
文档特别强调了两点约束(见 WslcInitSessionSettings):
- 会话名是机器级键:会话名既是显示名,也是全机器范围内标识会话的键。若同名会话已存在,创建将失败并返回
ERROR_ALREADY_EXISTS。 - 全机器可见的信息:以下信息对机器上所有用户可见——会话名称、创建会话的用户的 SID、创建会话的进程的 PID。
- 安全警告:不要在会话名中放置凭据或其他敏感信息。
WslcSessionSettings sessionSettings; HRESULT hr = WslcInitSessionSettings( L"demo-session", L"C:\\WSLC\\demo-session", &sessionSettings);2.2 实现层做了什么:不透明结构与默认值
WslcSessionSettings在公开头文件中被定义为不透明(opaque)结构(见 structures/wslcsessionsettings.md 与 wslcsdk.h):
#define WSLC_SESSION_OPTIONS_SIZE 72 #define WSLC_SESSION_OPTIONS_ALIGNMENT 8 typedef struct WslcSessionSettings { __declspec(align(WSLC_SESSION_OPTIONS_ALIGNMENT)) BYTE _opaque[WSLC_SESSION_OPTIONS_SIZE]; } WslcSessionSettings;从 wslcsdk.cpp 的实现可见,WslcInitSessionSettings在内部将displayName与storagePath写入不透明缓冲区,并一次性灌入四个默认值:
| 内部字段 | 默认值 | 来源 |
|---|---|---|
cpuCount | 2 | Defaults.h |
memoryMb | 2000(约 2 GB) | Defaults.h |
timeoutMS | 300000(5 分钟,受HVSOCKET_CONNECT_TIMEOUT_MAX约束) | Defaults.h |
vhdRequirements.sizeBytes | 32ULL * 1024 * 1024 * 1024(32 GB) | Defaults.h |
这意味着即使你只调用WslcInitSessionSettings不做任何微调,会话也已具备 2 核 CPU、2 GB 内存、5 分钟引导超时与 32 GB 存储的默认配额,无需关心底层细节。
三、会话资源配置:五个 Set 系列函数
所有WslcSetSessionSettings*函数都遵循同一约定:第一个参数是被修改的WslcSessionSettings*,返回HRESULT,且必须在WslcInitSessionSettings之后、WslcCreateSession之前调用。
3.1 CPU 核数:WslcSetSessionSettingsCpuCount
STDAPI WslcSetSessionSettingsCpuCount(_In_ WslcSessionSettings* sessionSettings, _In_ uint32_t cpuCount);| 参数 | 类型 | 方向 |
|---|---|---|
sessionSettings | WslcSessionSettings* | in |
cpuCount | uint32_t | in |
HRESULT hr = WslcSetSessionSettingsCpuCount(&sessionSettings, (uint32_t)4);实现细节(wslcsdk.cpp):当传入cpuCount非 0 时写入选定值;传入 0 则回落为默认值s_DefaultCPUCount(2)。内存与超时函数遵循同样的"0 值回落默认"语义(见下文),因此 0 在这里不是一个合法的"零核"配置,而是"使用默认值"的约定。
3.2 内存上限:WslcSetSessionSettingsMemory
STDAPI WslcSetSessionSettingsMemory(_In_ WslcSessionSettings* sessionSettings, _In_ uint32_t memoryMB);单位是MB。示例将内存设置为 4 GB:
HRESULT hr = WslcSetSessionSettingsMemory(&sessionSettings, (uint32_t)4096);实现(wslcsdk.cpp):memoryMB非 0 则写入,为 0 则回落s_DefaultMemoryMB(2000 MB)。
3.3 引导超时:WslcSetSessionSettingsTimeout
STDAPI WslcSetSessionSettingsTimeout(_In_ WslcSessionSettings* sessionSettings, _In_ uint32_t timeoutMS);单位是毫秒。示例将引导超时设为 2 分钟:
HRESULT hr = WslcSetSessionSettingsTimeout(&sessionSettings, (uint32_t)120000);实现(wslcsdk.cpp):timeoutMS非 0 则写入,为 0 则回落s_DefaultBootTimeout(300000 ms = 5 分钟)。该超时最终作用于底层 hvsocket 引导连接阶段,Defaults.h注释表明其上限受HVSOCKET_CONNECT_TIMEOUT_MAX约束,超时对慢速磁盘上的首次启动尤为重要。
3.4 VHD 存储需求:WslcSetSessionSettingsVhd
STDAPI WslcSetSessionSettingsVhd(_In_ WslcSessionSettings* sessionSettings, _In_opt_ const WslcVhdRequirements* vhdRequirements);| 参数 | 类型 | 方向 |
|---|---|---|
sessionSettings | WslcSessionSettings* | in |
vhdRequirements | const WslcVhdRequirements* | in,可选 |
传入NULL表示不使用自定义 VHD 需求。WslcVhdRequirements结构定义(见 structures/wslcvhdrequirements.md 与 wslcsdk.h):
typedef struct WslcVhdRequirements { _In_z_ PCSTR name; // 被 WslcSetSessionSettingsVhd 忽略 _In_ uint64_t sizeBytes; // 期望大小(用于创建/扩容) _In_ WslcVhdType type; // WSLC_VHD_TYPE_DYNAMIC 或 WSLC_VHD_TYPE_FIXED _In_ WslcVhdRequirementsFlags flags; // WSLC_VHD_REQ_FLAG_NONE / WSLC_VHD_REQ_FLAG_OWNER _In_ uint32_t uid; // 仅当 (flags & WSLC_VHD_REQ_FLAG_OWNER) 时生效 _In_ uint32_t gid; // 仅当 (flags & WSLC_VHD_REQ_FLAG_OWNER) 时生效 } WslcVhdRequirements;头文件注释明确了两条关键语义(wslcsdk.h):
name字段被WslcSetSessionSettingsVhd忽略;type之后的字段(flags/uid/gid)只被WslcCreateSessionVhdVolume采纳;WslcSetSessionSettingsVhd遇到非NONE的 flags 会返回E_INVALIDARG(对应实现见 wslcsdk.cpp 之后的校验分支);WSLC_VHD_TYPE_FIXED只被WslcCreateSessionVhdVolume尊重——在会话设置阶段请使用默认的WSLC_VHD_TYPE_DYNAMIC。
也就是说,在设置阶段WslcSetSessionSettingsVhd只关心sizeBytes,用于声明会话磁盘的默认大小(默认 32 GB,见 Defaults.h);完整的 VHD 创建语义(固定/动态、属主 uid/gid)在 Storage APIs 的WslcCreateSessionVhdVolume中体现。示例(将默认存储扩容到 64 GB):
WslcVhdRequirements vhdRequirements = { 0 }; vhdRequirements.name = "ignored-by-WslcSetSessionSettingsVhd"; vhdRequirements.sizeBytes = (uint64_t)64 * 1024 * 1024 * 1024; vhdRequirements.type = WSLC_VHD_TYPE_DYNAMIC; vhdRequirements.flags = WSLC_VHD_REQ_FLAG_NONE; vhdRequirements.uid = (uint32_t)0; vhdRequirements.gid = (uint32_t)0; HRESULT hr = WslcSetSessionSettingsVhd(&sessionSettings, &vhdRequirements);3.5 特性开关:WslcSetSessionSettingsFeatureFlags
STDAPI WslcSetSessionSettingsFeatureFlags(_In_ WslcSessionSettings* sessionSettings, _In_ WslcSessionFeatureFlags flags);WslcSessionFeatureFlags枚举(见 enumerations/wslcsessionfeatureflags.md 与 wslcsdk.h):
| 枚举值 | 值 | 含义 |
|---|---|---|
WSLC_SESSION_FEATURE_FLAG_NONE | 0x00000000 | 无特性 |
WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU | 0x00000004 | 启用 GPU 加速 |
启用 GPU 加速的示例:
HRESULT hr = WslcSetSessionSettingsFeatureFlags( &sessionSettings, WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU);需要说明的是:会话创建时,SDK 实现还会无条件叠加两个内部特性——WslcFeatureFlagsVirtioFs(virtio-fs 文件系统)与WslcFeatureFlagsDnsTunneling(DNS 隧道),见 wslcsdk.cpp。因此该 API 暴露的是用户可控制的特性位,与实现内部固定启用的特性是叠加关系。
四、创建会话:WslcCreateSession
STDAPI WslcCreateSession(_In_ WslcSessionSettings* sessionSettings, _Out_ WslcSession* session, _Outptr_opt_result_z_ PWSTR* errorMessage);| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
sessionSettings | WslcSessionSettings* | in | 已初始化并配置好的设置 |
session | WslcSession* | out | 接收新会话句柄 |
errorMessage | PWSTR* | out,可选 | 失败时返回人类可读错误信息 |
返回值:HRESULT。
WslcSession session = NULL; HRESULT hr = WslcCreateSession(&sessionSettings, &session, NULL);4.1 实现层的调用链
从 wslcsdk.cpp 可以看到WslcCreateSession的完整内部流程:
- 通过
CheckAndGetInternalType取出WslcSessionSettings内部字段; - 创建兼容会话管理器
IWSLCCompatSessionManager; - 将公开字段映射为
WSLCCompatSessionSettings运行时设置——MaximumStorageSizeMb由vhdRequirements.sizeBytes / 1MB计算得出、CpuCount、MemoryMb、BootTimeoutMs、NetworkingMode = WSLCNetworkingModeConsomme(Consomme 网络栈)、FeatureFlags经ConvertFlags转换; - 叠加 VirtioFs 与 DNS Tunneling 两个内部特性位;
- 调用
sessionManager->CreateSession(...)真正拉起会话; - 成功后通过
ConfigureForCOMImpersonation配置 COM 模拟身份(服务端进程管控的一部分),并将句柄返回给调用者。
会话句柄本身由DECLARE_HANDLE(WslcSession)声明(wslcsdk.h),对调用方是不透明句柄,只能传给其他 Wslc API 使用。若CreateSession失败,错误信息会写入可选的errorMessage参数,调用方需用CoTaskMemFree释放。
4.2 先决条件检查
在调用WslcCreateSession之前,官方端到端示例(end-to-end-example.md)还建议先通过WslcGetMissingComponents检查平台组件是否就绪,缺失时提示运行wsl --install:
WslcComponentFlags missing = WSLC_COMPONENT_FLAG_NONE; hr = WslcGetMissingComponents(&missing); if (FAILED(hr) || missing != WSLC_COMPONENT_FLAG_NONE) { printf("WSL components are missing. Run: wsl --install\n"); CoUninitialize(); return 1; }五、监控会话终止:事件 + 原因查询
5.1 获取终止事件:WslcGetSessionTerminationEvent
STDAPI WslcGetSessionTerminationEvent(_In_ WslcSession session, _Out_ HANDLE* terminationEvent);| 参数 | 类型 | 方向 |
|---|---|---|
session | WslcSession | in |
terminationEvent | HANDLE* | out |
返回的HANDLE是标准 Windows 事件内核对象,可直接用于WaitForSingleObject/WaitForMultipleObjects/SetThreadpoolWait等任意等待机制:
HANDLE terminationEvent = NULL; HRESULT hr = WslcGetSessionTerminationEvent(session, &terminationEvent); if (SUCCEEDED(hr)) { WaitForSingleObject(terminationEvent, 1000); }5.2 查询终止原因:WslcGetSessionTerminationReason
STDAPI WslcGetSessionTerminationReason(_In_ WslcSession session, _Out_ WslcSessionTerminationReason* reason);| 参数 | 类型 | 方向 |
|---|---|---|
session | WslcSession | in |
reason | WslcSessionTerminationReason* | out |
WslcSessionTerminationReason枚举(见 enumerations/wslcsessionterminationreason.md 与 wslcsdk.h):
| 枚举值 | 值 | 含义 |
|---|---|---|
WSLC_SESSION_TERMINATION_REASON_UNKNOWN | 0 | 未知原因 |
WSLC_SESSION_TERMINATION_REASON_SHUTDOWN | 1 | 正常关闭 |
WSLC_SESSION_TERMINATION_REASON_CRASHED | 2 | 崩溃终止 |
WslcSessionTerminationReason reason = WSLC_SESSION_TERMINATION_REASON_UNKNOWN; HRESULT hr = WslcGetSessionTerminationReason(session, &reason);5.3 源码证据:WinRT 层如何组合使用这两个 API
在 SDK 的 WinRT 投影实现 winrt/Session.cpp 中,Start()展示了标准的监控接线方式:
WslcCreateSession创建会话;WslcGetSessionTerminationEvent取出终止事件;CreateThreadpoolWait+SetThreadpoolWait把终止事件挂到线程池等待上;- 当线程池回调
OnTerminated触发时(Session.cpp),回调内部调用WslcGetSessionTerminationReason查询终止原因并向外抛出Terminated事件。
可见,"事件句柄 + 终止原因查询"这一对 API 正是上层封装事件模型的底层基石:事件解决"什么时候终止"的同步问题,原因枚举解决"为什么终止"的诊断问题。
六、崩溃转储订阅:回调注册与释放
6.1 回调类型与信息结构
回调类型定义(见 callback-types/wslcsessioncrashdumpcallback.md):
typedef __callback void(CALLBACK* WslcSessionCrashDumpCallback)(_In_ const WslcSessionCrashDumpInfo* info, _In_opt_ PVOID context);回调携带的WslcSessionCrashDumpInfo结构(见 structures/wslcsessioncrashdumpinfo.md 与 wslcsdk.h):
| 字段 | 类型 | 含义 |
|---|---|---|
dumpPath | PCWSTR | 转储文件路径(宽字符) |
processName | PCSTR | 崩溃进程名(窄字符) |
pid | uint32_t | 崩溃进程 PID |
signal | uint32_t | 触发崩溃的信号 |
timestamp | uint64_t | 时间戳 |
6.2 注册回调:WslcRegisterSessionCrashDumpCallback
STDAPI WslcRegisterSessionCrashDumpCallback( _In_ WslcSession session, _In_ WslcSessionCrashDumpCallback crashDumpCallback, _In_opt_ PVOID crashDumpContext, _Out_ WslcCrashDumpSubscription* subscription, _Outptr_opt_result_z_ PWSTR* errorMessage);| 参数 | 类型 | 方向 |
|---|---|---|
session | WslcSession | in |
crashDumpCallback | WslcSessionCrashDumpCallback | in |
crashDumpContext | PVOID | in,可选 |
subscription | WslcCrashDumpSubscription* | out |
errorMessage | PWSTR* | out,可选 |
WslcCrashDumpSubscription是不透明句柄,持有它就等于持有注册的存活期(见 wslcsdk.h);同一会话可注册多个订阅。头文件注释还强调该回调对任何持有活动会话的调用者都可用(即不限于创建者),便于独立监控进程挂接。
void CALLBACK OnCrashDump(const WslcSessionCrashDumpInfo* info, PVOID context) { UNREFERENCED_PARAMETER(context); wprintf(L"dump=%ls\n", info->dumpPath); } WslcCrashDumpSubscription subscription = NULL; HRESULT hr = WslcRegisterSessionCrashDumpCallback( session, OnCrashDump, NULL, &subscription, NULL);6.3 释放订阅:WslcReleaseCrashDumpSubscription
STDAPI WslcReleaseCrashDumpSubscription(_In_ WslcCrashDumpSubscription subscription);HRESULT hr = WslcReleaseCrashDumpSubscription(subscription); subscription = NULL;6.4 源码证据:WinRT 层回调适配
WinRT 投影 Session.cpp 中的OnCrashDump展示了回调的典型消费方式:把 C 回调收到的WslcSessionCrashDumpInfo包装成ProcessCrashInformation托管对象,再以事件形式抛给上层应用;而Session::Close对应的析构流程会释放m_crashDumpSubscription。这印证了"注册回调 → 收到信息 → 释放订阅"的完整闭环。
七、会话清理与收尾:Terminate 与 Release
7.1 终止会话:WslcTerminateSession
STDAPI WslcTerminateSession(_In_ WslcSession session);HRESULT hr = WslcTerminateSession(session);实现(wslcsdk.cpp):若句柄对应的内部会话不存在,返回HRESULT_FROM_WIN32(ERROR_INVALID_STATE);否则调用session->Terminate()。这是会话的主动关闭路径,会触发终止事件置位,使等待在WslcGetSessionTerminationEvent句柄上的代码得以唤醒。
7.2 释放句柄:WslcReleaseSession
STDAPI WslcReleaseSession(_In_ WslcSession session);HRESULT hr = WslcReleaseSession(session); session = NULL;Terminate与Release的分工:WslcTerminateSession负责让虚拟机停止运行,WslcReleaseSession负责释放本地句柄引用。官方示例的收尾总是成对出现:先WslcTerminateSession(session),再WslcReleaseSession(session)(见 end-to-end-example.md)。
八、会话内认证:WslcSessionAuthenticate
STDAPI WslcSessionAuthenticate( _In_ WslcSession session, _In_z_ PCSTR serverAddress, _In_z_ PCSTR username, _In_z_ PCSTR password, _Outptr_result_z_ PSTR* identityToken, _Outptr_opt_result_z_ PWSTR* errorMessage);| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
session | WslcSession | in | 目标会话 |
serverAddress | PCSTR | in | 服务器地址(如127.0.0.1:5000) |
username | PCSTR | in | 用户名 |
password | PCSTR | in | 密码 |
identityToken | PSTR* | out | 返回的身份令牌 |
errorMessage | PWSTR* | out,可选 | 错误信息 |
内存约定(头文件注释明确):identityToken由CoTaskMemAlloc分配,必须用CoTaskMemFree释放。
PSTR identityToken = NULL; HRESULT hr = WslcSessionAuthenticate( session, "127.0.0.1:5000", "user", "password", &identityToken, NULL); if (SUCCEEDED(hr)) { printf("token=%s\n", identityToken); CoTaskMemFree(identityToken); }该 API 用于在创建会话后,与会话内暴露的服务(例如镜像注册表服务)建立身份,获取后续操作所需的令牌。注意其地址、用户名、密码均为窄字符(PCSTR)而错误信息为宽字符(PWSTR),与WslcCreateSession的错误信息类型保持一致。
九、端到端实战:从初始化到清理的完整生命周期
把上面的 API 串起来,就是一个可编译运行的完整生命周期程序(改编自官方 end-to-end-example.md,下面对其做逐步注解)。前置条件:CoInitializeEx(nullptr, COINIT_MULTITHREADED)初始化 COM,链接ole32.lib与wslcsdk.lib。
#include <winsock2.h> #include <windows.h> #include <stdio.h> #include <objbase.h> #include <filesystem> #include "wslcsdk.h" #pragma comment(lib, "ole32.lib") #pragma comment(lib, "wslcsdk.lib") int main() { // Initialize COM CoInitializeEx(nullptr, COINIT_MULTITHREADED); HRESULT hr; PWSTR error = nullptr; // 0. Check prerequisites(先决条件检查,组件缺失时提示 wsl --install) WslcComponentFlags missing = WSLC_COMPONENT_FLAG_NONE; hr = WslcGetMissingComponents(&missing); if (FAILED(hr) || missing != WSLC_COMPONENT_FLAG_NONE) { printf("WSL components are missing. Run: wsl --install\n"); CoUninitialize(); return 1; } WslcVersion ver = {}; WslcGetVersion(&ver); printf("WSL version: %u.%u.%u\n", ver.major, ver.minor, ver.revision); // 1. 初始化并创建会话(本指南核心:Session APIs) std::filesystem::path storagePath = std::filesystem::current_path(); WslcSessionSettings sessionSettings; hr = WslcInitSessionSettings(L"MyApp", storagePath.c_str(), &sessionSettings); if (FAILED(hr)) return 1; // 可选:自定义资源配额 WslcSetSessionSettingsCpuCount(&sessionSettings, 4); WslcSetSessionSettingsMemory(&sessionSettings, 4096); WslcSetSessionSettingsTimeout(&sessionSettings, 120000); WslcSession session = nullptr; hr = WslcCreateSession(&sessionSettings, &session, &error); if (FAILED(hr)) { wprintf(L"Session creation failed: %s\n", error ? error : L"unknown"); CoTaskMemFree(error); CoUninitialize(); return 1; } // 2. 拉取镜像(Image APIs) WslcPullImageOptions pullOpts = {}; pullOpts.uri = "docker.io/library/alpine:latest"; hr = WslcPullSessionImage(session, &pullOpts, &error); if (FAILED(hr)) { wprintf(L"Pull failed: %s\n", error ? error : L"unknown"); CoTaskMemFree(error); WslcTerminateSession(session); WslcReleaseSession(session); CoUninitialize(); return 1; } // 3. 配置 init 进程(Process APIs) WslcProcessSettings initProcSettings; WslcInitProcessSettings(&initProcSettings); PCSTR argv[] = { "/bin/echo", "Hello from WSL Container!" }; WslcSetProcessSettingsCmdLine(&initProcSettings, argv, 2); // 4. 配置并创建容器(Container APIs) WslcContainerSettings containerSettings; WslcInitContainerSettings("alpine:latest", &containerSettings); WslcSetContainerSettingsName(&containerSettings, "hello-container"); WslcSetContainerSettingsInitProcess(&containerSettings, &initProcSettings); WslcContainer container = nullptr; hr = WslcCreateContainer(session, &containerSettings, &container, &error); if (FAILED(hr)) { wprintf(L"Container creation failed: %s\n", error ? error : L"unknown"); CoTaskMemFree(error); WslcTerminateSession(session); WslcReleaseSession(session); CoUninitialize(); return 1; } // 5. 启动容器 hr = WslcStartContainer(container, WSLC_CONTAINER_START_FLAG_NONE, &error); if (FAILED(hr)) { wprintf(L"Start failed: %s\n", error ? error : L"unknown"); CoTaskMemFree(error); WslcDeleteContainer(container, WSLC_DELETE_CONTAINER_FLAG_FORCE, nullptr); WslcReleaseContainer(container); WslcTerminateSession(session); WslcReleaseSession(session); CoUninitialize(); return 1; } // 6. 等待 init 进程退出 WslcProcess initProc = nullptr; hr = WslcGetContainerInitProcess(container, &initProc); if (SUCCEEDED(hr)) { HANDLE exitEvent = nullptr; if (SUCCEEDED(WslcGetProcessExitEvent(initProc, &exitEvent))) { WaitForSingleObject(exitEvent, 30000); // 30 秒超时 } INT32 exitCode = 0; if (SUCCEEDED(WslcGetProcessExitCode(initProc, &exitCode))) { printf("Process exited with code: %d\n", exitCode); } WslcReleaseProcess(initProc); } // 7. 清理:停容器、删容器、终止并释放会话 WslcContainerState containerState = WSLC_CONTAINER_STATE_INVALID; if (SUCCEEDED(WslcGetContainerState(container, &containerState)) && containerState == WSLC_CONTAINER_STATE_RUNNING) { WslcStopContainer(container, WSLC_SIGNAL_SIGTERM, 10, nullptr); } WslcDeleteContainer(container, WSLC_DELETE_CONTAINER_FLAG_NONE, nullptr); WslcReleaseContainer(container); WslcTerminateSession(session); WslcReleaseSession(session); CoUninitialize(); return 0; }生命周期要点回顾:
- 初始化:
WslcInitSessionSettings是唯一合法起点,同时写入默认配额; - 配置:各
WslcSetSessionSettings*按需覆盖默认值(传 0 回落默认); - 创建:
WslcCreateSession拉起虚拟机并返回句柄,失败时检查errorMessage; - 使用:在会话内进行镜像、容器、进程操作(分属 Image/Container/Process APIs);
- 监控(可选):
WslcGetSessionTerminationEvent+WslcGetSessionTerminationReason感知退出,WslcRegisterSessionCrashDumpCallback收集崩溃转储; - 清理:先
WslcTerminateSession再WslcReleaseSession,顺序不可颠倒,否则句柄泄漏或出现无效状态。
十、常见错误与排查提示
Session APIs 的所有函数均返回HRESULT,通用的 Windows HRESULT(如E_POINTER、E_INVALIDARG、ERROR_ALREADY_EXISTS、ERROR_INVALID_STATE)之外,还可能返回 WSL 容器专属错误码(完整列表见 error-codes.md),其中与会话场景最相关的是:
| 错误码 | 十六进制值 | 场景 |
|---|---|---|
WSLC_E_SESSION_RESERVED | 0x80040607 | 会话名被系统保留 |
WSLC_E_INVALID_SESSION_NAME | 0x80040608 | 会话名不合法 |
WSLC_E_SESSION_NOT_FOUND | 0x8004060F | 会话不存在 |
WSLC_E_VM_NOT_RUNNING | 0x80040610 | 虚拟机未运行(如尝试在已终止会话上操作) |
WSLC_E_SDK_UPDATE_NEEDED | 0x8004060B | 主机 WSL 组件与 SDK 版本不匹配 |
排查建议:
- 创建失败:优先检查
WslcGetMissingComponents返回值与errorMessage;确认会话名在机器上唯一且不含敏感信息; - 配额未生效:确认传入值非 0(0 会回落默认值),且所有
WslcSetSessionSettings*都在WslcCreateSession之前调用; - 终止监听失效:确认先
WslcGetSessionTerminationEvent再开始等待,且WslcTerminateSession或崩溃路径确实触发; - 内存泄漏:
errorMessage与identityToken均需CoTaskMemFree;会话句柄必须WslcReleaseSession,崩溃订阅必须WslcReleaseCrashDumpSubscription。
延伸阅读
- C API 参考总入口:结构、枚举、回调类型与全部 API 分组
- Structures 参考:
WslcSessionSettings、WslcVhdRequirements、WslcSessionCrashDumpInfo等 - Enumerations 参考:特性标志、终止原因、VHD 类型等枚举全集
- Error Codes:全部 WSL 容器专属错误码
- End-to-End Example:官方完整生命周期示例
- SDK 头文件:所有公开 API 声明与头文件注释
- SDK 实现:
WslcInitSessionSettings/WslcCreateSession/WslcTerminateSession等核心实现 - 默认值定义:CPU、内存、超时、存储的默认配额
- WinRT 投影示例:终止事件与崩溃回调在高层 API 中的消费方式
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考