[C++][实用类库]C++开机自启方案

模仿网易云切歌时候MAC的通知界面,需要用到开机自启的功能。但是只有写入的方法,没找到加入其他方法做成一整个类的。所以花了些时间把这功能包装成一个类了

教程被应用在MediaStateT中

MediaStateT Github项目地址: https://github.com/taxue-alfred/MediaStateT

MediaStateT Gitee项目地址: https://gitee.com/MediaState/MediaStateT

对这个类进行一些说明:

  • 类中的每一个方法都可以单独拿来使用,不受类中定义的变量影响

构造函数除外

  • 类中的部分方法我已经标明了参考的网址,如果想要进行学习的话可以去详细学习

  • 类中部分方法有这比较详细的注释,供大家参考

  • 构造函数中"MediaStateT"是我的项目名称。项目地址如上

核心代码讲解
  1. 这里其实就是通过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;
}
  1. 获取到当前程序运行的地址之后,加上程序的名称就可添加到自启动注册表了,对于不需要管理员权限的程序来讲,我们需要注册到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;
       }
   }
  1. 然后就是对于状态的检测,其实上面的代码已经状态检测的代码了,这里不在赘述,下面的源代码部分会有具体方法实现

  2. 最后就是删除注册表代码的实现:

这里只需要知道程序的名称就可以了

   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.csdn.net/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());
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值