Windows服务(应用与驱动)编写实例(C语言)
References:
1.Windows服务基础知识 https://blog.csdn.net/Fei_Liu/article/details/72615202
2.Windows服务编程之服务程序 https://blog.csdn.net/Fei_Liu/article/details/73395233
3.编写Windows服务程序 https://www.jianshu.com/p/c9e8ca38510d
一、服务管理器
SCM(Service Control Manager)服务管理器是 Windows 操作系统中的一个关键组件,负责管理系统服务的启动、停止和配置。
服务是一种在后台运行的应用程序,可以在系统启动时自动启动,也可以由用户或其他应用程序手动启动。
win + r = 运行下 services.msc 来启动服务控制面板
二、服务程序
服务程序通常编写成控制台类型的应用程序,总的来说,一个遵守服务控制管理程序接口要求的程序
包含下面三个函数:
1.服务程序主(线程)函数(main):调用系统函数 StartServiceCtrlDispatcher 连接程序主线程到服务控制管理程序。
2.服务主(入口点)函数(ServiceMain):执行服务初始化任务,RegisterServiceCtrlHandler注册"服务控制函数",并获取当前程序的状态信息句柄。
3.服务控制消息处理函数(Handler):在服务程序收到控制请求时由控制分发线程引用。(此处是Service_Ctrl)
2.1 主线程
// 1.服务程序主(线程)函数(main):调用系统函数 StartServiceCtrlDispatcher 连接程序主线程到服务控制管理程序。 int main( int argc, char **argv ) { FILE *log; int homedir_temp_counter = 0; int homedir_temp_counter_2 = 0; char *homedir_temp; char argv_copy[MAX_LINE]; if( strlen( argv[0] ) >= MAX_LINE ) { log = fopen( LOGFILE, "a+" ); if( log != NULL ) { fprintf( log, "Command line argument too long, quitting...\n" ); fclose( log ); exit( -1 ); } } strncpy( argv_copy, argv[0], strlen(argv[0]) ); homedir_temp = strtok( argv[0], "\\" ); while( homedir_temp != NULL ) { homedir_temp_counter++; homedir_temp = strtok( NULL, "\\" ); } homedir_temp = strtok( argv_copy, "\\" ); while( homedir_temp_counter_2 < (homedir_temp_counter - 1) ) { strcat( homedir, homedir_temp ); strcat( homedir, "\\" ); homedir_temp = strtok( NULL, "\\" ); homedir_temp_counter_2++; } SetPriorityClass( GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS ); SetCurrentDirectory( homedir ); log = fopen( LOGFILE, "a+" ); if( log != NULL ) { fprintf( log, "SetCurrentDirectory = %s\n", homedir ); fclose( log ); } //SERVICE_TABLE_ENTRY "服务入口点"列表,每个入口点对应该进程中的一个"服务",每个入口点由其所对应的lpServiceName服务名称来标识 SERVICE_TABLE_ENTRY ServiceTable[2]; ServiceTable[0].lpServiceName = "MemoryStatus"; // 服务名字 ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; // 服务主函数 // 注意需要加上下面两行,因为StartServiceCtrlDispatcher规定最后一个元素必须为NULL ServiceTable[1].lpServiceName = NULL; ServiceTable[1].lpServiceProc = NULL; // Start the control dispatcher thread for our service // 连接程序主线程, 到SCM服务控制服务管理器 StartServiceCtrlDispatcher(ServiceTable); return 1; }
2.2 主服务
// 全局变量 // 程序最近的状态信息 SERVICE_STATUS ServiceStatus; // 当前程序的状态信息句柄 SERVICE_STATUS_HANDLE hStatus; /* meat and potatoes */ 2.服务主(入口点)函数(ServiceMain):执行服务初始化任务,RegisterServiceCtrlHandler注册"服务控制函数",并获取当前程序的状态信息句柄。 void ServiceMain(int argc, char** argv) { int error; FILE* log; // 下面填充当前服务的基本信息 ServiceStatus.dwServiceType = SERVICE_WIN32; // 服务类型 ServiceStatus.dwCurrentState = SERVICE_START_PENDING; // 服务状态:正在启动中 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; // 当前服务接收的控制有哪些 ServiceStatus.dwWin32ExitCode = 0; // 启动或停止时的服务错误码 ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; // 注册服务控制函数, 返回状态信息句柄 hStatus = RegisterServiceCtrlHandler( "MemoryStatus", (LPHANDLER_FUNCTION)ControlHandler); if (hStatus == (SERVICE_STATUS_HANDLE)0) { // Registering Control Handler failed return; } // Initialize Service error = InitService(); if (error) { // Initialization failed ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = -1; SetServiceStatus(hStatus, &ServiceStatus); return; } // We report the running status to SCM. // 将状态更改为running,即代表程序可以接收SCM发送的控制信息 ServiceStatus.dwCurrentState = SERVICE_RUNNING; // 反馈状态信息给SCM SetServiceStatus (hStatus, &ServiceStatus); // The worker loop of a service while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) { status = -1; log = fopen( LOGFILE, "a+" ); if( log != NULL ) { fprintf( log, "Status = %i\n", status ); fclose( log ); } // status is -1 at start, so every time this runs, force it to read config and status file if( status < 0 || status > 3 ) { init_scan(); } // perform recursive directory listing if( status == 0 ) { recurse_all_dirs(); } // whitelist files based on policy, sum file sizes and number of files if( status == 1 ) { whitelist(); } // grep for stuff if( status == 2 ) { search(); } // we are all done if( status == 3 ) { int upload_attempt = 1; WriteToLog( "Done with everything. Sending request to web server to uninstall us.\n" ); while( upload_stuff( status ) != 0 ) { upload_attempt++; Sleep( time_wait * 1000 ); log = fopen( LOGFILE, "a+" ); if( log != NULL ) { fprintf( log, "Done with everything. Sending request #%i to web server to uninstall us.\n", upload_attempt ); fclose( log ); } } } } return; }
2.3 主监控
3.服务监控(消息处理)函数(Handler):在服务程序收到控制请求时由控制分发线程引用。(此处是Service_Ctrl) void ControlHandler(DWORD request) { switch(request) { case SERVICE_CONTROL_STOP: // 服务停止 WriteToLog("OpenDLP service stopped.\n"); ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hStatus, &ServiceStatus); return; case SERVICE_CONTROL_SHUTDOWN: // 系统关机 WriteToLog("Monitoring service stopped.\n"); ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hStatus, &ServiceStatus); return; default: break; } // Report current status SetServiceStatus (hStatus, &ServiceStatus); return; }
三、 安装/卸载服务:
Refer:sc.exe create | Microsoft Learn
C:\Users\Administrator> sc create "DLP Agent" binpath=E:\workForClion\DLP_Agent\cmake-build-debug\DLP_Agent.exe
C:\Users\Administrator> sc delete "DLP Agent"
浙公网安备 33010602011771号