十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

WSLC-Neofetch:用 C++/WinRT 编写原生 Windows 可执行文件,在 WSL 容器中运行 Linux 命令

WSLC-Neofetch:用 C++/WinRT 编写原生 Windows 可执行文件,在 WSL 容器中运行 Linux 命令 WSLC-Neofetch用 C/WinRT 编写原生 Windows 可执行文件在 WSL 容器中运行 Linux 命令【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL导读WSLC-Neofetch 是 WSL 仓库中 doc/samples 目录下的一个官方示例演示如何用C/WinRT 投影编写一个原生 Windows 可执行文件neofetch.exe通过WSL Container APIMicrosoft.WSL.Containers启动一个轻量级 WSL 容器、在容器内运行 Linux 的neofetch命令并把输出实时流式回传到 Windows 终端。读完本文你将掌握 WSL 容器 SDK 的核心生命周期会话 → 拉镜像 → 建容器 → 执行进程 → 清理、C/WinRT 回调驱动的 I/O 流式传输写法以及如何像本示例一样把命令行参数原样转发进容器做出一个 .exe 就是一条 Linux 命令的实战效果。一、示例背景从 Windows 调用 Linux 命令的新姿势传统上在 Windows 上运行 Linux 命令要么使用 WSL 发行版wsl.exe 发行版环境要么依赖 Docker Desktop。WSLC-Neofetch 展示的是另一条路径WSL Container APIWSLC——由Microsoft.WSL.ContainersSDK 提供的一套原生编程接口让任何 Windows 原生程序C/C、C#直接创建和管理运行在 WSL 内部的 Linux 容器。本示例的核心特性源自 WSLC-Neofetch README运行neofetch.exe会启动一个轻量级 WSL 容器在其中运行neofetch并将输出流式回传到你的终端命令行参数会被完整转发因此neofetch.exe --help的效果与 Linux 下的neofetch --help完全一致进度消息以[wslc] ...前缀出现写入stderr因此对 stdout 做管道重定向是安全的不会污染命令输出。配套的四个示例见 doc/samples/README.md覆盖了不同语言栈示例语言说明WSLC-HelloWorldC最小示例在alpine容器中运行echo并打印输出WSLC-NeofetchC/WinRT在原生 Windows.exe中运行 Linuxneofetch命令WSLC-NextCloudC#在容器中运行 Nextcloud 服务暴露于http://localhost:8080WSLC-CustomContainerC# CLI用自定义 Containerfile 构建镜像F5 自动构建在终端生成可扫描的二维码其中 WSLC-HelloWorld 使用扁平 C APIwslcsdk.h而本示例刻意选择了C/WinRT 投影winrt/Microsoft.WSL.Containers.h是学习现代投影写法的理想范本。二、构建Visual Studio 与命令行两种方式README 给出了两种构建方式前提是 x64方式一Visual Studio打开WSLCNeofetch.sln解决方案直接以 x64 平台构建即可。方式二开发者命令提示符nuget restore WSLCNeofetch.sln msbuild WSLCNeofetch.sln /p:ConfigurationDebug /p:Platformx64构建产物位于x64\Debug\neofetch.exe。依赖包NuGet 解析结果本示例的 NuGet 依赖在 packages.config 中声明packages package idMicrosoft.Windows.CppWinRT version3.0.260520.1 targetFrameworknative / package idMicrosoft.WSL.Containers version2.9.3 targetFrameworknative / /packagesMicrosoft.Windows.CppWinRTC/WinRT 工具链负责从 WinMD 元数据生成投影头文件Microsoft.WSL.ContainersWSLC SDK 本体其文档位于 nuget/Microsoft.WSL.Containers/docs/README.MD其中说明包会自动配置 include 目录与链接库wslcsdk.lib、把运行时 DLLwslcsdk.dll复制到输出目录并注入激活清单manifest使RoGetActivationFactory无需 COM 注册即可将 WinRT 类解析到wslcsdk.dll。前提条件需要安装 WSLwsl --install --no-distribution它同时提供wslcCLI且该 SDK 目前仍处于Preview阶段wslcsdk.h 明确声明 API 可能发生破坏性变更不应用于生产负载。三、运行一个 .exe 就是一条 Linux 命令x64\Debug\neofetch.exe # 显示系统信息 x64\Debug\neofetch.exe --help # 参数被转发给 neofetch第一行直接展示系统信息第二行把--help转发到容器内的neofetch输出 Linux 原生帮助文本。由于[wslc]进度消息全部走 stderr你可以安全地执行x64\Debug\neofetch.exe | findstr /i OSstdout 中只包含neofetch本身的输出不会混入 SDK 日志。四、源码逐段拆解C/WinRT 版本的完整生命周期核心实现位于 neofetch.cpp整体流程与 C 版 helloworld.c 一一对应可对照阅读。下面按执行顺序拆解。4.1 头文件与命名空间#include winrt/Windows.Foundation.h #include winrt/Windows.Foundation.Collections.h #include winrt/Microsoft.WSL.Containers.h using namespace winrt; using namespace winrt::Microsoft::WSL::Containers;winrt/Microsoft.WSL.Containers.h是Microsoft.WSL.Containers包的 C/WinRT 投影头文件。SDK 的 WinRT 激活类清单见 Microsoft.WSL.Containers.manifest列出了Session、SessionSettings、Container、ContainerSettings、Process、ProcessSettings、PullImageOptions等可激活类全部通过wslcsdk.dll提供。4.2 常量与工具函数constexpr std::wstring_view c_imageName Lanrginit/ubuntu-neofetch:1.0; void WriteToConsole(FILE* stream, array_viewuint8_t const data) { fprintf(stream, %.*s, static_castint(data.size()), reinterpret_castconst char*(data.data())); fflush(stream); } std::wstring GetStoragePath() { wchar_t exePath[MAX_PATH]; GetModuleFileNameW(nullptr, exePath, MAX_PATH); wchar_t* lastSlash wcsrchr(exePath, L\\); if (lastSlash ! nullptr) *(lastSlash 1) L\0; return std::wstring{exePath} LWslcStorage; }镜像固定为anrginit/ubuntu-neofetch:1.0内含neofetch的 Ubuntu 镜像WriteToConsole把容器 stdout/stderr 的数据块直接写到 Windows 控制台流并立即刷新GetStoragePath在可执行文件旁生成WslcStorage目录作为会话存储路径——刻意不依赖任何硬编码绝对路径。这与 C 版 helloworld.c 的GetStoragePath思路完全一致。4.3 参数转发argv[0] 替换为 neofetchint wmain(int argc, wchar_t* argv[]) { init_apartment(); std::vectorhstring commandLine{Lneofetch}; for (int i 1; i argc; i) { commandLine.emplace_back(argv[i]); } ...关键设计argv[0]neofetch.exe自身被替换成 Linux 侧的neofetch其余参数原样透传。这是neofetch.exe --help等价于neofetch --help的实现基础。init_apartment()初始化 C/WinRT 的线程模型默认多线程单元。4.4 第一步创建并启动会话SessionSessionSettings sessionSettings{LWSLCNeofetch, GetStoragePath()}; sessionSettings.CpuCount(4); sessionSettings.MemorySizeInMB(2048); Session session{sessionSettings}; session.Start();Session对应一个 WSL 容器虚拟机租期承载其下所有容器。SessionSettings构造函数接收会话名与存储路径CpuCount(4)与MemorySizeInMB(2048)分别限定 4 个 CPU 与 2 GB 内存。在扁平 C API 中这两个选项对应 wslcsdk.h 的WslcSetSessionSettingsCpuCount与WslcSetSessionSettingsMemory此外 C API 还暴露了WslcSetSessionSettingsTimeout会话超时毫秒、WslcSetSessionSettingsVhd自定义 VHD 要求支持动态/固定分配见WslcVhdType与WslcSetSessionSettingsFeatureFlags如 GPU 加速WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU等可选设置。4.5 第二步拉取镜像PullImagesession.PullImage(PullImageOptions{hstring{c_imageName}});从注册表拉取anrginit/ubuntu-neofetch:1.0到本地。C API 对应的 WslcPullSessionImage 支持progressCallback上报分层拉取进度Pulling fs layer/Downloading/Verifying Checksum/Extracting/Pull complete见WslcImageProgressStatus枚举并支持registryAuth认证。若后续想避免每次联网拉取C API 还提供了WslcImportSessionImage/WslcLoadSessionImage从 tar/文件导入镜像见 wslcsdk.h。4.6 第三步创建并启动容器ContainerProcessSettings initProcess; initProcess.CommandLine(single_threaded_vectorhstring({L/bin/sleep, L60})); ContainerSettings containerSettings{hstring{c_imageName}}; containerSettings.Name(Lwslc-neofetch); containerSettings.InitProcess(initProcess); containerSettings.EnableAutoRemove(true); Container container session.CreateContainer(containerSettings); container.Start();容器由ContainerSettings描述Name(Lwslc-neofetch)容器名称InitProcessinit 进程。这里用/bin/sleep 60让容器保持存活 60 秒以便后续exec运行neofetch——这是 WSLC 的关键机制容器内必须有一个常驻 init 进程进程Process是挂在容器之上被CreateProcess出来的EnableAutoRemove(true)容器退出后自动清理对应 C API 的WSLC_CONTAINER_FLAG_AUTO_REMOVE标志wslcsdk.h。C API 中ContainerSettings还支持更多可选配置WslcSetContainerSettingsNetworkingModeNONE隔离 /BRIDGED桥接、WslcSetContainerSettingsHostName/DomainName、WslcSetContainerSettingsPortMappingsWindows 端口 ↔ 容器端口映射TCP/UDP、WslcSetContainerSettingsVolumesWindows 目录挂载进容器支持只读、WslcSetContainerSettingsNamedVolumes以及WSLC_CONTAINER_FLAG_ENABLE_GPU/PRIVILEGED标志等均可在创建前设置。4.7 第四步Exec 进程并流式接收输出Process这是本示例最有代表性的部分——回调驱动的异步 I/OProcessSettings processSettings; processSettings.CommandLine(single_threaded_vectorhstring(std::move(commandLine))); processSettings.OutputMode(ProcessOutputMode::Event); Process process container.CreateProcess(processSettings); handle exitEvent{CreateEvent(nullptr, TRUE, FALSE, nullptr)}; int32_t exitCode -1; process.OutputReceived([](array_viewuint8_t const data) { WriteToConsole(stdout, data); }); process.ErrorReceived([](array_viewuint8_t const data) { WriteToConsole(stderr, data); }); process.Exited( { exitCode code; if (!SetEvent(exitEvent.get())) fwprintf(stderr, L[wslc] Warning: SetEvent failed (0x%08X)\n, GetLastError()); }); process.Start(); DWORD waitResult WaitForSingleObject(exitEvent.get(), 30000); if (waitResult WAIT_TIMEOUT) fwprintf(stderr, L[wslc] Error: Timed out waiting for the process to exit.\n); else if (waitResult ! WAIT_OBJECT_0) throw_last_error();OutputMode(ProcessOutputMode::Event)将输出模式切换为事件回调配合OutputReceived/ErrorReceived两个 lambda 把容器 stdout/stderr 数据块即时转发到 Windows 控制台Exited回调记录退出码并触发exitEvent主线程用WaitForSingleObject等待 30 秒超时C API 的对应物是 WslcProcessCallbacks 中的onStdOut/onStdErr/onExit三件套注意头文件注释缓冲区由 WSLC 持有、仅在回调期间有效需要保留数据必须自行拷贝且回调需尽快返回否则会阻塞 SDK 内部 I/O 处理。WslcSetProcessSettingsCmdLine/WslcSetProcessSettingsEnvVariables还可设置工作目录、环境变量等。4.8 第五步清理与错误处理container.Stop(Signal::SIGTERM, std::chrono::seconds{5}); session.Terminate();container.Stop(Signal::SIGTERM, 5s)以 SIGTERM 信号优雅停止容器超时 5 秒。C API 的WslcSignal枚举wslcsdk.h定义了SIGHUP(1)、SIGINT(2)、SIGQUIT(3)、SIGKILL(9)、SIGTERM(15)session.Terminate()结束整个会话虚拟机租期外层try/catch (hresult_error const ex)统一捕获 WinRT 错误打印 HRESULT 码0x%08X并返回 1。C 版则通过goto cleanup逐级释放WslcReleaseProcess→WslcStopContainer→WslcTerminateSession等句柄。4.9 完整生命周期全景阶段C/WinRT本示例扁平 C APIhelloworld.c会话SessionSettingsSession::Start()WslcInitSessionSettings→WslcCreateSession拉镜像session.PullImage(...)WslcPullSessionImage建容器ContainerSettingsCreateContainerWslcInitContainerSettings→WslcCreateContainer启容器container.Start()WslcStartContainer跑进程ProcessSettingsCreateProcessWslcInitProcessSettings→WslcCreateContainerProcess收输出OutputReceived/ErrorReceived/Exited委托onStdOut/onStdErr/onExit回调清理Stop(SIGTERM)→Terminate()WslcStopContainer→WslcTerminateSession五、扩展讨论如何把这个模式推广到任意 Linux 命令WSLC-Neofetch 的可贵之处在于它几乎不包含任何与neofetch强绑定的逻辑——commandLine只是把argv替换后整体转发。这意味着只需修改commandLine向量与镜像即可把同一套模板套用到任意 Linux CLI换命令把commandLine首元素从Lneofetch改为Lhtop、Llazygit等并换成包含该工具的镜像拉长命令/bin/sleep 60的 init 进程超时可根据任务耗时调整若命令超时可考虑给 init 更长的存活时间或改用更合适的机制改用本地镜像若不想每次联网拉取可用 WSLC-CustomContainer 演示的构建集成——WslcImageMSBuild 项在构建期自动执行wslc image buildwslc image save生成 tar再通过 SDK 的导入/加载接口WslcImportSessionImageFromFile/WslcLoadSessionImageFromFile从本地 tar 载入无注册表拉取步骤跨语言对照想理解扁平 C API 的同学可对照 WSLC-HelloWorld两份代码的生命周期与回调语义几乎一一对应。值得注意该 SDK 处于预览期wslcsdk.h 与 Microsoft.WSL.Containers 文档 均给出 Preview 警告用于生产负载前需评估 API 稳定性风险。六、小结WSLC-Neofetch 以不足 140 行的 C/WinRT 代码完整展示了 WSL Container API 的五段生命周期会话Session→ 拉镜像PullImage→ 建容器Container→ 执行进程Process→ 优雅清理。它的核心工程经验有三条参数转发把argv[0]替换为容器内命令名、其余参数原样透传即可获得原生 .exe 即 Linux 命令的体验回调流式输出OutputReceived/ErrorReceived/Exited委托让容器 I/O 与 Windows 控制台无缝衔接且进度日志走 stderr、业务输出走 stdout天然适合管道零硬编码路径存储目录基于可执行文件位置动态生成WslcStorage示例开箱即用、便于分发。如果你正准备为 Windows 桌面应用集成 Linux 工具链或想学习Microsoft.WSL.ContainersSDK 的 C/WinRT 投影写法这个示例是绝佳的起点。更完整的 API 面GPU 加速、端口映射、卷挂载、镜像导入导出、注册表认证等可进一步查阅 wslcsdk.h 与 Microsoft.WSL.Containers 包文档。【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表