模仿网易云切歌时候MAC的通知界面,需要用到开机自启的功能。但是只有写入的方法,没找到加入其他方法做成一整个类的。所以花了些时间把这功能包装成一个类了
教程被应用在MediaStateT中
MediaStateT Github项目地址: https://github.com/taxue-alfred/MediaStateT
MediaStateT Gitee项目地址: https://gitee.com/MediaState/MediaStateT
对这个类进行一些说明:
- 类中的每一个方法都可以单独拿来使用,不受类中定义的变量影响
构造函数除外
-
类中的部分方法我已经标明了参考的网址,如果想要进行学习的话可以去详细学习
-
类中部分方法有这比较详细的注释,供大家参考
-
构造函数中"MediaStateT"是我的项目名称。项目地址如上
核心代码讲解
- 这里其实就是通过
GetMouleFileName
来获取当前程序运行的地址
std::string get_programme_path() {
TCHAR buffer[512] = {0};
GetModuleFileName(nullptr, buffer, sizeof(buffer));
//TCHAR转string
//参考:https://www.cnblogs.com/staring-hxs/archive/2013/01/24/2874690.html
UINT len = wcslen(buffer)*2;
char *buf = (char *)malloc(len);
UINT i = wcstombs(buf,buffer,len);
std::string full_path = buf;
return full_path;
}
- 获取到当前程序运行的地址之后,加上程序的名称就可添加到自启动注册表了,对于不需要管理员权限的程序来讲,我们需要注册到
HKEY_CURRENT_USER
下的
SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run
这个路径当中,不然会提示需要管理员权限
对于以上的函数实现:
这里用到的stringToPCWSTR函数下面的全部代码有些,这里为了讲述明白不再赘述
bool tart_with_system(const std::string &name, const std::string &full_path) {
if (name_w == NULL){
//string转LPCWSTR
stringToLPCWSTR(name, name_w);
std::cout << "hello";
stringToLPCWSTR(full_path, path_w);
}
//打开启动项
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS){
//判断注册表项目是否存在
TCHAR strDir[MAX_PATH] = {};
DWORD nLength = MAX_PATH;
// If the function succeeds, the return value is ERROR_SUCCESS.
// 函数解释:https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluea
long result = RegGetValue(hkey, nullptr, name_w, RRF_RT_REG_SZ, 0, strDir, &nLength);
//注册表已经存在
if (result != ERROR_SUCCESS) {
//添加一个Key
RegSetValueEx(hkey, name_w, 0, REG_SZ, (LPBYTE)path_w,
(strlen(full_path.c_str()) + 1) * sizeof(TCHAR));
//关闭注册表
RegCloseKey(hkey);
return true;
}else{
std::cout << "StartWithSystem: Have been created!" << std::endl;
return false;
}
}
else{
std::cout << "StartWithSystem: Can`t open the Reg!" << std::endl;
return false;
}
}
-
然后就是对于状态的检测,其实上面的代码已经状态检测的代码了,这里不在赘述,下面的源代码部分会有具体方法实现
-
最后就是删除注册表代码的实现:
这里只需要知道程序的名称就可以了
bool remove_sws(const std::string &name) {
if (name_w == NULL){
//string转LPCWSTR
stringToLPCWSTR(name, name_w);
}
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS){
RegDeleteValue(hkey, name_w);
RegCloseKey(hkey);
return true;
}else{
return false;
}
}
代码参考(可直接复制使用):
代码虽然看起来比较长,但不难。好多都是注释和为了代码阅读的缩进
StartWithSystem.h
//
// Created by Txwh on 2022/1/12.
//
#include <windows.h>
#include <iostream>
#include <stringapiset.h>
class StartWithSystem {
private:
HKEY hkey;
public:
std::string programme_full_path;
//PCWCHAR 是 WCHAR的指针,这里是为了防止内存泄露而不用new
//所以选择新建非指针变量
WCHAR name_w[512];
WCHAR path_w[512];
public:
StartWithSystem();
/**
* @brief: string 转 LPCWSTR
* @param: 被转换string
* @param: 存储WCHAR的变量
* @note: PCWCHAR是WCHAR的指针
* **/
void stringToLPCWSTR(const std::string &converse_str, PCWCHAR out);
/**
* @brief: 获取当前程序运行的绝对路径
* @return: 返回绝对路径
* **/
std::string get_programme_path();
/**
* @brief: 添加开机自启项目
* @param: 开机项目的名称
* @param: 开机项目的绝对路径
**/
bool start_with_system(const std::string &name, const std::string &full_path);
/**
* @brief: 检测给定程序名称是否在注册表中
* @param: 开机项目名称
* @param: 开机项目的绝对路径
**/
bool sws_statue(const std::string &name, const std::string &full_path);
/**
* @brief: 移除开机自启项
* @param: 开机项目的名称
* **/
bool remove_sws(const std::string &name);
/**
* @brief: 用来设置当前工作目录,解决自动启动导致的工作目录不对的问题
* @param: 开机项目的绝对路径
**/
void SetWorkDirectory(std::string & full_path);
};
StartWithSystem.cpp
//
// Created by Txwh on 2022/1/12.
//
#include "StartWithSystem.h"
StartWithSystem::StartWithSystem() {
hkey = NULL;
programme_full_path = get_programme_path();
//string转LPCWSTR
stringToLPCWSTR("MediaStateT", name_w);
stringToLPCWSTR(programme_full_path, path_w);
SetWorkDirectory(programme_full_path);
}
std::string StartWithSystem::get_programme_path() {
TCHAR buffer[512] = {0};
GetModuleFileName(nullptr, buffer, sizeof(buffer));
//TCHAR转string
//参考:https://www.cnblogs.com/staring-hxs/archive/2013/01/24/2874690.html
UINT len = wcslen(buffer)*2;
char *buf = (char *)malloc(len);
UINT i = wcstombs(buf,buffer,len);
std::string full_path = buf;
return full_path;
}
void StartWithSystem::stringToLPCWSTR(const std::string &converse_str, PCWCHAR out) {
// 参考:https://blog.youkuaiyun.com/wangshubo1989/article/details/50274103
wchar_t * buffer = new wchar_t[converse_str.size()+1];
MultiByteToWideChar(CP_ACP, 0, converse_str.c_str(),
converse_str.size(), buffer,
converse_str.size() * sizeof(wchar_t));
buffer[converse_str.size()] = 0;
//宽字符一个字体两个字节
memcpy((void *)out, (void *)buffer, (converse_str.size()+1)*sizeof(wchar_t));
delete [] buffer;
}
bool StartWithSystem::start_with_system(const std::string &name, const std::string &full_path) {
if (name_w == NULL){
//string转LPCWSTR
stringToLPCWSTR(name, name_w);
std::cout << "hello";
stringToLPCWSTR(full_path, path_w);
}
//打开启动项
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS){
//判断注册表项目是否存在
TCHAR strDir[MAX_PATH] = {};
DWORD nLength = MAX_PATH;
// If the function succeeds, the return value is ERROR_SUCCESS.
// 函数解释:https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluea
long result = RegGetValue(hkey, nullptr, name_w, RRF_RT_REG_SZ, 0, strDir, &nLength);
//注册表已经存在
if (result != ERROR_SUCCESS) {
//添加一个Key
RegSetValueEx(hkey, name_w, 0, REG_SZ, (LPBYTE)path_w,
(strlen(full_path.c_str()) + 1) * sizeof(TCHAR));
//关闭注册表
RegCloseKey(hkey);
return true;
}else{
std::cout << "StartWithSystem: Have been created!" << std::endl;
return false;
}
}
else{
std::cout << "StartWithSystem: Can`t open the Reg!" << std::endl;
return false;
}
}
bool StartWithSystem::sws_statue(const std::string &name, const std::string &full_path) {
if (name_w == NULL){
//string转LPCWSTR
stringToLPCWSTR(name, name_w);
stringToLPCWSTR(full_path, path_w);
}
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS){
//判断注册表项目是否存在
TCHAR strDir[MAX_PATH] = {};
DWORD nLength = MAX_PATH;
// If the function succeeds, the return value is ERROR_SUCCESS.
long result = RegGetValue(hkey, nullptr, name_w, RRF_RT_REG_SZ, 0, strDir, &nLength);
//注册表已经存在
if (result != ERROR_SUCCESS) {
return false;
}else{
return true;
}
}
else{
std::cout << "StartWithSystem: Can`t open the Reg!" << std::endl;
return false;
}
}
bool StartWithSystem::remove_sws(const std::string &name) {
if (name_w == NULL){
//string转LPCWSTR
stringToLPCWSTR(name, name_w);
}
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS){
RegDeleteValue(hkey, name_w);
RegCloseKey(hkey);
return true;
}else{
return false;
}
}
void StartWithSystem::SetWorkDirectory(std::string & full_path) {
//参考:https://www.cxyzjd.com/article/qq_42987442/108831931
std::string workpath_c = full_path;
//删除最后的xxx.exe
std::string work_path = workpath_c.substr(0, workpath_c.find_last_of('\\'));
//设置工作目录
SetCurrentDirectoryA(work_path.c_str());
}