windows 启动项首选注册表(hkcu/hklm un),wmi 不稳定;linux 需按 systemd、autostart 目录等场景分别处理;macos 分 launchagents、launchdaemons 和 login items 三类,需调用原生 api 或 plist 解析。

Windows 上读取启动项:注册表和 WMI 都要试,但注册表更稳
Windows 启动项分散在多个位置,HKCUSoftwareMicrosoftWindowsCurrentVersionRun 和 HKLMSoftwareMicrosoftWindowsCurrentVersionRun 是最常见、最可靠的两个注册表路径。WMI(Win32_StartupCommand 类)理论上能覆盖更多类型(比如 Shell 延迟启动项),但实际中常因权限或 WMI 服务状态返回空结果,不建议单独依赖。
实操建议:
- 用
RegOpenKeyEx分别打开上述两个键,再用RegEnumValue枚举所有值;注意判断值类型是否为REG_SZ或REG_EXPAND_SZ,后者需调用ExpandEnvironmentStrings - 避免硬编码宽字符处理逻辑——直接用
std::wstring和RegQueryValueEx的LPBYTE缓冲区配合dwSize循环读取,比一次性分配大缓冲更安全 - 若程序以普通用户运行,
HKEY_LOCAL_MACHINE下的项可能因 UAC 被拒绝访问,此时应捕获ERROR_ACCESS_DENIED并静默跳过,而非报错中断
Linux 下没有统一“启动项”概念,得按场景拆解
Linux 没有 Windows 那种中心化启动项管理机制,所谓“开机自启”取决于 init 系统(systemd、sysvinit、upstart)和用户会话管理器(如 ~/.config/autostart/)。C++ 程序无法跨发行版一招通吃,必须先检测环境。
实操建议:
- 优先检查
systemctl --user list-unit-files --type=service(用户级)和systemctl list-unit-files --type=service(系统级),解析 stdout 中状态为enabled的 service 单元;注意区分--user和 root 权限调用 - 检查
/etc/xdg/autostart/和$HOME/.config/autostart/目录下的.desktop文件,用libinih或手动解析[Desktop Entry]段中的Exec=字段,忽略Hidden=true或NoDisplay=true的项 - 不要尝试读取
/etc/rc.local或传统 init 脚本——它们在大多数现代发行版中已弃用,且执行时机与桌面自启无关
macOS 启动项分三类:LaunchAgents、LaunchDaemons、Login Items
macOS 的启动项由 launchd 管理,但用户级和系统级完全隔离:~/Library/LaunchAgents/ 存放用户登录后启动的 plist,/Library/LaunchDaemons/ 存放系统级守护进程,而 GUI 应用的“登录项”则藏在 NSWorkspace 的私有 API 或 defaults read com.apple.loginitems 输出里。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
实操建议:
- 遍历
~/Library/LaunchAgents/和/Library/LaunchDaemons/目录,用plistC API(plist_from_xml+plist_dict_get_item)提取ProgramArguments或Program键;注意校验文件所有权和权限(launchd 会拒绝加载组/其他可写的 plist) - 获取 GUI 登录项必须调用 Objective-C 运行时——C++ 项目可通过
extern "C"封装一个 .mm 文件,用[[NSWorkspace sharedWorkspace] loginItems]获取数组,再转成 C 字符串;直接执行defaults命令容易漏掉禁用项(isDisabled = 1) - 不要混淆
LaunchAgents和Login Items:前者是后台服务,后者是前台应用图标,两者在系统设置里显示位置不同,用途也不同
跨平台封装要注意权限、路径和“启用状态”的语义差异
同一个字符串在不同系统代表的意义可能完全不同:Windows 注册表里的字符串可能是完整命令行,macOS plist 里的 ProgramArguments 是 argv 数组,Linux desktop 文件里的 Exec= 又支持 %f/%u 等占位符。更麻烦的是,“是否启用”在各平台判定逻辑不一致。
关键细节:
- Windows 注册表值存在即启用;Linux systemd 中
enabled表示软链接存在,但实际是否运行要看active状态;macOS Login Items 有显式的isEnabled属性,但 LaunchAgents 没有对应字段——只能靠文件是否存在+是否被 launchd 加载来间接判断 - 所有路径拼接必须用
std::filesystem::path(C++17),避免硬拼"\\"或"/";读取前务必调用std::filesystem::exists()和std::filesystem::is_regular_file(),防止符号链接循环或权限拒绝导致崩溃 - 不要试图用单一结构体统一表示所有启动项——字段太多、语义太散,不如按平台返回
std::vector<:map std::string>></:map>,让上层业务自己适配字段名
真正难的不是读取,而是理解每个平台“启动项”背后的实际行为边界:有的只在登录时触发,有的随系统启动就拉起,有的甚至需要用户交互才激活。拿到列表只是第一步,后续的启用/禁用/编辑操作,每一步都得回到对应平台的原生机制里去实现。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










