当前位置: 首页 > news >正文

C++:如何指定应用开机自启动

前言

通过代码将要开机自启动的应用的路径信息写入到本地注册表中,这样我的应用就可以在重启或者开机后,自动启动了。以下为代码演示:

头文件

#include <windows.h> #include <iostream> #include <string> #include <fstream> #include <shlwapi.h> #include <sstream> // 用于 std::istringstream #pragma comment(lib, "shlwapi.lib")

工具函数:

宽字符串转窄字符串(ANSI)

// 宽字符串转窄字符串(ANSI) std::string WStringToString(const std::wstring& wstr) { if (wstr.empty()) return ""; int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL); if (len <= 0) return ""; std::string result(len - 1, 0); WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &result[0], len, NULL, NULL); return result; }

窄字符串转宽字符串

// 窄字符串转宽字符串 std::wstring StringToWString(const std::string& str) { if (str.empty()) return L""; int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0); if (len <= 0) return L""; std::wstring result(len - 1, 0); MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &result[0], len); return result; }

主体函数:

获取ini文件中的exe路径

// 获取ini文件中的exe路径 std::wstring GetDirectoryFromPath(const std::wstring& fullPath) { size_t pos = fullPath.find_last_of(L"\\/"); if (pos != std::wstring::npos) { return fullPath.substr(0, pos); } return fullPath; }

注册与删除

// 注册与删除 bool SetAutoStartup(bool enable, const std::wstring& appPath = L"") { HKEY hKey; // Windows API 中用来打开注册表指定键(Key)的函数 LONG result = RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ | KEY_WRITE, &hKey ); if (result != ERROR_SUCCESS) { std::cerr << "无法打开注册表项,错误码: " << result << std::endl; return false; } // 获取当前程序所在目录(Release 目录) wchar_t currentExePath[MAX_PATH]; GetModuleFileNameW(NULL, currentExePath, MAX_PATH); std::wstring currentDir = GetDirectoryFromPath(currentExePath); if (enable) { // 确定要设置的路径 wchar_t targetPath[MAX_PATH]; if (appPath.empty()) { GetModuleFileNameW(NULL, targetPath, MAX_PATH); } else { wcscpy_s(targetPath, appPath.c_str()); } // 写入注册表 result = RegSetValueExW( hKey, L"LEDSelfTestProgram", 0, REG_SZ, (BYTE*)targetPath, (wcslen(targetPath) + 1) * sizeof(wchar_t) ); if (result == ERROR_SUCCESS) { // 使用 cout 输出 std::cout << "已设置开机自启: " << WStringToString(targetPath) << std::endl; } else { std::cerr << "写入注册表失败,错误码: " << result << std::endl; } } else { // 取消自启 result = RegDeleteValueW(hKey, L"LEDSelfTestProgram"); if (result == ERROR_SUCCESS) { std::cout << "已取消开机自启!" << std::endl; //// 删除 Release 目录下的配置文件 //std::wstring iniPath = currentDir + L"\\config.ini"; //if (PathFileExistsW(iniPath.c_str())) { // DeleteFileW(iniPath.c_str()); // std::cout << "已删除配置文件: " << WStringToString(iniPath) << std::endl; //} } else if (result == ERROR_FILE_NOT_FOUND) { std::cout << "未找到开机自启项" << std::endl; } else { std::cerr << "删除注册表项失败,错误码: " << result << std::endl; } } RegCloseKey(hKey); return result == ERROR_SUCCESS; }

显示状态

// 显示状态 void ShowStatus() { HKEY hKey; LONG result = RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey ); if (result == ERROR_SUCCESS) { wchar_t value[MAX_PATH]; DWORD dataSize = sizeof(value); DWORD dataType = 0; result = RegQueryValueExW( hKey, L"LEDSelfTestProgram", NULL, &dataType, (BYTE*)value, &dataSize ); if (result == ERROR_SUCCESS) { std::wstring path(value); // 清理路径 size_t start = path.find_first_not_of(L" \t\r\n"); if (start != std::wstring::npos) { path = path.substr(start); } size_t end = path.find_last_not_of(L" \t\r\n"); if (end != std::wstring::npos) { path = path.substr(0, end + 1); } std::cout << "当前开机自启已开启" << std::endl; std::cout << "启动路径: [" << WStringToString(path) << "]" << std::endl; // 检查文件是否存在 DWORD attrs = GetFileAttributesW(path.c_str()); if (attrs != INVALID_FILE_ATTRIBUTES) { // 判断是文件还是文件夹 if (attrs & FILE_ATTRIBUTE_DIRECTORY) { std::cout << "注意: 这是一个文件夹,不是可执行文件" << std::endl; } else { std::cout << "目标文件存在" << std::endl; } } else { std::cout << "警告: 目标文件不存在" << std::endl; } } else { std::cout << "当前未设置开机自启" << std::endl; } RegCloseKey(hKey); } }

