Windowsのサービス

個人的にWindowsのサービスプログラムについて知りたい挙動があって、簡単なサービスプログラムを作成&テストしてみた。


0.
OSはWindows XP
コンパイラVC++2005Express Ed.&WPSDK2003R2。下で使ってたのと一緒。
http://d.hatena.ne.jp/s0u/20060513/1147444775
タダ&商用利用可でここまで出来るなんてすばらしい。


1.
プログラムはコレ。
[C:\service\experimental.c]


#include
#include

#define SERVICE_NAME "experimental"

#define LOGFILE "C:\\service\\experimental.log"
void putlog(char* msg)
{
SYSTEMTIME tm;
FILE* flog = fopen(LOGFILE, "a");
GetLocalTime(&tm);
fprintf(flog, "%04d/%02d/%02d %02d:%02d:%02d %s\n",
tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond, msg);
fclose(flog);
}

SERVICE_STATUS ss;
SERVICE_STATUS_HANDLE hss;
void setstat(DWORD stat, DWORD cp, DWORD wh, char* msg)
{
ss.dwCurrentState = stat;
ss.dwCheckPoint = cp;
ss.dwWaitHint = wh;
if (SetServiceStatus(hss, &ss) == 0) {
char buff[1024];
strcpy(buff, "fail ");
strncat(buff, msg, (sizeof buff) - strlen(buff));
putlog(buff);
} else {
putlog(msg);
}
}

void stop_handler()
{
setstat(SERVICE_STOP_PENDING, 1, 1000, "stop pending");
Sleep(1000);
setstat(SERVICE_STOPPED, 0, 0, "stopped");
}

void WINAPI handler(DWORD cntl)
{
switch (cntl) {
case SERVICE_CONTROL_STOP:
stop_handler();
break;
case SERVICE_CONTROL_SHUTDOWN:
putlog("system shutdown");
stop_handler();
break;
}
}

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
putlog("service starting");

ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwCurrentState = SERVICE_START_PENDING;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ss.dwWin32ExitCode = 0;
ss.dwServiceSpecificExitCode = 0;
ss.dwCheckPoint = 1;
ss.dwWaitHint = 1000;
hss = RegisterServiceCtrlHandler(SERVICE_NAME, handler);
if (hss == 0) {
putlog("fail register");
return;
}
putlog("start pending");

Sleep(1000);

setstat(SERVICE_RUNNING, 0, 0, "running");
return;
}

int main(int argc, char* argv[])
{
SERVICE_TABLE_ENTRY ste[] = { {SERVICE_NAME, ServiceMain}, {NULL, NULL} };
if (StartServiceCtrlDispatcher(ste) == 0) {
putlog("fail main");
return 1;
}
return 0;
}


2.
VS2005コマンドプロンプトを起動して、以下のコマンドを実行してプログラムをビルド。


cd /d c:\service
"C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\SetEnv.Cmd" /XP32 /RETAIL
cl /MT /w experimental.c /link ADVAPI32.LIB


3.
以下のコマンドを実行して、Windowsにサービスを登録。
昔サービスプログラム作ったときはサービス登録専用のプログラムをわざわざ作った覚えがあるけど、今(XP以降)はサービス制御用のコマンドが標準で用意されてるのね。


sc create "experimental" start= auto binPath= "C:\service\experimental.exe"


4.
Windowsのサービス管理画面から動作テスト。
イ)起動
ロ)停止
ハ)また起動
ニ)PCシャットダウン
ホ)PC起動


その結果がコレ。


2006/05/29 02:42:33 service starting
2006/05/29 02:42:33 start pending
2006/05/29 02:42:34 running
2006/05/29 02:43:13 stop pending
2006/05/29 02:43:14 stopped
2006/05/29 02:43:15 service starting
2006/05/29 02:43:15 start pending
2006/05/29 02:43:16 running
2006/05/29 02:43:40 system shutdown
2006/05/29 02:43:40 stop pending
2006/05/29 02:43:41 stopped
2006/05/29 02:44:54 service starting
2006/05/29 02:44:54 start pending
2006/05/29 02:45:00 running


知りたかったのは、実は上のプログラムからはわからないのだけど SERVICE_ACCEPT_SHUTDOWN を実装しないときに Windows 停止時に SERVICE_CONTROL_STOP は呼ばれるのかということ。呼ばれないのかー。えー。


ちなみに、登録したサービスを削除するコマンドは以下。


sc delete "experimental"