Windows服务简单一例,捕获关机信号做些处理

Windows服务

创建在 Windows 中的可长时间运行的可执行应用程序。

这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。它非常适合在服务器上使用,或为了不影响在同一台电脑上工作的其他用户需要长时间运行功能时使用,或者是随开机就启动后台默默干活的应用。

通过运行界面,输入services.msc可打开windows自带的服务管理界面对服务进行控制。

一个服务不管有没有被运行,都在你的硬盘里,只有当它真正被运行时,操作系统就会真正给它分配内存、CPU时间片等资源,这一次运行就对应一个“进程”。

服务管理

可以使用SC命令对服务进行管理,SC 是用于与服务控制管理器和服务进行通信的命令行程序。

如下示例:

#创建服务
sc create myservice binpath= "c:\mywin32.exe" displayname= "myService"
 
sc delete myservice
 
sc start myservice
 
sc stop myservice

随便写一个hello.exe以这种方式加进去行不行?

结论是可以添加进去,在服务管理界面也能看到。但是没什么意义,因为无法启动也无法控制,它也不会自动运行。

服务需要符合一定的写法。

基本写法

需要的有:

服务入口函数:

void WINAPI ServiceMain(int argc, char* argv[])

 服务控制函数(暂停、关机一些命令的控制)

ServiceCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)

服务状态结构体 

SERVICE_STATUS m_ServiceStatus;  

注册服务控制函数

RegisterServiceCtrlHandlerEx("myService",lpHandlerProc,myContext)

设置服务状态函数 

SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus)

服务进入表,设置服务程序的入口 

SERVICE_TABLE_ENTRY DispatchTable[2]

服务控制分发

 StartServiceCtrlDispatcher(DispatchTable) 

基本上完成以上这些,就可以创建一个简单的windows服务了,熟悉下套路还是很简单的。编译完成后生成的.exe可执行文件不能直接运行,使用上面的sc命令来创建和启动服务。

还有一些稍复杂的点用法,可以完成应用自身对服务的创建,启动和停止等管理。

比如windows上的redis服务,它通过:

./redis-server.exe  --service-install redis.windows-service.conf 就可以把自己以服务的方式运行和启动。是它的源码内部实现了服务的创建,暂停,启动等方法。如:ServiceInstall,ServiceStart,ServiceStop等。参见redis源码中的Win32_service.cpp。

源码地址:https://github.com/tporadowski/redis

简单示例

#include <Windows.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include <helper.h>
#include <logging.h>
#include <redisclient.h>
using namespace std;

const int SLEEP_TIME = 5000;	// 延迟时间
BOOL bFlag = TRUE;  // 标记循环是否结束

SERVICE_STATUS_HANDLE m_ServiceStatusHandle;	// 服务状态句柄
SERVICE_STATUS m_ServiceStatus;	// 服务状态结构体,保存服务程序的一些信息

// 命令行参数可加可不加
void WINAPI ServiceMain(int argc, char* argv[]);// 服务程序入口函数
//void WINAPI ServiceCtrlHandler(DWORD Opcode);	// 服务控制函数(暂停、关机一些命令的控制)
DWORD WINAPI ServiceCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext);	// 服务控制函数

LPVOID myContext;

void WINAPI ServiceMain(int argc, char* argv[])
{
    MEMORYSTATUS memstatus;	// 内存状态结构体,存储内存的一些信息
    char str[100];	// 存储一个字符串
    size_t availmb;	// 将获取到的内存大小 B --> MB转换

    // 初始化服务状态
    m_ServiceStatus.dwServiceType = SERVICE_WIN32;	// Win32类型
    m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;	// 当前状态为开始等待
    m_ServiceStatus.dwControlsAccepted =  SERVICE_ACCEPT_PAUSE_CONTINUE|SERVICE_ACCEPT_STOP;	// 接受关机与暂停两种控制
    m_ServiceStatus.dwWin32ExitCode = 0;		// 下面四个默认都为0
    m_ServiceStatus.dwServiceSpecificExitCode = 0;
    m_ServiceStatus.dwCheckPoint = 0;
    m_ServiceStatus.dwWaitHint = 0;
    //重要
    m_ServiceStatus.dwControlsAccepted |= SERVICE_ACCEPT_PRESHUTDOWN;
    //注册服务控制
    //m_ServiceStatusHandle = RegisterServiceCtrlHandler("myService", ServiceCtrlHandler);
    m_ServiceStatusHandle = RegisterServiceCtrlHandlerEx("myService",ServiceCtrlHandler,myContext);
    if (m_ServiceStatusHandle == 0)	// 判断是否成功执行
    {
        LOGGING_DEBUG("RegisterServiceCtrlHandle failed");	// 错误信息写入文件
        return;
    }
    LOGGING_DEBUG("RegisterServiceCtrlHandle success"); 	// 成功信息写入文件
    m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;	// 成功运行则把状态设置为运行状态


    SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus); // 设置状态

    bFlag = TRUE;		// 循环条件为真
    memset(str, 0, 100);	// 初始化字符串中的数据
    while (bFlag)
    {
        //todo,fixeme,服务空闲状态干什么事,这里假做记录内存信息
        GlobalMemoryStatus(&memstatus);			// 获取内存状态信息
        availmb = memstatus.dwAvailPhys / 1024 / 1024;	// 将获取的字节转化为M
        sprintf_s(str, 100, "availmb memory is %d MB ", availmb);	// 格式化字符串
        LOGGING_DEBUG(str);	// 写入文件中
        Sleep(SLEEP_TIME);	// 延迟五秒
    }
    LOGGING_DEBUG("service stopped");	// 结束循环后,发送一消息给文件
}

