Qt (7) QtでWindows Serviceを作る
ご利用のブラウザは、JavaScript が無効 となっていませんか?
このサイトでは、コンテンツの一部が非表示 、あるいは、コメント、お問い合わせの投稿ができない 、検索ができない ことがあります。
概要 :
Qtで、WindowsのServiceを作成することはできるでしょうか。
Unix系のdeamonプロセスとWindowsのServiceをラップしたクラスが提供されています。そのクラスを用いることで簡単に作成することができます。
ただ、標準のQt SDKの中には、含まれていません。
以降のアドレスから、ダウンロードし、コンパイル(ビルド)作業が必要になります。
この記事では、VC++ 2008 Expressでの環境作成とサンプルの動作概要について簡単に説明します。
コンパイルしましょう
ダウンロードしたZIPファイルを解凍します
オープンソース版であれば、以下のような名前のZIPファイルをダウンロードします。
(バージョンによって多少は異なります。)
1
qtservice-2.6-opensource.zip
ここでは、例として、先のZIPファイルを以下のディレクトリへ解凍したものとして、話を進めます。
C:\Qt\Qt\service
解凍したら、以下のようなディレクトリが作成されます。
1
2
3
4
5
6
C:\Qt\Qt\service\buildlib
C:\Qt\Qt\service\doc
C:\Qt\Qt\service\examples
C:\Qt\Qt\service\lib
C:\Qt\Qt\service\src
C:\Qt\Qt\service\tmp
コンパイル(ビルド)します
VC++ 2008 Expressのスタートアップメニューの中の"Visula Studio 2008 コマンドプロンプト"を開きます
コマンドプロンプトから、解凍先ディレクトリ へカレントディレクトリを移動します
1
2
C:\Program Files\Microsoft Visual Studio 9.0\VC> cd C:\Qt\Qt\service
C:\Qt\Qt\service>
ライブラリのビルド方法を指定します
-- ここでは、DLL版を作成します。
1
2
C:\Qt\Qt\service> configure -library
C:\Qt\Qt\service>
-- static ライブラリを作成する場合は、パラメータなしでconfig.batを起動します。
-- ライセンスの確認メッセージが表示されますので、それに答えて作業を進めます。
ライブラリをコンパイル(ビルド)します
1
2
3
4
5
6
C:\Qt\Qt\service> qmake
C:\Qt\Qt\service> nmake
:
:
:
C:\Qt\Qt\service>
-- 必ず、ここで、qmakeを実施し、makeを起動します。(数分の作業です)
ここまで完了すると、デバッグ版、リリース版、サンプルが全てコンパイル(ビルド)されています。
開発環境を設定しましょう
[ マイコンピュータ ] - [ プロパティ ]で環境設定を行います。
環境変数名 値
PATH
環境変数のpathにLibのディレクトリを追加します。
例)
%path%;C:\Qt\Qt\service\.
-- C:\Qt\Qt\service\lib\ : Qt - Service Lib(DLL)のディレクトリ
ここで、設定する環境変数のpathは、システム環境変数のPATH へ設定します。
ユーザ環境変数のPATHでないことに注意します。
Qtの各ライブラリのパスについても同様です。Serviceを扱う場合、全てのQt関連のパスは、システム環境変数のPATH へ設定します。
設定を終えたら、OKボタンをクリックします。
システムの環境変数を変更していますので、システムをリブートします。
リブートを終えたら、サンプルを実行してみましょう。
サンプルを実行してみましょう
このService関連でのサンプルは、3つあります。
An Interactive Service
-- デスクトップ上に画面を表示する簡単なサービスのサンプルです。
A simple HTTP Server
-- HTTPのサーバの簡単なサービスのサンプルです。
A simple Service Controller
-- サービスの登録/削除や実行/停止を行うサンプルです。
ここでは、An Interactive Service, A simple Service Controller を使ってみましょう。
説明の便宜上、同じディレクトリへ実行ファイルをコピーします。
1
2
3
C:\temp> copy C:\Qt\Qt\service\examples\controller\release\controller.exe .
C:\temp> copy C:\Qt\Qt\service\examples\interactive\release\interactive.exe .
C:\temp>
controller.exeを使ってinteractive.exeをサービス登録(install)します。
1
2
3
4
5
6
C:\temp> controller.exe -i C:\temp\interactive.exe
The service Qt Interactive Service has been installed under: C:\temp\interactive.exe
The service was installed.
C:\temp>
The service was installed. が出力されれば、OKです。
The service was not installed. では、エラーですので、入力などを確認してみてください。
また、コントロールパネルのサービスでも確認してみましょう。
上記のように、"Qt Interactive Service"という名前のサービスが確認できればOKです。
controller.exeを使ってinteractive.exeを実行します。
1
2
3
4
C:\temp> controller.exe "Qt Interactive Service" -s
The service "Qt Interactive Service" was started.
C:\temp>
The service "Qt Interactive Service" was started. が出力されれば、OKです。
The service "Qt Interactive Service" was not started. では、エラーですので、入力などを確認してみてください。
また、デスクトップ左上に"Service"とういうラベルのみの画面が表示されたと思います。
この画面が表示されない場合は、何か環境に問題がありますので、再度、見直されることをお勧めします。
このサービスは、Vista, Windows 7では、開始できません。XP,2000などで確認してください。
controller.exeを使ってinteractive.exeを停止します。
1
2
3
4
C:\temp> controller.exe "Qt Interactive Service" -t
The service "Qt Interactive Service" was stopped.
C:\temp>
The service "Qt Interactive Service" was stopped. が出力されれば、OKです。
The service "Qt Interactive Service" was not stopped. では、エラーですので、入力などを確認してみてください。
また、デスクトップ左上に"Service"とういうラベルのみの画面が消えたと思います。
controller.exeを使ってinteractive.exeをサービス削除(uninstall)します。
1
2
3
4
C:\temp> controller.exe "Qt Interactive Service" -u
The service "Qt Interactive Service" was uninstalled.
C:\temp>
The service "Qt Interactive Service" was uninstalled. が出力されれば、OKです。
The service "Qt Interactive Service" was not uninstalled. では、エラーですので、入力などを確認してみてください。
サンプルのソースコードを見ても、サービスの登録に2、3行程度です。
サービス自体は、QtService<QApplication>を継承し、各メソッドを準備すれば、それほど、難しいものではありません。
Qtでサービスを作成する需要がどれほどあるのかわかりませんが、簡単であることは、間違いありません。
一度、試されるのも良いと思います。
簡単なサンプルの解説
An Interactive Service, A simple Service Controller のいずれのサンプルソースもmain.cppのみです。
[An Interactive Service]
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
class InteractiveService : public QtService< QApplication >
{
public :
InteractiveService( int argc, char ** argv) ;
~InteractiveService( ) ;
protected :
void start( ) ;
void stop( ) ;
void pause( ) ;
void resume( ) ;
void processCommand( int code) ;
private :
QLabel * gui;
} ;
InteractiveService:: InteractiveService ( int argc, char ** argv)
: QtService< QApplication > ( argc, argv, "Qt Interactive Service" ) , gui( 0 )
{
setServiceDescription( "A Qt service with user interface." ) ;
setServiceFlags( QtServiceBase:: CanBeSuspended ) ;
}
InteractiveService:: ~InteractiveService ( )
{
}
void InteractiveService:: start ( )
{
#if defined(Q_OS_WIN)
if ( ( QSysInfo :: WindowsVersion & QSysInfo :: WV_NT_based ) &&
( QSysInfo :: WindowsVersion >= QSysInfo :: WV_VISTA ) ) {
logMessage( "Service GUI not allowed on Windows Vista. See the documentation for this example for more information." , QtServiceBase:: Error ) ;
return;
}
#endif
qApp-> setQuitOnLastWindowClosed ( false ) ;
gui = new QLabel ( "Service" , 0 , Qt:: WindowStaysOnTopHint | Qt:: FramelessWindowHint ) ;
gui-> move ( QApplication :: desktop ( ) -> availableGeometry ( ) .topLeft ( ) ) ;
gui-> show ( ) ;
}
void InteractiveService:: stop ( )
{
delete gui;
}
void InteractiveService:: pause ( )
{
if ( gui)
gui-> hide ( ) ;
}
void InteractiveService:: resume ( )
{
if ( gui)
gui-> show ( ) ;
}
void InteractiveService:: processCommand ( int code)
{
gui-> setText ( "Command code " + QString :: number ( code) ) ;
gui-> adjustSize ( ) ;
}
ここでは、InteractiveServiceのクラスのみを抜粋しています。
mainルーチンでは、このクラスをnewして、exec()を起動しているだけです。
このクラスの特徴は、QtService<QApplication>の継承と以下のメソッドです。
void start();
-- サービスが開始した時のこのメソッドが動きます。
void stop();
-- サービスが停止した時のこのメソッドが動きます。
void pause();
-- サービスが一時停止した時のこのメソッドが動きます。
void resume();
-- サービスが再開した時のこのメソッドが動きます。
void processCommand(int code);
-- サービスがユーザからのコマンドを受信した時のこのメソッドが動きます。
22行目あたりのコンストラクタで、
サービスの概要を登録(setServiceDescription),
サービスの機能の設定(setServiceFlags)-一時停止を可と設定している,
ぐらいでしょうか。
あとは、解説するほどのソースコードではないように思います。
[A simple Service Controller]
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
int processArgs( int argc, char ** argv)
{
if ( argc > 2 ) {
QString arg1( argv[ 1 ] ) ;
if ( arg1 == QLatin1String ( "-i" ) ||
arg1 == QLatin1String ( "-install" ) ) {
if ( argc > 2 ) {
QString account;
QString password;
QString path( argv[ 2 ] ) ;
if ( argc > 3 )
account = argv[ 3 ] ;
if ( argc > 4 )
password = argv[ 4 ] ;
printf ( "The service %s installed.\n " ,
( QtServiceController:: install ( path, account, password) ? "was" : "was not" ) ) ;
return 0 ;
}
} else {
QString serviceName( argv[ 1 ] ) ;
QtServiceController controller( serviceName) ;
QString option( argv[ 2 ] ) ;
if ( option == QLatin1String ( "-u" ) ||
option == QLatin1String ( "-uninstall" ) ) {
printf ( "The service \" %s\" %s uninstalled.\n " ,
controller.serviceName ( ) .toLatin1 ( ) .constData ( ) ,
( controller.uninstall ( ) ? "was" : "was not" ) ) ;
return 0 ;
} else if ( option == QLatin1String ( "-s" ) ||
option == QLatin1String ( "-start" ) ) {
QStringList args;
for ( int i = 3 ; i < argc; ++ i)
args.append ( QString :: fromLocal8Bit ( argv[ i] ) ) ;
printf ( "The service \" %s\" %s started.\n " ,
controller.serviceName ( ) .toLatin1 ( ) .constData ( ) ,
( controller.start ( args) ? "was" : "was not" ) ) ;
return 0 ;
} else if ( option == QLatin1String ( "-t" ) ||
option == QLatin1String ( "-terminate" ) ) {
printf ( "The service \" %s\" %s stopped.\n " ,
controller.serviceName ( ) .toLatin1 ( ) .constData ( ) ,
( controller.stop ( ) ? "was" : "was not" ) ) ;
return 0 ;
} else if ( option == QLatin1String ( "-p" ) ||
option == QLatin1String ( "-pause" ) ) {
printf ( "The service \" %s\" %s paused.\n " ,
controller.serviceName ( ) .toLatin1 ( ) .constData ( ) ,
( controller.pause ( ) ? "was" : "was not" ) ) ;
return 0 ;
} else if ( option == QLatin1String ( "-r" ) ||
option == QLatin1String ( "-resume" ) ) {
printf ( "The service \" %s\" %s resumed.\n " ,
controller.serviceName ( ) .toLatin1 ( ) .constData ( ) ,
( controller.resume ( ) ? "was" : "was not" ) ) ;
return 0 ;
} else if ( option == QLatin1String ( "-c" ) ||
option == QLatin1String ( "-command" ) ) {
if ( argc > 3 ) {
QString codestr( argv[ 3 ] ) ;
int code = codestr.toInt ( ) ;
printf ( "The command %s sent to the service \" %s\" .\n " ,
( controller.sendCommand ( code) ? "was" : "was not" ) ,
controller.serviceName ( ) .toLatin1 ( ) .constData ( ) ) ;
return 0 ;
}
} else if ( option == QLatin1String ( "-v" ) ||
option == QLatin1String ( "-version" ) ) {
bool installed = controller.isInstalled ( ) ;
printf ( "The service\n "
"\t \" %s\" \n \n " , controller.serviceName ( ) .toLatin1 ( ) .constData ( ) ) ;
printf ( "is %s" , ( installed ? "installed" : "not installed" ) ) ;
printf ( " and %s\n \n " , ( controller.isRunning ( ) ? "running" : "not running" ) ) ;
if ( installed) {
printf ( "path: %s\n " , controller.serviceFilePath ( ) .toLatin1 ( ) .data ( ) ) ;
printf ( "description: %s\n " , controller.serviceDescription ( ) .toLatin1 ( ) .data ( ) ) ;
printf ( "startup: %s\n " , controller.startupType ( ) == QtServiceController:: AutoStartup ? "Auto" : "Manual" ) ;
}
return 0 ;
}
}
}
printf ( "controller [-i PATH | SERVICE_NAME [-v | -u | -s | -t | -p | -r | -c CODE] | -h] [-w]\n \n "
"\t -i(nstall) PATH\t : Install the service\n "
"\t -v(ersion)\t : Print status of the service\n "
"\t -u(ninstall)\t : Uninstall the service\n "
"\t -s(tart)\t : Start the service\n "
"\t -t(erminate)\t : Stop the service\n "
"\t -p(ause)\t : Pause the service\n "
"\t -r(esume)\t : Resume the service\n "
"\t -c(ommand) CODE\t : Send a command to the service\n "
"\t -h(elp)\t \t : Print this help info\n "
"\t -w(ait)\t \t : Wait for keypress when done\n " ) ;
return 0 ;
}
ここでは、A simple Service Controllerの内部サブルーチンprocessArgsのみを抜粋しています。
mainルーチンでは、このサブルーチンを起動しているだけです。
このサブルーチンで、コマンドパラメータにより、分岐がありますが、ほとんど、解説は不要と思います。
ほとんどが、QtServiceController クラスオブジェクトに対して、メソッドをコールするだけです。
その結果に対して、コンソールへ結果表示を行っています。
簡単にQtServiceController クラスのメソッドを解説しておくと以下のとおりです。
bool start ( const QStringList & arguments )
-- サービスを開始する時のこのメソッドを起動します。
bool start ()
-- サービスを開始する時のこのメソッドを起動します。
bool stop ()
-- サービスを停止する時のこのメソッドを起動します。
bool pause ()
-- サービスを一時停止する時のこのメソッドを起動します。
bool resume ()
-- サービスを再開する時のこのメソッドを起動します。
bool sendCommand ( int code )
-- サービスへユーザからのコマンドを送信する時のこのメソッドを起動します。
bool uninstall ()
-- サービスをサービス削除(uninstall)する時のこのメソッドを起動します。
bool install ( const QString & serviceFilePath, const QString & account = QString(), const QString & password = QString() )
-- サービスをサービス登録(install)する時のこのメソッドを起動します。
もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。
2010年10月15日 @ 16:06:12
I tried to compile the qtservice framework. But after nmake, I got the list of errors.
I am using Qt4.7, Visual Studio 2008 and Window XP.
C:\Qt\QtService2.6_1>qmake
C:\Qt\QtService2.6_1>nmake
Microsoft (R) Program Maintenance Utility Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
cd buildlib\ && “C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\nma
ke.exe” -f Makefile
Microsoft (R) Program Maintenance Utility Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
c:\Qt\Qt4.7WinCE\bin\qmake.exe -o Makefile buildlib.pro
“C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\nmake.exe” -f Makef
ile.Debug
Microsoft (R) Program Maintenance Utility Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
cl -c -nologo -Zm200 -Zc:wchar_t- -DDEBUG -D_DEBUG -Zi -MDd -EHs-c- -W3
-w34100 -w34189 -DUNDER_CE -DWINCE -D_WINDOWS -D_UNICODE -DUNICODE -D_WIN32 -DQT
_NO_PRINTER -DQT_NO_PRINTDIALOG -DARMV4I -D_ARMV4I_ -Darmv4i -D_ARM_ -DARM -D_M_
ARM -DARM -D__arm__ -DQ_OS_WINCE_WM -DQT_NO_PRINTER -DQT_NO_PRINTDIALOG -D_WIN32
_WCE=0x502 -DQT_QTSERVICE_EXPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD
_SUPPORT -DQT_NO_DYNAMIC_CAST -I”..\..\Qt4.7WinCE\include\QtCore” -I”..\..\Qt4.7
WinCE\include\QtGui” -I”..\..\Qt4.7WinCE\include” -I”..\src” -I”..\..\Qt4.7WinCE
\include\ActiveQt” -I”debug” -I”..\..\Qt4.7WinCE\mkspecs\default” -Fodebug\ @C:\
DOCUME~1\user\LOCALS~1\Temp\nm6.tmp
qtservice_win.cpp
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2260) : error C2
733: second C linkage of overloaded function ‘InterlockedIncrement’ not allowed
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2258) :
see declaration of ‘InterlockedIncrement’
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2267) : error C2
733: second C linkage of overloaded function ‘InterlockedDecrement’ not allowed
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2265) :
see declaration of ‘InterlockedDecrement’
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2275) : error C2
733: second C linkage of overloaded function ‘InterlockedExchange’ not allowed
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2272) :
see declaration of ‘InterlockedExchange’
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2286) : error C2
733: second C linkage of overloaded function ‘InterlockedExchangeAdd’ not allowe
d
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2283) :
see declaration of ‘InterlockedExchangeAdd’
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2295) : error C2
733: second C linkage of overloaded function ‘InterlockedCompareExchange’ not al
lowed
C:\Program Files\Microsoft SDKs\Windows\v6.0A\include\winbase.h(2291) :
see declaration of ‘InterlockedCompareExchange’
..\src\qtservice_win.cpp(718) : error C2065: ‘WM_ENDSESSION’ : undeclared identi
fier
NMAKE : fatal error U1077: ‘”C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN
\cl.EXE”‘ : return code ‘0x2’
Stop.
NMAKE : fatal error U1077: ‘”C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN
\nmake.exe”‘ : return code ‘0x2’
Stop.
NMAKE : fatal error U1077: ‘cd’ : return code ‘0x2’
Stop.
Is there solution for that?
Thanks
2010年10月15日 @ 19:48:36
Hi Ko,
I could compile qt service 2.6.1 with Qt4.7, Visual Studio 2008 and Window XP.
You might have problem with your environment , or forget ‘C:QtQtService2.6_1> configure -library’ before ‘qmake’.
If you want static library, you should do it without parameter ( ex) ‘C:QtQtService2.6_1> configure’ ).
OK?
2010年12月28日 @ 02:03:48
hi guy, the InteractiveService app works fine to me, but i can’t debug the code in InteractiveService::start() function, what’s the matter with this problem?