C++語言編寫windows服務

C++語言編寫windows服務

1、 windows服務

通過快捷鍵”win+R”打開運行框,輸入”services.msc”,就能夠打開windows服務。鼠標右鍵任意一個服務,能看見以下的選項,如下圖1.1所示 
圖1.1圖1.1 windows服務 
本文的內容講的就是通過windows服務控制程序的啓動停止等操作。

2、 DebugView調試工具

官網上是這樣介紹這款軟件的

DebugView is an application that lets you monitor debug output on your local system, or any computer on the network that you can reach via TCP/IP. It is capable of displaying both kernel-mode and Win32 debug output, so you don’t need a debugger to catch the debug output your applications or device drivers generate, nor do you need to modify your applications or drivers to use non-standard debug output APIs.

我們可以用這款軟件來調試windows服務程序。如圖2.1進行DebugView的相關設置,並在我們寫的程序中使用函數”OutputDebugString”,這時當啓動我們寫的windows服務,DebugView就能夠將程序的調試信息捕捉到,顯示出來。 
圖2.1圖2.1 將Capture Kernel打上勾

3、 c++語言編寫windows服務

c++語言的windows服務的代碼如下,此程序已在win7,VS2010調試運行通過。本例的源代碼來自代碼來源

#include <stdio.h>

#include <Windows.h>

#define SLEEP_TIME 5000 //間隔時間

#define FILE_PATH "C:\\log.txt" //信息輸出文件

bool brun=false;

SERVICE_STATUS servicestatus;

SERVICE_STATUS_HANDLE hstatus;

int WriteToLog(char* str);

void WINAPI ServiceMain(int argc, char** argv);

void WINAPI CtrlHandler(DWORD request);

int InitService();

int WriteToLog(char* str)

{

    FILE* pfile;

    fopen_s(&pfile,FILE_PATH,"a+");

    if (pfile==NULL)

    {

        return -1;

    }

    fprintf_s(pfile,"%s\n",str);

    fclose(pfile);

    return 0;

}

void WINAPI ServiceMain(int argc, char** argv)
{

    servicestatus.dwServiceType = SERVICE_WIN32;

    servicestatus.dwCurrentState = SERVICE_START_PENDING;

    servicestatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP;//在本例中只接受系統關機和停止服務兩種控制命令

    servicestatus.dwWin32ExitCode = 0;

    servicestatus.dwServiceSpecificExitCode = 0;

    servicestatus.dwCheckPoint = 0;

    servicestatus.dwWaitHint = 0;

    hstatus = ::RegisterServiceCtrlHandler("testservice", CtrlHandler);

    if (hstatus==0)
    {

        WriteToLog("RegisterServiceCtrlHandler failed");

        return;

    }

    WriteToLog("RegisterServiceCtrlHandler success");

    //向SCM 報告運行狀態

    servicestatus.dwCurrentState = SERVICE_RUNNING;

    SetServiceStatus (hstatus, &servicestatus);

    //在此處添加你自己希望服務做的工作,在這裏我做的工作是獲得當前可用的物理和虛擬內存信息

    brun=true;

    MEMORYSTATUS memstatus;

    char str[100];

    memset(str,'\0',100);

    while (brun)
    {

        GlobalMemoryStatus(&memstatus);

        int availmb=memstatus.dwAvailPhys/1024/1024;

        sprintf_s(str,100,"available memory is %dMB",availmb);

        WriteToLog(str);

        Sleep(SLEEP_TIME);

    }

    WriteToLog("service stopped");

}

void WINAPI CtrlHandler(DWORD request)
{

    switch (request)
    {
    case SERVICE_CONTROL_STOP:

        brun=false;

        servicestatus.dwCurrentState = SERVICE_STOPPED;

        break;

    case SERVICE_CONTROL_SHUTDOWN:

        brun=false;

        servicestatus.dwCurrentState = SERVICE_STOPPED;

        break;

    default:

        break;

    }

    SetServiceStatus (hstatus, &servicestatus);
}