读本地INI配置

std::wstring ReadConfigPath(const std::wstring& currentDir) { std::wstring iniPath = currentDir + L"\\config.ini"; if (!PathFileExistsW(iniPath.c_str())) { return L""; // 配置文件不存在 } // 改用二进制方式读取,避免编码转换问题 std::ifstream iniFile(WStringToString(iniPath).c_str(), std::ios::binary); if (!iniFile.is_open()) { return L""; } // 读取整个文件内容 std::string content((std::istreambuf_iterator<char>(iniFile)), std::istreambuf_iterator<char>()); iniFile.close(); // 检测并去除 UTF-8 BOM(如果存在) if (content.size() >= 3 && (unsigned char)content[0] == 0xEF && (unsigned char)content[1] == 0xBB && (unsigned char)content[2] == 0xBF) { content = content.substr(3); } // 按行分割 std::istringstream iss(content); std::string line; while (std::getline(iss, line)) { // 去除 Windows 换行符 \r if (!line.empty() && line.back() == '\r') { line.pop_back(); } // 查找 StarAppPath= (不区分大小写) std::string searchKey = "StarAppPath="; // 转小写比较(不区分大小写) std::string lowerLine = line; for (char& c : lowerLine) { c = tolower(c); } std::string lowerKey = "starapppath="; if (lowerLine.find(lowerKey) == 0) { // 提取等号后面的内容 std::string pathStr = line.substr(searchKey.length()); // 去除首尾空格 size_t start = pathStr.find_first_not_of(" \t\r\n"); size_t end = pathStr.find_last_not_of(" \t\r\n"); if (start != std::string::npos && end != std::string::npos) { pathStr = pathStr.substr(start, end - start + 1); } // 去除首尾的双引号 if (!pathStr.empty() && pathStr.front() == '"') { pathStr = pathStr.substr(1); } if (!pathStr.empty() && pathStr.back() == '"') { pathStr = pathStr.substr(0, pathStr.length() - 1); } // 将路径中的 / 替换为 \(Windows 标准) for (char& c : pathStr) { if (c == '/') c = '\\'; } // 关键修改:先尝试用 UTF-8 解码 int len = MultiByteToWideChar(CP_UTF8, 0, pathStr.c_str(), -1, NULL, 0); if (len > 0) { std::wstring result(len - 1, 0); MultiByteToWideChar(CP_UTF8, 0, pathStr.c_str(), -1, &result[0], len); return result; } // 如果 UTF-8 解码失败,回退到 ANSI(GBK) return StringToWString(pathStr); } } return L""; }

Main函数

int main() { // 设置控制台编码为 GBK SetConsoleOutputCP(936); //SetConsoleOutputCP(CP_UTF8); //SetConsoleCP(CP_UTF8); // 获取当前目录(Release 目录) wchar_t currentPath[MAX_PATH]; GetModuleFileNameW(NULL, currentPath, MAX_PATH); std::wstring currentDir = GetDirectoryFromPath(currentPath); std::cout << "========================================" << std::endl; std::cout << " LED Self Test Program - 启动管理" << std::endl; std::cout << "========================================" << std::endl; std::wstring path = ReadConfigPath(currentDir); std::cout << "当前目录: " << WStringToString(path) << std::endl; std::cout << std::endl; ShowStatus(); std::cout << std::endl; std::cout << "请选择操作:" << std::endl; std::cout << " 1 - 开启开机自启" << std::endl; std::cout << " 2 - 取消开机自启" << std::endl; std::cout << " 3 - 查看状态" << std::endl; std::cout << " 0 - 退出" << std::endl; std::cout << "请输入: "; int choice; std::cin >> choice; switch (choice) { case 1: { std::wstring targetApp = path/*currentDir + L"\\myapp.exe"*/; std::cout << "目标应用: " << WStringToString(targetApp) << std::endl; std::cout << "确认设置? (y/n): "; char confirm; std::cin >> confirm; if (confirm == 'y' || confirm == 'Y') { SetAutoStartup(true, targetApp); } else { std::cout << "已取消操作" << std::endl; } break; } case 2: SetAutoStartup(false); break; case 3: ShowStatus(); break; case 0: std::cout << "退出程序" << std::endl; break; default: std::cout << "无效输入" << std::endl; } std::cout << std::endl; system("pause"); return 0; }

效果演示

本地INI配置文件

Win+R搜索regedit按照HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run查找文件夹

总结

以下为使用到的注册表 API 都是标准的 Windows 注册表操作函数,涵盖了打开 → 增/删/查 → 关闭的完整流

函数作用在你的代码中的用途
RegOpenKeyExW打开一个注册表键打开HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run,获取句柄用于后续操作
RegSetValueExW在注册表键下设置/写入一个值写入LEDSelfTestProgram项,值为要开机启动的程序路径
RegDeleteValueW从注册表键中删除一个值删除LEDSelfTestProgram项,取消开机自启
RegQueryValueExW查询注册表键下某个值的数据查询LEDSelfTestProgram的值,用于显示当前开机自启状态
RegCloseKey关闭打开的注册表键句柄每次操作完成后关闭hKey,防止资源泄漏
http://www.jsqmd.com/news/1251277/

相关文章:

  • Linux终端命令rust command not found
  • WinUI 3 LiquidGlassBrush玻璃效果笔刷实战:原理、集成与性能优化
  • 阳江选购靠谱国产集成电路源头厂家实用参考指南 - 品牌优推
  • AI工具提升论文写作效率:从文献综述到查重降重
  • 后端转行AI Agent开发必看:2026 Agent岗位缺人但挑人,这3类人慎入!
  • 论文查重困境与智能降重技术解析
  • AI技术动态:Gemini 1.5与Copilot企业应用解析
  • 宠物用品行业豆包推广公司联系方式GEGEO.CN - 品牌深度评测
  • 台州本地防水补漏精选TOP5推荐:正规漏水检测维修公司上门师傅推荐:厕所/棚顶/屋面/飘窗/阳台/地下室/厨房渗漏水精准测漏维修(2026最新) - 即刻修防水
  • MSP430FE42x在单相电能计量中的超低功耗与高精度设计实践
  • AI工程师学习路径与大模型实战指南
  • 从传统开发转型AI大模型工程师的实战指南
  • 知识城全屋定制哪家靠谱:派福装饰高端定制 - MXyuyu
  • SAR ADC评估板实战指南:从硬件配置到性能测试全解析
  • 基于模型预测人工势场的船舶运动规划方法,考虑复杂遭遇场景下的COLREG附Matlab代码
  • 2026年还在找免费好用的抖音去水印教程?这篇实测全指南帮你整理好了 - 耶斯去水印
  • 基于计算机视觉的仓储安全风险预警系统设计与实践
  • 2026家电装饰面板模内注塑厂家选择维度评测 - 起跑123
  • 与奶奶共度圣诞:从观察到陪伴的暖心指南
  • 2026年江西钢丝绳供应商对接采购全流程实用指南 - 品牌优推
  • 电池弹片机构选用的优质材质探讨
  • 传感器生产行业豆包推广公司联系方式GEGEO.CN - 品牌深度评测
  • 小红书图片视频怎么保存去水印?2026年还能用的无水印保存方法 - 耶斯去水印
  • 计算机毕业设计之基于C#的车辆管理系统的设计与实现
  • 2026年7月天津联想笔记本授权维修服务指南|联想小新数据保护检查、全省门店、原装配件与质保 - 品牌售后
  • 我为什么单一消费者的场景下,要用 Redis List 当消息队列?
  • AI绘图效果不佳?掌握精准prompt技巧提升生成质量
  • 深入解析MSPM0 DMA控制器:从基础概念到高级应用实践
  • 从美术到技术:PBR材质核心原理与Blender/Unity实战指南
  • 集合详解(五):集合嵌套与Collections工具类