WindowsAPI编程核心技术-自启动技术

注册表

RegOpenKeyEx

打开注册表键。

1
2
3
4
5
6
7
8
9
10
11
12
LONG WINAPI RegOpenKeyEx(
_In_ HKEY hKey,
//这些键:HKEY_CLASSES_ROOT HKEY_CURRENT_USER HKEY_LOVAL_MACHINE HKEY_USERS HEY_CURRENT_CONFIG
_In_opt_ LPCTSTR lpSubKey,
//要打开键的名称 NULL则打开新的句柄由hKey决定
_In_ DWORD ulOptions,
//保留 必须0
_In_ REGSAM samDesired,
//希望得到的访问权限 自己去查
_Out_ PHKEY phkResult
//打开注册表键的句柄
)//成功返回ERROR_SUCCESS=0 否则返回WINERROR.h中非零值

RegSetValueEx

设置指定值的数据或类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
LONG WINAPI RegSetValueEx(
_In_ HKEY hKey,
_In_opt_ LPCTSTR lpValueName,
//欲设置值 不存在则新建 NULL设置为默认值或未命名
_Reserved_ DWORD Reserved,
//保留 必须0
_In_ DWORD dwType,
//将存储的数据类型 值自己查
_In_ const BYTE *lpData,
//指向缓冲区 包含为指定值名称存储的数据
_In_ DWORD cbData
//lpData指向数据大小
)//成功0 否则错误代码

例子

两个开机自启动的注册表路径:

1
2
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run

第二个想修改必须得管理员权限,第一个用户默认权限就行。

x64下为了兼容x86的正常运行,第二个可能会被重定位到这个路径:

1
HEKY_LOVAL_MACHINE\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run

但是在RegOpenKeyEx中设置KEY_WOW64_64KEY选项就问题不大。

1
2
3
4
5
6
7
8
9
10
11
BOOL Reg_CurrentUser(WCHAR* lpszFileName, WCHAR* lpszValueName) {
HKEY hKey;
if (ERROR_SUCCESS != ::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_WRITE, &hKey))
return FALSE;
if (ERROR_SUCCESS != ::RegSetValueEx(hKey, lpszValueName, 0, REG_SZ, (BYTE*)lpszFileName, (1 + ::lstrlen(lpszFileName)))) {
::RegCloseKey(hKey);
return FALSE;
};
::RegCloseKey(hKey);
return TRUE;
};

快速启动目录

SHGetSpecialFolderPath

获取指定的系统路径。

1
2
3
4
5
6
7
8
9
10
BOOL SHGetSpecialFolder(
_In_ HWND hwndOwner,
//窗口所有者句柄
_In_? LPTSTR lpszPath,
//返回路径的缓冲区
_In_ int nFolder,
//系统路径的CSIDL标识
_In_ BOOL fCreate
//文件夹不存在时是否创建 TRUE创建
)//成功TRUE

例子

系统每次启动的快速启动文件夹可能都不一样,需要用SHGetSpecialFolder来获得。把要启动的程序直接CopyFile过去,或者快捷方式也行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <ShlObj.h>
#include <cstdio>
BOOL AutoRun_StartUp(WCHAR* lpszSrcFilePath, WCHAR* lpszDestFileName) {
BOOL bRet = FALSE;
WCHAR szStartupPath[MAX_PATH] = { 0 };
WCHAR szDestFilePath[MAX_PATH] = { 0 };
bRet = ::SHGetSpecialFolderPath(NULL, szStartupPath, CSIDL_STARTUP, TRUE);
printf("%s\n", szStartupPath);
if (FALSE == bRet)
return FALSE;
::wsprintf(szDestFilePath, L"%s\\%s", szStartupPath, lpszDestFileName);
bRet = ::CopyFile(lpszSrcFilePath, szDestFilePath, FALSE);
if (FALSE == bRet)
return FALSE;
return TRUE;
};

计划任务

涉及COM组件,太复杂了,略。

系统服务

OpenSCManager

建立一个到服务控制管理器的连接,并打开指定的数据库。

1
2
3
4
5
6
7
8
SC_HANDLE OpenSCManager(
_In_ LPCTSTR lpMachineName,
//目标计算机名称 空字符串为连接到本地计算机的服务控制管理器
_In_ LPSTSTR lpDatabaseName,
//要打开的服务控制管理数据库的名称 SERVICE_ACTIVE_DATABASE
_In_ DWORD dwDesiredAccess
//指定服务访问控制管理器的权限
)//成功返回服务控制管理器数据库的句柄 失败NULL

CreateService