void main()
{

    SERVICE_TABLE_ENTRY entrytable[2];

    entrytable[0].lpServiceName="testservice";

    entrytable[0].lpServiceProc=(LPSERVICE_MAIN_FUNCTION)ServiceMain;

    entrytable[1].lpServiceName=NULL;

    entrytable[1].lpServiceProc=NULL;

    StartServiceCtrlDispatcher(entrytable);

}
  • 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
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 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
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157

我在寫相關的windows服務程序的時候遇到了這樣的問題,程序加載當前的路徑的配置文件”./config.xml”,發現程序總是在加載文件這個地方出錯,然後用函數”GetCurrentDirectory”函數獲取程序當前運行的路徑,並且用函數”OutputDebugString”將獲取到的路徑信息打印出來,獲取到程序當前的運行目錄是”C:\Windows\system32”,要加載程序運行的配置文件,應該使用絕對路徑。在windows服務中獲取程序的路徑。下面兩段程序都能獲得程序的路徑。

//代碼一
string GetProgramDir()    
{     
    TCHAR exeFullPath[MAX_PATH]; // Full path  
    GetModuleFileName(NULL,exeFullPath,MAX_PATH);  
    string strPath = __TEXT("");         
    strPath = exeFullPath;    // Get full path of the file  
    int pos = strPath.find_last_of(L'\\', strPath.length());  
    return strPath.substr(0, pos);  // Return the directory without the file name  
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
//代碼二
void GetConfigPath()
{   
    UINT    nLen  = MAX_PATH;
    char    process[MAX_PATH] = {0};
    char    drive[_MAX_DRIVE] = {0};
    char    dir[_MAX_DIR] = {0};
    char    fname[_MAX_FNAME] = {0};
    char    ext[_MAX_EXT] = {0};
    UINT    nbaselen = 0;
    UINT    nprocesslen = 0;
    char *pChrTemp = chConfigPath;
    memset(pChrTemp,0,MAX_PATH);
    GetModuleFileName(NULL, process, MAX_PATH);
    _splitpath_s(process, drive, dir, fname, ext);
    _makepath_s(process, "", dir, "", "");
    strcat_s(pChrTemp,nLen-strlen(pChrTemp),drive);
    nbaselen = (UINT)strlen(pChrTemp);
    nprocesslen = (UINT)strlen(process);
    if((nbaselen+nprocesslen)<nLen)
    {   
        strcat_s(pChrTemp,nLen-strlen(pChrTemp),process);
        chConfigPath[strlen(chConfigPath)-1] = '\0';
    }
    /*
    while( *pChrTemp) {
        if( *pChrTemp == '\\') {
            *pChrTemp = '/';
        }
        pChrTemp ++;
    }
    */
}
  • 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
  • 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

4、 將程序作爲windows服務

windows服務有以下命令,”win+R”後輸入”cmd”,即可進行操作

輸入sc create testservicename binpath= D:\test.exe (這裏的D:\test.exe路徑就是你的.exe程序所在的絕對路徑,注意"="後面有一個空格)

輸入sc start testservicename 啓動服務

輸入sc query 會在最底部顯示你的服務當前的狀態

輸入sc stop testservicename 停止服務

輸入sc delete testservicename刪除服務,該服務將在下次重啓後刪除,在重啓之前將不能註冊同一個名字的服務。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

下面是一個簡單的startup.bat文件創建windows服務的操作

rem startup.bat 文件創建服務,這裏爲服務取名爲testservicename,此文件放在與.exe文件同級目錄下,按着"Shift"鍵,同時單擊鼠標右鍵,點擊"在此處打開命令窗口",然後輸入此文件名"startup.bat",就能創建此服務
@echo off

rem 獲取絕對路徑
set "CURRENT_DIR=%~dp0"

set "EXE_NAME=testservicename.exe"

@echo %CURRENT_DIR%%EXE_NAME%

rem 創建windows服務
sc create yzUpgradeService binpath= %CURRENT_DIR%%EXE_NAME%

sc config yzUpgradeService start= AUTO 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

發佈了51 篇原創文章 · 獲贊 14 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章