posted at 2023.9.20 10:37 by Administrator
实现开机自启动的途径和方式很多,其中修改注册表方式应用最为广泛。还包括快速启动目录、计划任务以及系统服务等。
三、计划任务
Windows系统可以设置计划任务来执行一些定时任务。计划任务的触发条件可以为在用户登录时触发,执行启动指定路径程序的操作,从而实现开机自启动。
对于用户来说,手动创建计划任务并不复杂,但是编程实现添加计划任务还是略微复杂些。使用Windows Shell编程实现创建计划任务时,会涉及COM组件接口的调用。同时要注意的是创建计划任务要求具有管理员权限。
四、系统服务
打开计算机上的任务管理器,可以发现有许多系统服务进程在后台运行,而且大多数的系统服务进程都是随着系统启动而启动的,如svchost.exe进程。
系统服务运行在SESSION 0,由于系统服务的SESSION 0隔离,隔断了系统服务和用户桌面进程之间进行交互和通信的桥梁,因此,系统服务一般不显示程序界面。
系统进程自启动是通过创建系统服务并设置服务启动类型为自动启动来实现的。接下来就介绍创建系统服务进程的原理和实现。
实现原理
创建自启动系统服务进程分成两部分,一部分是创建启动系统服务,另一部分是系统服务程序的编写。每个部分都开发成一个独立的小程序,以实现相应的功能。
创建启动系统服务:
首先通过OpenSCManager函数打开服务控制管理器数据库并获取数据库的句柄。
若要创建服务 ,则调用CreateService开始创建服务,指明创建的服务类型是SERVICE_WIN32_OWN_PROCESS系统服务,同时设置SERVICE_AUTO_START为开机自启动;若是其他操作,则调用OpenService 打开服务,获取服务句柄。
接着根据服务句柄考虑以下操作:启动、停止和删除服务。
最后,关闭服务句柄和服务控制管理器数据库句柄。
代码如下:
#include"stdafx.h"
#include"ServiceOperate.h"
int_tmain(intargc, _TCHAR* argv[]){ BOOL bRet = FALSE; char szFileName[MAX_PATH] = "C:\\Users\\feng\\ServiceTest.exe"; // 创建并启动服务 bRet = SystemServiceOperate(szFileName, 0); if (FALSE == bRet) { printf("Create Error!\n"); } bRet = SystemServiceOperate(szFileName, 1); if (FALSE == bRet) { printf("Start Error!\n"); } printf("Create and Start OK.\n"); system("pause"); // 停止并删除服务 bRet = SystemServiceOperate(szFileName, 2); if (FALSE == bRet) { printf("Stop Error!\n"); } bRet = SystemServiceOperate(szFileName, 3); if (FALSE == bRet) { printf("Delete Error!\n"); } printf("Stop and Delete OK.\n"); system("pause"); return 0;} void ShowError(char *lpszText){ char szErr[MAX_PATH] = { 0 }; ::wsprintf(szErr, "%s Error!\nError Code Is:%d\n", lpszText, ::GetLastError());#ifdef_DEBUG ::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR);#endif} // 0 加载服务 1 启动服务 2 停止服务 3 删除服务BOOL SystemServiceOperate(char *lpszDriverPath, intiOperateType){ BOOL bRet = TRUE; char 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) { ShowError("OpenSCManager"); returnFALSE; } if (0 != iOperateType) { // 打开一个已经存在的服务 shCS = OpenService(shOSCM, szName, SERVICE_ALL_ACCESS); if (!shCS) { ShowError("OpenService"); ::CloseServiceHandle(shOSCM); shOSCM = NULL; returnFALSE; } } switch (iOperateType) { case 0: { // 创建服务 // SERVICE_AUTO_START 随系统自动启动 // SERVICE_DEMAND_START 手动启动 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) { ShowError("CreateService"); bRet = FALSE; } break; } case 1: { // 启动服务 if (!::StartService(shCS, 0, NULL)) { ShowError("StartService"); bRet = FALSE; } break; } case 2: { // 停止服务 if (!::ControlService(shCS, SERVICE_CONTROL_STOP, &ss)) { ShowError("ControlService"); bRet = FALSE; } break; } case 3: { // 删除服务 if (!::DeleteService(shCS)) { ShowError("DeleteService"); bRet = FALSE; } break; } default: break; } // 关闭句柄 if (shCS) { ::CloseServiceHandle(shCS); shCS = NULL; } if (shOSCM) { ::CloseServiceHandle(shOSCM); shOSCM = NULL; } return bRet;}系统服务程序 的编写:自启动服务程序并不是普通的程序,而是要求程序创建服务入口点函数,否则,不能创建系统服务。创建系统服务的流程如下所示。
调用系统函数StartServiceCtrlDispatcher将程序主线程连接到服务控制管理程序(其中定义了服务入口函数是ServiceMain)。服务控制管理程序启动服务程序后,等待服务程序主函数调用StartServiceCtrlDispatcher函数。没有调用,则报错。
执行服务初始化任务,然后设定运行状态,接着运行服务代码。
代码如下:
#include"stdafx.h"#include<Windows.h>// 服务入口函数以及处理回调函数void__stdcall ServiceMain(DWORD dwArgc, char *lpszArgv);void__stdcall ServiceCtrlHandle(DWORD dwOperateCode);BOOL TellSCM(DWORD dwState, DWORD dwExitCode, DWORD dwProgress);void DoTask(); // 全局变量char g_szServiceName[MAX_PATH] = "ServiceTest.exe"; // 服务名称SERVICE_STATUS_HANDLE g_ServiceStatusHandle = { 0 }; int_tmain(intargc, _TCHAR* argv[]){ // 注册服务入口函数 SERVICE_TABLE_ENTRY stDispatchTable[] = { { g_szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL } }; ::StartServiceCtrlDispatcher(stDispatchTable); return 0;} void__stdcall ServiceMain(DWORDdwArgc, char *lpszArgv){ g_ServiceStatusHandle = ::RegisterServiceCtrlHandler(g_szServiceName, ServiceCtrlHandle); TellSCM(SERVICE_START_PENDING, 0, 1); TellSCM(SERVICE_RUNNING, 0, 0); // 自己程序实现部分代码放在这里 // !!注意!! 此处一定要为死循环, 否则在关机再开机的情况(不是点击重启), 不能创建用户进程 while (TRUE) { Sleep(5000); DoTask(); }} void__stdcall ServiceCtrlHandle(DWORDdwOperateCode){ switch (dwOperateCode) { caseSERVICE_CONTROL_PAUSE: { // 暂停 TellSCM(SERVICE_PAUSE_PENDING, 0, 1); TellSCM(SERVICE_PAUSED, 0, 0); break; } caseSERVICE_CONTROL_CONTINUE: { // 继续 TellSCM(SERVICE_CONTINUE_PENDING, 0, 1); TellSCM(SERVICE_RUNNING, 0, 0); break; } caseSERVICE_CONTROL_STOP: { // 停止 TellSCM(SERVICE_STOP_PENDING, 0, 1); TellSCM(SERVICE_STOPPED, 0, 0); break; } caseSERVICE_CONTROL_INTERROGATE: { // 询问 break; } default: break; }} BOOL TellSCM(DWORDdwState, DWORDdwExitCode, DWORDdwProgress){ SERVICE_STATUS serviceStatus = { 0 }; BOOL bRet = FALSE; ::RtlZeroMemory(&serviceStatus, sizeof(serviceStatus)); serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState = dwState; serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode = dwExitCode; serviceStatus.dwWaitHint = 3000; bRet = ::SetServiceStatus(g_ServiceStatusHandle, &serviceStatus); return bRet;} void DoTask(){ // 自己程序实现部分代码放在这里} 测试效果图
以管理员身份运行系统服务创建启动程序AutoRun_Service_Test.exe,创建完成后,打开任务管理器详细信息,发现“ServiceTest.exe”服务成功创建。
关机重启计算机,然后打开服务管理器查看服务列表,发现“ServiceTest.exe”系统服务进程成功实现开机自启动。
fe413f4c-f088-45c6-adb7-e20158b1d176|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: 程序, 代码, 接口, 类, 数据
IT技术