• 实现:服务程序增删


    实现代码如下:自己的理解都在注释里面

    #include<windows.h>
    #include<stdio.h>
    
    #define SLEEP_TIME 5000
    #define LOG_FILE "c:\log.txt"
    
    void WINAPI ServiceMain(int argc, char *argv[]);
    void WINAPI CtrlHandler(DWORD request);
    bool WriteToLog(const char *mylog);
    bool ToInstallService();
    bool ToDeleteService();
    BOOL brun = FALSE;
    SERVICE_STATUS ServiceStatus;
    SERVICE_STATUS_HANDLE hStatus;
    
    int main(int argc,char *argv[]) {
    
    
    	if (argc == 2) {
    
    		if(strcmp(argv[1],"-install") == 0){
    			//相当于 打开SCM(Service Control Manager)-> 创建服务
    			ToInstallService();
    		}
    		else if (strcmp(argv[1], "-uninstall") == 0) {
    			// 相当于 打开SCM(Service Control Manager)-> 打开服务 -> 停止服务(如果正在运行) -> 删除服务
    			ToDeleteService();
    		}
    	}
    
    	//下面的逻辑为:启动分发器(连接到SCM) -> 注册服务控制处理器 -> 在控制处理器中对服务控制进行处理(通过SetServiceStatus反馈服务状态和设置接受的控制)
    
    	//下面的功能是实现创建分派表并调用进程的主线程来启动控制分派器
    	SERVICE_TABLE_ENTRY ServiceTable[2];
    	wchar_t mydemo[] = TEXT("mydemozz");
    	ServiceTable[0].lpServiceName = mydemo; //指向表示服务名称字符串的指针
    	ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;//指向服务主函数的指针(服务入口点)
    	ServiceTable[1].lpServiceName = NULL; //分派表的最后一项必须是服务名的NULL 指针
    	ServiceTable[1].lpServiceProc = NULL; //分派表的最后一项必须是服务主函数域的 NULL 指针
    	StartServiceCtrlDispatcher(ServiceTable);// 分派器启动新线程来运行分派表中每个服务的 ServiceMain 函数
    	
    	return 0;
    }
    
    void WINAPI ServiceMain(int argc,char * argv[]) { //这个函数就是工作函数,主要的处理都在这里面
    	ServiceStatus.dwServiceType = SERVICE_WIN32; //
    	ServiceStatus.dwCurrentState = SERVICE_PAUSE_PENDING; // 服务暂停正在等待中
    	ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; //只接受系统关机和停止服务两种控制命令
    	ServiceStatus.dwWin32ExitCode = 0;
    	ServiceStatus.dwServiceSpecificExitCode = 0;
    	ServiceStatus.dwCheckPoint = 0;
    	ServiceStatus.dwWaitHint = 0;
    
    	hStatus = ::RegisterServiceCtrlHandler(TEXT("mydemozz"), CtrlHandler); //注册CtrlHandler,CtrlHandler的功能是接收系统传递的控制命令,然后进行相应的处理
    	if (hStatus == 0) // 判断控制处理器是否注册成功
    	{
    		WriteToLog("RegisterServiceCtrlHandler Failed");
    		return;
    	}
    
    	WriteToLog("RegisterServiceCtrlHandler Success");
    	ServiceStatus.dwCurrentState = SERVICE_RUNNING; //到了这里的时候,该服务就是开始是准备运行了,那么状态就需要改成RUNNING
    	SetServiceStatus(hStatus, &ServiceStatus); //更新状态
    
    
    	//下面就开始任务循环了,你可以添加你自己希望服务做的工作
    	brun = true;
    	MEMORYSTATUS memstatus;
    	char str[100];
    	ZeroMemory(str, sizeof(str)); //清零str的内存地址
    	while (brun)
    	{
    		// 日志保存内存剩余大小
    		GlobalMemoryStatus(&memstatus);
    		int availmb = memstatus.dwAvailPhys / 1024 / 1024;
    		sprintf_s(str, 100, "available memory is %dMB", availmb);
    		WriteToLog(str);
    		Sleep(SLEEP_TIME); //每5秒进行更新一次
    	}
    
    }
    
    
    void WINAPI CtrlHandler(DWORD request){ // 运行期间CtrlHandler根据request参数来进行相应的处理
    	switch (request){
    		case SERVICE_CONTROL_STOP:
    			brun = FALSE;
    			ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    			WriteToLog("Service Stopped");
    			break;
    		case SERVICE_CONTROL_SHUTDOWN:
    			brun = FALSE;
    			ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    			break;
    		default:
    			break;
    	}
    	SetServiceStatus(hStatus, &ServiceStatus); //更新状态
    }
    
    bool WriteToLog(const char *mylog) { //写入文件
    	FILE *pfile;
    	fopen_s(&pfile, LOG_FILE, "a+");
    	if (pfile == NULL)
    	{
    		return false;
    	}
    	fprintf_s(pfile, "%s
    ", mylog);
    	fclose(pfile);
    	return true;
    }
    
    bool ToInstallService() {
    	//首先获取自身文件路径
    	wchar_t myPath[1024];
    	GetCurrentDirectory(1024, myPath);
    	GetModuleFileName(NULL, myPath, sizeof(myPath));
    	LPCWSTR path;
    	//printf("%ls", myPath);
    	SC_HANDLE SCmanager; // 用来接收 SCM
    	SC_HANDLE  SCservice; // 接收 用SCM来创建来的服务返回来的该对象的句柄
    
    	path = myPath;
    
    	SCmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); //为空则连接本身的服务器,NULL打开默认的服务器,SC_MANAGER_ALL_ACCESS权限
    
    	if (SCmanager == NULL) {
    		printf("OpenSCManager Failed, error in 128 line
    ");
    		return true;
    	}
    
    	SCservice = CreateService(
    		SCmanager,
    		TEXT("mydemozz"),
    		TEXT("360 protect center"),
    		SC_MANAGER_ALL_ACCESS,
    		SERVICE_WIN32_OWN_PROCESS,
    		SERVICE_AUTO_START,
    		SERVICE_ERROR_NORMAL,
    		path,
    		NULL,
    		NULL,
    		NULL,
    		NULL,
    		NULL);
    
    	if (SCservice == NULL) { // 创建失败
    		printf("CreateService Failed, error in 148 line
    ");
    		return false;
    	}
    	else {
    		printf("CreateService Success!
    ");
    	}
    	//创建成功的操作,则我们还需要关闭相应的句柄
    	CloseServiceHandle(SCservice);
    	CloseServiceHandle(SCmanager);
    	return true;
    }
    
    bool ToDeleteService() {
    	SC_HANDLE SCmanager;
    	SC_HANDLE SCservice;
    
    	SCmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    	if (SCmanager == NULL) {
    		printf("OpenSCManager Failed, error in 164 line, the reason maybe your privilege not enough 
    ");
    		return FALSE;
    	}
    
    	SCservice = OpenService(SCmanager, TEXT("mydemozz"), SERVICE_ALL_ACCESS | DELETE); //拿到 mydemozz 的服务句柄
    
    	if (!SCservice) {
    		printf("OpenService Failed, error in 171 line, the reason maybe your privilege not enough 
    ");
    		return FALSE;
    	}
    
    	//两个句柄都拿到了,就可以进行删除的操作了
    
    	//首先需要判断下SCservice中的服务是否正在运行,如果在运行的话 那么就得先stop,要不然删除不了的
    
    	SERVICE_STATUS sStatus;
    	
    	//首先获取服务的信息
    	if (!QueryServiceStatus(SCservice, &sStatus)) {
    		printf("Get ServiceStataus Failed, error in 183 line
    ");
    		return FALSE;
    	}
    
    	//判断服务当前的状态
    	if (sStatus.dwCurrentState != SERVICE_STOPPED) {
    		//将该服务进行停止的操作
    		if (ControlService(SCservice, SERVICE_CONTROL_STOP, &sStatus)) {
    			//然后进行停止操作
    			printf("Stop Service Success
    ");
    		}
    	}
    
    	if (DeleteService(SCservice)) {
    		printf("Delete Service Success");
    	}
    
    	//最后关闭句柄
    	CloseServiceHandle(SCmanager);
    	CloseServiceHandle(SCservice);
    	return true;
    }
    

  • 相关阅读:
    ASP.NET 中JSON的序列化和反序列(抄的别人的,为了自己收藏)
    Javascript DOM动态添加表格
    Jquery应用技巧
    福克斯驾驶技巧(手动挡)
    肾盂分离来判断肾积水的程度
    降低车辆使用成本——节油
    青岛手精白重磅整合、横空出世申请长期置顶
    福克斯保养注意事项及驾驶技巧
    轻度肾积水怎么办?
    新手车主看过来 保养方法开车技巧全解析(求精)
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/12244463.html
Copyright © 2020-2023  润新知