サービスってのを作ったことが無いので詳しくは知りませんが
サーバってのは必ずしもネットワークの向こうにあるコンピュータを指しません。
たとえば、COM インプロセスサーバなんてのは、実体はローカルコンピュータ内にある
EXE だったり DLL だったりしますが、他のプログラムに機能を提供するという意味で
広義の「サーバ」と呼ばれます。
ただ、前述の MSDN 抜粋のサーバってのは狭義の意味で、ネットワークサーバのこと
でしょうから、そのビルド時のメッセージに出たサーバ云々と
GetFileInformationByHandle の成功/失敗は無関係だと思われますが。
あぁ… ATL 使ってるからですね。
ATL ってのは COM コンポーネントを簡単に作るためのものですから。
まさに例に出した「COM サーバ」を作ってたわけですね。
> そこで 変わりに
> Uninstall();を記述するか
これって本当に問題ない?用途的におかしいような・・・
# 言葉通りの動作するはずですけど・・・(^^;
> PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
> このようにすると正常に終了するみたいです
これの意図がわかりませんが、Run 内にメッセージループがあるから
メッセージ飛ばさなくてもreturn しちゃえば済むのでは・・・(^^;
気になるのは、PostThreadMessage の後にメッセージループを書いてるんじゃないの?
と言うことだけなんですけど、これって問題ないのかな?
# 個人的にはあまりよろしくないような気がする・・・(^^;
# 動作自体には問題ないのでしょうけどね・・・
サーバー云々は・・・COM からみてのサーバーとかだったような?
どっかにその辺りの記述があったような気もする・・・
# その辺りの言葉の使い方は別にどうでもいいと思うけどね・・・動作がはっきりしてれば
(^^;
なんにせよ、OS 種別としてのServer = サーバーと言ってるとは限らないって事ですね。
サービスやCOM から見ると、実行時の親をサーバーと呼んでるみたいです。
# 私の認識なので、違ったらどなたか訂正よろしく(^^;
シャノン さんへ
私の参考書「VISUAL C++6.0 ATLによる COM プログラミング入門」の14ページ
にこんなことが書かれていて「サーバー」と言う機能に該当しないものを作っている
意識で降りました
書籍一部引用
「ビューを持つコントロールをACTIVEX COMコントロールと呼び
ビューが無いものをACTIVEX COMサービスと呼びます
また、
ACTIVEX COMの呼び出しをサポートする実行モジュールを
ACTIVEX COM実行モジュールと呼びます(EXEタイプ)
これらは
どれもクライアント/サーバーで分類するとサーバーに属します」
「これらは」の意味を「ビューを持つEXE」だけが「サーバー」と呼ばれるのだと
勘違いしていたようです
つまり、ビューを持つと言う意味と、サーバーと言う意味にはビューは関係なく
「ACTIVEX COM」を使用するすべては、呼び出され方または、実行の仕方で
「サーバー」になりえると言うことのようです
大変申し訳ございませんが、「サーバー解釈論議」ついては尽きる事がなさそうなので
まことに勝手ながら、ここらで打ち切らさせていただきます
ありがとうございました
あいる さんへ
「TLCSVC6」これが今作っている本当の名前です、書き直すの面倒になったので
デバックウィンドウはそのままコピペします
>#これの意図がわかりませんが、Run 内にメッセージループがあるから
>#メッセージ飛ばさなくてもreturn しちゃえば済むのでは・・・(^^;
「return しちゃえば済むのでは」こんなこと全然思っても見てませんでした
やってみたら「PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);」は
必要なくなりました
そして
KillTimer(NULL, m_timer);
SetServiceStatus(SERVICE_STOP_PENDING);
return ;
この方法でデバック・ステップ実行(以降も同様)を行い終了まで実行すると
デバックウィンドにこのように表示されます
システムが表示する「アサーサッション」の表示等は表示されずに終了できるみたい
なのですが(タスクマネージャも確認しました)
「例外処理」がちょっと気になりました、意味はまだわかってません、今後調べます
ーーーーーーーーーーーーーーーーーーーーーーーーーー
例外処理 (初回) は TLCSVC6.exe (KERNEL32.DLL) にあります: 0x000006EF: (名前があ
りません)。
スレッド 0x358 終了、終了コード 0 (0x0)。
プログラム 'E:\DEVPROJECTV6\TLCSVC6\Debug\TLCSVC6.exe' はコード 0 (0x0) で終了しまし
た。
ーーーーーーーーーーーーーーーーーーーーーーーーーー
こう、記述を変更して再実行
KillTimer(NULL, m_timer);
Uninstall();
return ;
結果 こうなりました
ーーーーーーーーーーーーーーーーーーーーーーーーーー
スレッド 0xEF5 終了、終了コード 0 (0x0)。
プログラム 'E:\DEVPROJECTV6\TLCSVC6\Debug\TLCSVC6.exe' はコード 0 (0x0) で終了しまし
た。
ーーーーーーーーーーーーーーーーーーーーーーーーーー
「Uninstall」を使ってみた発想は単純にAppWizardが生成したコードを眺めなおしたら
ただの直感で「アンインストール」と言う言葉に引かれて使ってしまいました
現在の最終ソース(一部割愛)
ーーーーーーーーーーーーーーーーーーーーーーーーーーー
void CServiceModule::Run()
{
_Module.dwThreadID = GetCurrentThreadId();
・
・
AppWizardが生成したコード
・
・
MSG msg;
↓↓↓↓ここから私がコーディングしたところ
// ユーザーコーディング ST
// Handlerも同様に設定すること ←先に参考リンクを見て自分に言い聞かせるための
メモです(SetTimerに対するもの)
m_timer = SetTimer(NULL, NULL, 1000, NULL); //1秒設定
GetCurrentDirectory(sizeof(dir_str),dir_str);
strcat(dir_str,\\SCRIDX\\TLCSVC.IDX);
↑↑↑
ここの実際のファオルダ名称を変更し以下の関数が
失敗する用にしてデバックしてます
m_chkfil = CreateFile(
dir_str ,
GENERIC_READ|GENERIC_WRITE ,
FILE_SHARE_READ ,
NULL ,
OPEN_EXISTING ,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH |
FILE_FLAG_RANDOM_ACCESS ,
NULL);
if(m_chkfil == INVALID_HANDLE_VALUE ){
sprintf(m_error_str,%s,GetSystemMessage(GetLastError()));
MessageBox(NULL,m_error_str, err,MB_OK);
KillTimer(NULL, m_timer);
Uninstall();
//SetServiceStatus(SERVICE_STOP_PENDING);
//PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
return ;
}else{
GetFileInformationByHandle(m_chkfil,&m_fil_info);
GetFileTime(m_chkfil,
&m_Create_Time,&m_LastAccess_Time,&m_LastWrite_Time);
}
// ユーザーコーディング ED
↑↑↑↑ ここまで
while (GetMessage(&msg, 0, 0, 0))
{
if(msg.message == WM_TIMER) TLC_FIL_CHK(); ←これは私が追加したところ
です
DispatchMessage(&msg);
}
_Module.RevokeClassObjects();
CoUninitialize();
}
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
CreateFileの部分は、今後さらに書き直しますので気にしないでください
ちょっとご紹介
(私にとっては、便利だったので、既に知っている人にはどうでもいい事ですが)
http://www.roy.hi-ho.ne.jp/pastel/home/VC/errormsg.html
はじめまして
ぽち といいます
ご存知かも知れませんが「VC6++ ATL サービス」を作成したときに参考にしたHPです。
http://program.station.ez-net.jp/special/vc/atl/service_vc6.asp
# 初めてサービスを作る私にもかなり参考になりました。
# 紹介だけというのも寂しいので、チョコッと書かせていただきます。
ATLのサービスをビルドすると
・デバッグビルド:ローカルサーバー
・リリースビルド:サービス
として登録されます。
# ローカルサーバーとして登録する理由としては、デバッグできるようにとのことです
# 間違ってたらすいません。
デバッグされていると言うことはローカルサーバーとして登録されているので、ビルド
の結果に
---------------------------
リンク中...
登録を行っています
サーバー登録が完了しました! ←← ここ
ブラウザ データベースを作成中...
HOGEHOGE.exe - エラー 0、警告 0
---------------------------
こう出るわけです。
サービスとして登録すると、コントロールパネルの「サービス」から操作が可能となり
ます。
# ローカルサーバーでは、「サービス」からの操作はできません。
ここで本題なのですが(長くなってすいません)、問題のSetServiceStatus()はサービス
として登録しないと(?)実行できなかったと思います。
# おそらくこれが↓↓↓にあたるのでは?
ーーーーーーーーーーーーーーーーーーーーーーーーーー
例外処理 (初回) は TLCSVC6.exe (KERNEL32.DLL) にあります: 0x000006EF: (名前があ
りません)。
スレッド 0x358 終了、終了コード 0 (0x0)。
プログラム 'E:\DEVPROJECTV6\TLCSVC6\Debug\TLCSVC6.exe' はコード 0 (0x0) で終了
しまし
た。
ーーーーーーーーーーーーーーーーーーーーーーーーーー
解決策としては
・ローカルサーバーとして登録したらSetServiceStatus()を使用しない
・サービスと登録したらSetServiceStatus()を実行する
ローカルサーバーとサービスの見分けは、確かmService(BOOL型)という変数をチェック
とするとわかります。
# mServiceをいじっている箇所は_tWinMain()にあります。
# 長々書いてしまいましたが、ここまで書いてはずしていたらすいませんm(_ _)m
えーとですね・・・Uninstall は、MSDN より・・・
「実行中のサービスを停止し、サービス コントロール マネージャ データベースから削除しま
す。」
と言う動作します。問題大有りではないかと・・・(^^;
# 起動毎にインストール/アンインストールは不思議な動作かと・・・
なんにせよ、atlbase.h をまずは見た方がいいかと・・・
# VC6 にあったかな?ないかも?(^^;
それと、サービスステータスの意味ももう一度確認した方がいいと思います。
# 後始末してからPENDING ってのはちょっとね・・・
もうひとつ・・・return する前に後始末はきちんと終わらせましょう。
_Module.RevokeClassObjects();
CoUninitialize();
が呼ばれてないですね・・・
蛇足ですが、CoInitialize とCoUninitialize はいらないような・・・
AppWizard ではWinMain もServiceMain も書き出してくれてないと思いますが、
ServiceMain で呼んでるはずです。
# 手元にATL7.0 のソースしかなくていまいち自信なし(^^;
# ATL7.0 では開発がかなり楽にできるようなってます(^^;
ぽち さん 情報ありがとうございます
>mService
探してみます
あいるさんへ
>AppWizard ではWinMain もServiceMain も書き出してくれてないと思いますが、
VC6では書き出されていました
たぶん「CServiceModule::ServiceMain」と
「extern C int WINAPI _tWinMain(HINSTANCE hInstance,・・・」
のことだと思います
ご指摘頂いたそれぞれ、確認してから次に進みたいと思います
ぽち さん の解説からこのようにしてみました
----------------
sprintf(m_error_str,%s,GetSystemMessage(GetLastError()));
MessageBox(NULL,m_error_str, err,MB_OK);
KillTimer(NULL, m_timer);
if(m_bService == TRUE)
SetServiceStatus(SERVICE_STOP_PENDING);
return ;
----------------
一度ここで済みにさせていただきます
ご両名の方々、いろいろ親切に解説していただき真にありがとうございました