创建一个服务对象,并添加到指定服务控制管理器数据库中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SC_HANDLE CreateService(
_In_ SC_HANDLE hSCManager,
//指向服务控制管理器数据库的句柄
_In_ LPCTSTR lpServiceName,
//要安装服务的名称
_In_ LPCTSTR lpDisplayName,
//用户界面程序用来标识服务的显示名称
_In_ DWORD dwDesiredAccess,
//对服务的访问
_In_ DWORD dwServiceType,
//服务类型 有枚举值
_In_ DWORD dwStartType,
//服务启动选项 有枚举值
_In_ DWORD dwErrorControl,
//服务启动失败时 指定产生错误的严重程度即应采取的保护措施
_In_ LPCTSTR lpBinaryPathName,
//服务程序的二进制文件
_In_ LPCTSTR lpLoadOrderGroup,
//指向加载排序组的名称
_In_ LPCTSTR lpdwTagId,
//由lpLoadOrderGroup参数指定的组中唯一的标记值变量
_In_ LPCTSTR lpDependencies,
//依赖关系
_In_ LPCTSTR lpServiceStartName,
//应运行的账户名称
_In_ LPCTSTR lpPassword
//lpServiceStartName指定的账户密码
)//成功返回该服务句柄 失败NULL

OpenService

打开一个已经存在的服务。

1
2
3
4
5
6
7
8
SC_HANDLE WINAPI OpenService(
_In_ SC_HANDLE hSCManager,
//SCM数据库句柄
_In_ LPCTSTR lpServiceName,
//服务名称
_In_ DWORD dwDesiredAccess
//权限
)//成功返回句柄 失败NULL

StartService

启动服务

1
2
3
4
5
6
7
8
BOOL WINAPI StartService(
_In_ SC_HANDLE hService,
//句柄
_In_ DWORD dwNumServiceArgs,
//lpServiceArgVectors字符串个数
_In_opt_ LPCTSTR* lpServiceArgVectors
//传参 没有NULL
)//成功非0 失败0

StartServiceCtrlDispatcher

服务进程主线程连接到服务控制管理器,将该线程作为调用过程的服务控制分派器线程。

1
2
3
4
BOOL WINAPI StartServiceCtrlDispatcher(
_In_ const SERVICE_TABLE_ENTRY* lpServiceTable
//可在调用进程中执行的每个服务的条目
)//成功非0 失败0

例子

创建自启动系统服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<shlwapi.h>
BOOL SystemServiceOperate(WCHAR* lpszDriverPath, int iOperateType) {
BOOL bRet = TRUE;
WCHAR szName[MAX_PATH] = { 0 };
::lstrcpy(szName, lpszDriverPath);
::PathStripPath(szName); //过滤文件目录 只留下文件名
SC_HANDLE shOSCM = NULL, shCS = NULL;
SERVICE_STATUS ss;
DWORD dwErrorCode = 0;
BOOL bSuccess = FALSE;
shOSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!shOSCM)
return FALSE;
if (0 != iOperateType) { //打开一个已经存在的服务
shCS = OpenService(shOSCM, szName, SERVICE_ALL_ACCESS);
if (!shCS) {
::CloseServiceHandle(shOSCM);
shOSCM = NULL;
return FALSE;
};
};
switch (iOperateType) {
case 0: { //创建服务
shCS = ::CreateService(shOSCM, szName, szName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, lpszDriverPath, NULL, NULL, NULL, NULL, NULL);
if (!shCS)
bRet = FALSE;
break;
};
case 1: { //启动服务
if (!::StartService(shCS, 0, NULL))
bRet = FALSE;
break;
};
case 2: { //停止服务
if (!::ControlService(shCS, SERVICE_CONTROL_STOP, &ss))
bRet = FALSE;
break;
};
case 3: { //删除服务
if (!::DeleteService(shCS))
bRet = FALSE;
break;
};
default:
break;
};
if (shCS) {
::CloseServiceHandle(shCS);
shCS = NULL;
};
if (shOSCM) {
::CloseServiceHandle(shOSCM);
shOSCM = NULL;
};
return bRet;
};

系统服务程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<tchar.h>
WCHAR g_szServiceName[MAX_PATH] = { 0 };
SERVICE_STATUS_HANDLE g_ServiceStatusHandle;
void CALLBACK ServiceCtrlHandle(DWORD request) {
//...
return;
};
void WINAPI ServiceMain(DWORD dwArgc, char* lpszArgv) {
g_ServiceStatusHandle = ::RegisterServiceCtrlHandler(g_szServiceName, ServiceCtrlHandle);
//...
};
int _tmain(int argc, _TCHAR* argv[]) {
SERVICE_TABLE_ENTRY stDispatchTable[] = {
{g_szServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL,NULL}
};
::StartServiceCtrlDispatcher(stDispatchTable);
return 0;
};