void doYourWork(){
    //ostringstream out;
    //out << "RedisClient isConnect = " << ret;
    //LOGGING_DEBUG((char*)out.str().c_str());
}
 int WriteToLog(char* str)				//自定义的写日志函数
{
	FILE* pfile;
	fopen_s(&pfile,"C:/mylog.log","a+");			//已追加的方式打开文件;fopen_s函数的安全性更高;
	if (pfile==NULL)
	{
		return -1;
	}
	fprintf_s(pfile,"%s\n",str);			//向文件中写入字符串
	fclose(pfile);					//关闭打开的文件
	return 0;
}
//注册服务控制处理
DWORD ServiceCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext){
    switch( dwControl ){
        //如果是关机事件,则...
        case SERVICE_CONTROL_PRESHUTDOWN:
            LOGGING_DEBUG("myService. SERVICE_CONTROL_PRESHUTDOWN");
            doYourWork();
            //ShutdownBlockReasonCreate(hwnd, (("waiting for user response")));
            break;
        case SERVICE_CONTROL_STOP:	// 暂停控制
            bFlag = FALSE;			// 循环标志为FASE
            m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;// 状态设置为停止
            LOGGING_DEBUG("myService. SERVICE_CONTROL_STOP");
            break;
        case SERVICE_CONTROL_CONTINUE:	// 继续
            LOGGING_DEBUG("myService. SERVICE_CONTROL_CONTINUE");
            break;
        case SERVICE_CONTROL_SHUTDOWN:// 关机控制
            bFlag = FALSE;  		// 循环标志为FASE
            m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;// 状态设置为停止
            LOGGING_DEBUG("myService. SERVICE_CONTROL_SHUTDOWN");
            break;
        default:
            ostringstream oStr;
            oStr << "lpHandlerProc dwControl=" << dwControl;
            LOGGING_DEBUG((char*)oStr.str().c_str());
            break;
    }
    // 设置服务状态
    SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
    return 0;
}
int main(){
    cout<<"hello myService start"<<endl;
    LOGGING_DEBUG(" myService start...");
    //为当前调用的进程设置关闭的参数,此函数为进程设置一个相对于系统中其它进程的关闭顺序
    int ret = SetProcessShutdownParameters(0x3FF,0);
    if(ret == 0){
        LOGGING_ERROR("SetProcessShutdownParameters error");
    }
    // 定义服务进入表,设置服务程序的入口函数
    SERVICE_TABLE_ENTRY DispatchTable[2];
    DispatchTable[0].lpServiceName = "myService";	// 服务程序名称
    DispatchTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; // 服务程序入口
    DispatchTable[1].lpServiceName = NULL;
    DispatchTable[1].lpServiceProc = NULL;
   
    // 开始服务控制分布
    StartServiceCtrlDispatcher(DispatchTable);
    return 0;
}

引用

Windows 服务程序(一) - 走看看

正在关闭 - Win32 apps | Microsoft Docs

关于服务 - Win32 apps | Microsoft Docs

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
PCI信号捕获信号处理控制器是一种用于采集和处理PCI总线上的数据信号的设备。PCI是一种常用的计算机总线标准,用于连接计算机内部的各种硬件设备,如显卡、网络适配器、声卡等。 PCI信号捕获信号处理控制器的主要功能是捕获来自PCI总线上的数据信号,并对这些信号进行处理和分析。它通常由硬件和软件两部分组成。硬件部分包括物理接口电路和数据缓冲区,用于接收和存储从PCI总线上传输过来的数据。软件部分包括驱动程序和应用程序,用于控制硬件设备的操作,并对捕获的数据进行处理和分析。 通过PCI信号捕获信号处理控制器,我们可以获取PCI总线上的各种数据信息,如数据包、控制信号等。这对于系统调试、性能分析和故障诊断非常有用。通过分析这些数据,我们可以了解系统的运行状态、数据传输的流程和速度等关键信息,从而对系统进行优化和改进。 在实际应用中,PCI信号捕获信号处理控制器广泛应用于各种领域。例如,在通信领域,它可用于分析网络数据包的传输过程,以便排查网络故障或优化网络性能。在计算机硬件设计领域,它可用于调试和验证新的硬件设备。在嵌入式系统领域,它可用于分析实时数据流,以便改进系统的响应时间和稳定性。 总之,PCI信号捕获信号处理控制器是一种重要的设备,用于采集和处理PCI总线上的数据信号。通过这种设备,我们能够获得有关系统性能和数据传输的关键信息,从而对系统进行优化和改进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

特立独行的猫a

您的鼓励是我的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值