前言
通过代码将要开机自启动的应用的路径信息写入到本地注册表中,这样我的应用就可以在重启或者开机后,自动启动了。以下为代码演示:
头文件
#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,防止资源泄漏 |