ファイルタイムスタンプ取得 +α について

[戻る]
wood 2004/09/04(土) 08:06:00
VC6 ATL サービス.EXE 
Win XP SP1a

質問は2つあります
−−−−−−−−−−−−−ソース−−−−−−−−−−−−−
void CServiceModule::Run()
   ・
   ・
    MSG msg;
// ユーザーコーディング ST
 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);
   SetServiceStatus(SERVICE_STOPPED); ←ここ(2つ目質問
 }

// ユーザーコーディング ED

    while (GetMessage(&msg, 0, 0, 0))
   ・
   ・
−−−−−−−−−−−−−ソース−−−−−−−−−−−−−
1つ目:表題にもあります
  ファイルのタイムスタンプを取得するために関数「GetFileTime」を使用する
  と思うのですが、この関数の引数で、HANDLEが必要とされるため
  CreateFile関数を使用してファイルハンドルを取得しなければいけない
    ようなのですが
  CreateFile関数は使用するとファイルをオープンしてしまう様に解釈出来て
  しまうのですが間違いでしょうか?

  間違いでなければ、ファイルオープンをせづに、ハンドルの習得または
  ファイルタイムスタンプの取得を行うことは出来ませんでしょうか
  
  出来るのであれば、どんな関数を使って取得すればよいか教えてください

2つ目:初期エラー発生時にサービスEXEのSHUTDOWNまたはSTOPをしたいと考え
  SetServiceStatus(SERVICE_STOPPED);
  のような記述をしました
  コンパイルが通って、デバック実行したら アクセスバイオレーション
  起こしてしまいました
  目的にあったコーディングでは無いようなので、この目的を達成するためには
  どのようにコーディングしたらよいでしょうか

参考書
  技術評論社 「VisualC++6.0 ATLによるCOM プログラミング入門」
  読んでみたがほとんど意味不明(理解できない)
参考にしたページ
  http://program.station.ez-net.jp/special/vc/atl/service_vc6.asp
周辺で聞ける人いません(汎用コボラー のみ)

wood 2004/09/04(土) 08:16:57
追伸
「MFCは使えない」みたいな解説ありましたのでWin32APIでの回答をお願いします

wood 2004/09/04(土) 08:30:56
環境変更
 VC6 SP6 WinXP(Pro) SP2

実行環境
 開発中および、デバック中はWinXP(Pro) SP2
 本稼動は、Win2000(Pro)で実行したいと思ってます
 

瀬戸っぷ [E-Mail] 2004/09/04(土) 14:09:11
>   CreateFile関数は使用するとファイルをオープンしてしまう様に解釈出来て
>   しまうのですが間違いでしょうか?

MSDNを参照すると、第二引数を0とするコトで「問い合わせアクセス」が可能なようです。
その場合、「最終アクセス時間」が更新されるかどうかは不明です。
# 試したことはありませんが。

>   間違いでなければ、ファイルオープンをせづに、ハンドルの習得または
>   ファイルタイムスタンプの取得を行うことは出来ませんでしょうか
>   出来るのであれば、どんな関数を使って取得すればよいか教えてください

FindFirstFile()で、WIN32_FIND_DATA構造体に取得できるかと。

成歩堂 2004/09/04(土) 16:09:46
ただ、GetFileTimeの第一引数について、MSDNにはこう書かれているのですが。

>ファイルのハンドルを指定します。このハンドルは、GENERIC_READ アクセスを持って
いなければなりません。

wood 2004/09/04(土) 16:45:21
成歩堂さん はじめまして
>ただ、GetFileTimeの第一引数について、MSDNにはこう書かれているのですが。
>ファイルのハンドルを指定します。このハンドルは、GENERIC_READ アクセスを持って
>いなければなりません。

そのとおり CreateFile を行う際に
GENERIC_READ を指定したソースを最初に掲示したつもりですが、方法が違うのでしょうか?
何に対する回答なのか不明です


瀬戸っぷ さん 早々の回答ありがとうございます
>FindFirstFile()で、WIN32_FIND_DATA構造体に取得できるかと。
いわれてみれば記憶の片隅に「FindFirstFile」聞いたことあります
自宅に帰ったら早速調べてみます

瀬戸っぷ [E-Mail] 2004/09/04(土) 17:01:30
> ただ、GetFileTimeの第一引数について、MSDNにはこう書かれているのですが。
> >ファイルのハンドルを指定します。このハンドルは、GENERIC_READ アクセスを持っ> >いなければなりません。

ありゃ、調べていなかった。(というか、第二引数以降の型を確認しただけで(^_^;))
フォローどうもです。

アクセス無しって条件なら私はFindFrstFile()で処理しようとしますので。
(単体ファイルが対象だとCreateFile()とGetFileTime()かも知れませんが。)

成歩堂 2004/09/04(土) 20:48:33
WOODさん初めまして

>何に対する回答なのか不明です

話の流れで瀬戸っぷさんの書き込みに対して書いただけです。

前後しますが

>そのとおり CreateFile を行う際に
>GENERIC_READ を指定したソースを最初に掲示したつもりですが、方法が違うのでし
ょうか?

その通りと言われましても、少なくとも質問でそれと明文化されてませんし。

wood 2004/09/04(土) 22:31:23
再度 質問1の主旨
単体ファイルが更新された日付・時間の取得が対象だとCreateFile()とGetFileTime()
の組み合わせ以外ない物でしょうか
つまりファイルをオープンしなければ、取得できないのでしょうか

成歩堂 2004/09/05(日) 13:51:55
(最初の質問が端折られたようにしか見えませんが…)

最初の質問や途中の私に対するレスから勘案するに、WOODさんは次の点が知りたい
のではないのですか?

>CreateFile 以外で GENERIC_READ 属性を持つ FileHandle を取得できる関数が
>有るか無いか。

ならば、少なくとも私は無いと思っています。

ちなみに既に書きましたように、GetFileTime に渡す FileHandle には GENERIC_READ
属性が付けられていなければなりませんが、この仕組みはこのケースに限らず
GetFileSize 等でも同様です。
インターネット上で見つかるサンプルソースでも CreateFile との組み合わせ以外は
見かけたことはありません。

通りすがり 2004/09/05(日) 17:45:41
>再度 質問1の主旨
>単体ファイルが更新された日付・時間の取得が対象だとCreateFile()とGetFileTime()
>の組み合わせ以外ない物でしょうか
>つまりファイルをオープンしなければ、取得できないのでしょうか

瀬戸っぷさんが
>FindFirstFile()で、WIN32_FIND_DATA構造体に取得できるかと。
と書かれていますよ。
FindCloseしなければならないので手間はオープンする場合と同じだと思いますが。

wood 2004/09/05(日) 18:59:53
見つけた!
瀬戸っぷさんが教えてくれた「問い合わせアクセス」がでファイルの状態を取得可能
関数ありました

秀和システム 「Visual C++ 逆引き大全」の399に解説ありました
関数名は「GetFileInformationByHandle」だそうです

まだ、試していないのと 質問2も解決していないのでもう少しお付き合い
ください

補足 2004/09/05(日) 20:36:38
この関数は、オペレーティングシステムのネットワークコンポーネントと、それに接続
されるサーバーの種類によっては、失敗することがあります。したがって、アプリケー
ションの動作環境がはっきりしている場合以外は、この関数を使わないようにしてくだ
さい。

wood 2004/09/05(日) 21:49:40
今回はローカルサービスとしてexeを作成するつもりですが
>サーバーの種類によっては、失敗することがあります
せっかく補足していただいたので
失敗しないサーバーの種類とはどんなものがあり、失敗するサーバーの種類とは
どんなものがあるのでしょうか
向学のため是非教えてください

wood 2004/09/05(日) 21:58:11
サービス.EXE本体がネットワークドライブに存在した場合は
>補足 2004/09/05(日) 20:36:38
に該当するのでしょうか?

wood 2004/09/06(月) 06:10:55
最初に提示してある
> GetCurrentDirectory(sizeof(dir_str),dir_str);
> strcat(dir_str,"\\SCRIDX\\TLCSVC.IDX");
> m_chkfil =  CreateFile(
の方法だと、自分の意識していないところで
 オペレーティングシステムのネットワークコンポーネントと、
 それに接続されるサーバー
になるんでしょうか

>wood 2004/09/05(日) 18:59:53
の時点でMSDNを読んで、
>補足 2004/09/05(日) 20:36:38
は自分には該当しないと思っていましたが、間違いなのでしょうか

デバック環境では、「GetFileInformationByHandle」が成功しているように
見受けられるのですが...

補足 2004/09/06(月) 10:39:22
GetFileInformationByHandle は _fstat Cランタイム関数と同等とされているよう
です。
しかし、Win32s バージョン1.1ではサポートされていないということと、NEC PC98
の Windows9x からネットワーク上の Windows9x を参照した場合は、ファイル属性
が取得出来ないケースがあるらしいです。その他は分かりません。

MSDN に記載されている情報以上のことはなかなか得難いと思いますので、不安で
あれば定石の手を使った方が安全かと。

wood 2004/09/06(月) 21:12:25
不安をあおって「GetFileInformationByHandle」を使わせたくない理由
はなんでしょうか?

Win2k(Pro) or WinXP(PRO) の ローカルサービスとして実行する
と明示していることにたいして「Windows9x」補足はどのように関わり
また、明示されないケースをどのように信用すればよいのでしょうか

MSDNのコピペを提示して頂いたと言うことは、それぞれの詳細情報をお持ちで解説可能
な方が、回答者としてキチンとした回答していただけるものと期待したのですが..

「定石」とは何でしょうか?
回答者が思っている方法が一番正しいことなので、プログラミング初心者は
記号を覚えるのと同様に、意味はわからなくてもいいから、そう思えということですか

補足 2004/09/06(月) 23:58:29
この際色々書かせて頂きます。

>不安をあおって「GetFileInformationByHandle」を使わせたくない理由

そういうつもりは毛頭ありません。

>Win2k(Pro) or WinXP(PRO) の ローカルサービスとして実行する
>と明示していることにたいして「Windows9x」補足はどのように関わり
>また、明示されないケースをどのように信用すればよいのでしょうか

知っている情報をすべて出したのみです。それを取捨選択するのは貴方の自由
でしょう。

>MSDNのコピペを提示して頂いたと言うことは、それぞれの詳細情報をお持ちで解説可>な方が、回答者としてキチンとした回答していただけるものと期待したのですが..

MSDNに書かれているからこそ大事な事だと思ってコピペしただけですが、何が
不満なのでしょうか?
MSDN著者以上の情報をよこさないならば余計な情報は書くなと仰るならば、
それこそあらかじめ宣言なさって下さい。
(そういう割には、貴方はつい最近、中途半端に横レスを入れたまま放置されている
トピックがありますね。貴方が書き込んだレスは例外なのでしょうか?)

>「定石」とは何でしょうか?

考えられる不具合を回避するのに最善な方法を取るべきでしょうという意味です。
既知の方法を取るのが一番無難な方法ではないでしょうか。

瀬戸っぷさんがわざわざ FindFirstFile を提示してくださっているのに、動作
報告など全く無いまま GetFileInformationByHandle を使いたがる理由は何なの
でしょうか?
通常の運用であれば CreateFile で GENERIC_READ 指定しても良いはずです。

普段から質問の初心者に対して厳しい言葉を発している貴方ですが、ご自身に対しては
随分と甘いのですね。

wood 2004/09/07(火) 07:01:26
FindFirstFile とは複数のまたは、同一の拡張子を持つファイルを「列挙」する関数
と他の解説書から、解釈いたしました

GetFileInformationByHandleは特定の単一ファイルを指定し、そのファイル情報を取得
する関数と解説書より解釈しました

私のニーズは、後者(特定の単一ファイルを指定し、そのファイル情報を取得)です
・ファイル情報取得の際、ファイルの物理オープンはしたくない
  物理的オープンの発生は、監視しているファイルをメンテナンスしている
  プログラムに悪影響(ファイルロック)等を与える危険性を含んでいるから
  です

・取得したいファイルの場所およびファイル名は特定のもの

成歩堂さんが記載した
>CreateFile 以外で GENERIC_READ 属性を持つ FileHandle を取得できる関数が
>有るか無いか。
については、ファイルハンドルの取得方法についての質問じゃなかった
つまりニーズにあった記載ではなかったので放置しました


>wood 2004/09/05(日) 21:58:11
>サービス.EXE本体がネットワークドライブに存在した場合は
については
>補足 2004/09/05(日) 20:36:38
の記載に「ネットワーク」と言う言葉があったのでそれに対して
具体的「ケース」を提示し、再質問したまでのことで、
実際の運用には関係ございません

MSDNのコピペについては、回答内容として記載されましたので、
回答内容の不明点を再質問したまでです
また、「Windows9x」についても同様です

MSDNの大雑把な内容+
>失敗することがあります。
どんなケースで失敗するのか、一例くらいは知りたくなりませんか?

「Windows9x」についても
>取得出来ないケースがあるらしいです
ケースってなにどんなこと、「らしい」とは何?、
それはWinXPにおいても同様に起こりうること?
正確な情報をいただけなければ、情報の選択なんて俺にはできません
だから質問しているのです

質問の回答として「らしい」じゃわからないから再質問が増えるんです
理解できないことを質問する掲示板だと思って利用してますが
聞いちゃいけない掲示板だったのでしょうか

>考えられる不具合
とは、なに?
ネットワークをダウンさせる可能性があるとか?(ローカルで実行するのに)
アクセスバイオレーションを引き起こす可能性があるとか?
何らかのモジュール(DLLやOCX)内部でページ違反起す可能性がある?

少なくとも、今のデバック環境においては発生していませんが
「らしい」じゃわかりません、具体例ください

俺の知らない、解釈できない、知識範囲外の情報だからこそ解説してほしいんです

具体的問題点を知ってこそ良いものを作ることが出来ると
何故わかっていただけないのでしょう?

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

このスレッドは俺の質問コーナーだ!

他のスレッドの事を持ち出すのなら、それは雑談掲示板へ行ってください
ここの利用方法に反します(質問ニーズにあった参考記事は別)
当然、どのスレッドなのかも、リンク張ってください

>中途半端に横レス
に対して、その質問者から、俺のように「ここの所、ここの記載の意味がわかりませ
ん、再度解説してください」と言う書き込みありましたでしょうか
あったんだったら見逃してました

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

シャノン 2004/09/07(火) 09:58:19
CreateFile は、Win32 API でファイルを扱う際の、最も基点かつ低レベルな関数です
(NTDLL.DLL 除く)。
対して GetFileInformationByHandle や FindFirstFile は、より高レベルな関数ですの
で、ひょっとしたらそれらは内部で CreateFile を呼んでいる可能性も否定できませ
ん。
DLL の逆汗でもすれば、真偽は明らかになるかもしれませんが、その結果さえいつまで
通用するか保証はできません。
明示的に CreateFile しなきゃオープンされないとは限りませんよ、ということです。

> FindFirstFile とは複数のまたは、同一の拡張子を持つファイルを「列挙」する関数
> と他の解説書から、解釈いたしました

> GetFileInformationByHandleは特定の単一ファイルを指定し、そのファイル情報を
> 取得する関数と解説書より解釈しました

> 私のニーズは、後者(特定の単一ファイルを指定し、そのファイル情報を取得)です

> 成歩堂さんが記載した
> >CreateFile 以外で GENERIC_READ 属性を持つ FileHandle を取得できる関数が
> >有るか無いか。
> については、ファイルハンドルの取得方法についての質問じゃなかった
> つまりニーズにあった記載ではなかったので放置しました

ニーズに合った解答が欲しいのは誰しも同じですが、放置はいけません放置は。
ニーズに合ってないなら合ってないと、一言言うべきでしょう。

> どんなケースで失敗するのか、一例くらいは知りたくなりませんか?

知りたいのは当然ですが、ではどうすれば知ることができるのでしょう?
MSDN には、どのような場合に失敗し、どのような場合なら成功するのか明記されていま
せん。
MSDN に書かれていない以上、これ以上取得できる一次情報はありません。
確実な情報が欲しければ、Microsoft に問い合わせるくらいしかないでしょう。
また、多少確実性は落ちるとしても、成功/失敗の経験談を探すという手もあるでしょ
う。
それらを探すのは、回答者の責任ですか?
手がかりをもらったら、それをもとに調べるという発想はありませんか?

> 質問の回答として「らしい」じゃわからないから再質問が増えるんです
> 理解できないことを質問する掲示板だと思って利用してますが
> 聞いちゃいけない掲示板だったのでしょうか

では、回答者は一から十まで理解していなければ回答してはいけませんか?
回答者にだって「らしい」という以上のことはわかりません。

> ここの利用方法に反します(質問ニーズにあった参考記事は別)

そんな規約はどこにもありません。

少々、自己中が過ぎやしませんか?

アイススケーター 2004/09/07(火) 10:58:22
私は、_findfirst(FindFirstFileと動作はほぼ同じ)でファイル情報を取得していました
が、単体ファイルでもOKのはずですが。
なにか勘違いしてませんか?
一度、冷静になられてはいかがでしょう。

あいる 2004/09/07(火) 11:58:58
誰も触ってないようなので、質問2について・・・
何か参考になることをと思ったのですが、情報が足りません・・・orz

なので、質問・・・
1、エラーの原因は特定できませんか?
   実際にどこで落ちるのか全くわからないのでしょうか?
# 私の予想はTimer 周りでないかと・・・

2、サービスに停止の権限は与えてありますか?
# 関係ないかも?

3、手順として、SERVICE_STOP_PENDING してからSERVICE_STOPPED の方がよいと思います
が、
  そこは関係してないですか?
# 状態の値を設定するだけだったと思うから関係ないとは思いますが・・・

とりあえず、Timer 止めても同じ症状なのか等チェックしてみてはいかがですか?

wood 2004/09/07(火) 21:35:11
シャノン さん ありがとうございます
言いたいことは、わかりました
しかし、一言言わせてもらいます(最後に書き込んであることに対して)
>> ここの利用方法に反します(質問ニーズにあった参考記事は別)
>そんな規約はどこにもありません。
>少々、自己中が過ぎやしませんか?
他のスレッドの事ですが、誹謗・中傷に当たる発言と受け取りましたので
「利用方法に反します」と書き込みました

>(そういう割には、貴方はつい最近、中途半端に横レスを入れたまま放置されている
>トピックがありますね。貴方が書き込んだレスは例外なのでしょうか?)
この書き込みは私の質問になんら関係のある書き込みとは思えませんでした

アイススケーター さんありがとうございます
ご指摘の関数は、特定ファイル1つの情報を探す場合FindFirstFileの後に
必ず、FindnextFileを呼ばないと取得できないもの、と思ってました

あいる さん
質問2に触れていただきありがとうございます

エラー発生箇所
 デバックのステップ実行ではAPPWIZARDが生成した「サービス.exe」のソース
 サービス.CPP 内にある
 void CServiceModule::SetServiceStatus(DWORD dwState)
 {
    m_status.dwCurrentState = dwState;
    ::SetServiceStatus(m_hServiceStatus, &m_status);
 }
 
 ::SetServiceStatus(m_hServiceStatus, &m_status);この関数に
 ステップインしたときに発生します


エラー内容
 「ハンドルされていない例外は サービス.EXE(ADVAPI32.DLL)にあります
  0xC0000005 アクセスバイオレーション」


timer 気づきませんでした 試してみます

2.はadministrator権限を持つユーザーで開発していますが
  他にも何か設定が必要なのでしょうか
  方法を教えてください

3.最初に提示してあるとおり
  SetServiceStatus(SERVICE_STOPPED); 

  これだけしかしていません
  先にSERVICE_STOP_PENDINGをやってみます 


このコーディングを
if(m_chkfil == INVALID_HANDLE_VALUE ){
   sprintf(m_error_str,"%s",GetSystemMessage(GetLastError()));
   MessageBox(NULL,m_error_str,"   err",MB_OK);
   SetServiceStatus(SERVICE_STOPPED); 
}
 
        ↓↓

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);
   SetServiceStatus(SERVICE_STOP_PENDING); 

}
に変えて試して見ます

記述・使い方に間違いがあれば、ご指摘お願いします

wood 2004/09/07(火) 21:48:46
あいる さん ありがとうございました
エラーが出ることなく、終了させることが出来ました

質問2については解決にしたいところですが
あいる さんがもし、2番に書いてくれた方法を教授していただけるなら
方法を教えてください

あいる 2004/09/07(火) 23:08:02
できれば、実際にどんなコードになったのか書いておいた方がいいかと・・・(^^;
# 解決しましたじゃなんとなく・・・ね(^^;
# 結局Timer だったのかな??

2は、サービスのInitialize の時構造体にセットする値の話なので、最初に提示されて
いる参考サイトにあります
# サイトにある書き方とだいぶ違って書かれていたので、詳しく見てないのかもと思い
聞いてみました。
# 要はSERVICE_ACCEPT_STOP は指定されていますか?って事ですね。
# 内部で処理される場合は特に関係ないと思いますが、もしかしたらあるかな?と思
い・・・

3についてなのですが・・・変更しましたか?
もし変更したのであれば、STOP_PENDING にして、KillTimer して、STOPPED にする方が
いいかも?
# STOP_PENDING は停止中なので、このステータス時は停止前に処理すべき事を記述し
# 後片付けが終わってからSTOPPED にするのが状態遷移的に美しいかと思います。

私は特に、回答したわけではないので・・・陥りやすい所を聞いてみたまでです(^^;

wood 2004/09/07(火) 23:34:57
このコーディングを
if(m_chkfil == INVALID_HANDLE_VALUE ){
   sprintf(m_error_str,"%s",GetSystemMessage(GetLastError()));
   MessageBox(NULL,m_error_str,"   err",MB_OK);
   SetServiceStatus(SERVICE_STOPPED); 
}
 
        ↓↓

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);
   SetServiceStatus(SERVICE_STOP_PENDING); 

}

のままです、もしかしてただ異常終了しなくなっただけで解決したと思ったけど
違うのかも...
デバックウィンドウには「XXX は0x00で終了しました」と出ていましたので
てっきり解決したと思い込んでいました

あいる さん のアドバイスからすると、なんか足りないみたいですね

>結局Timer だったのかな??
たぶんそうだと思うのですが、
いっぺんに「SetServiceStatus(SERVICE_STOP_PENDING);」も変えた結果なので
一概にはいえません、もう一度再現ステップ踏んで見ます
後日、結果書き込みます

tetrapod 2004/09/08(水) 10:24:47
GetFileInformationByHandle についてちょっと調べてみました。

この API は UNIX の fstat() を意識して作られています。ただ FileSystem の違い上、
struct stat と BY_HANDLE_FILE_INFORMATION は同一になりません。

そのため Cygwin の fstat はさらに他の情報も調べているので激遅になっています
http://www.kaimei.org/note/mag/in_cyg.html
また WIN32s では API 自体は成功するが一部情報が入っていないという記述がありました。
http://kmaebashi.com/bbs/bbs09.html

MSDN の記載
"May fail, return partial information ..."
の意味は私は以下のように解釈しましたが正しいかどうかは定かではありません。

ネットワークドライブの割り当て等で接続した先 例: net use n: \\server\share
のファイルは、当該サーバに存在します(当然)
当該サーバのファイルシステム/OS が Windows と同一であるとは限りません。
たとえば接続先はいにしえの MS-DOS MS-Networks server かもしれませんし、
OS/2 か samba か NetWare か、あるいは私の見たことの無い OS かもしれません。
接続先ファイルシステム/OS によっては Windows でいうところの
「ファイル属性」「タイムスタンプ」の概念が無いかもしれません。
そーいう場合には(すべての)内容が得られるとは限らない、ということのようです。
同様の記載は FindFirstFile/WIN32_FIND_DATA のところにもあります。

サーバーがどうのこうのは W2k Server Edition 等や SQL サーバとは無関係かと。

wood 2004/09/06(月) 06:10:55
ローカルサービスをネットワークドライブにインストールすることは可能です。
ローカルサービスを FAT12 なフロッピーディスクにインストールすることは可能です。
# 実用的運用ができるかどうかは別。

補足 2004/09/06(月) 23:58:29
さんの言葉を借りておきます。
掲示板に発言された情報を「取捨選択するのは貴方の自由」です。
ただ、「俺にはそんな情報は不要だ」と公言するのはいかがなものかと。

wood 2004/09/09(木) 07:25:41
tetrapod さん
大変ご苦労をおかけし、貴重な情報を探してくれた事に感謝いたします

雑談の法へ
「シャノン さんへ」あてに書いたとおり、障害が発生してから悩むことにしました

ご尽力を尽くしてくださった、大変ご迷惑をおかけしました
質問 1 については、この記載を持ってクローズいたします

なお、質問 2 については、「あいる さん」への報告は
この時点でかけません(試してません)ので、解決マークのチェックは
入れません

wood 2004/09/10(金) 05:30:18
あいる さんへ
timer は関係無いみたいです
SetServiceStatus(SERVICE_STOPPED);
をいきなり使おうとするから、異常終了メッセージが出るようです

そこで 変わりに
 Uninstall();を記述するか


教えてもらったように記述をし
  SetServiceStatus(SERVICE_STOP_PENDING);
さらに
  PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
このようにすると
正常に終了するみたいです

ただし。Uninstall では無い、後者の方法ですと
デバックウィンドウに0X00による正常終了メッセージの前に「名前がありません」
の表示がされてます


なお、お騒がせしている「サーバー」と言う言葉について
プロジェクトのビルドの最中にビルドウィンドウに

−−−−−−−−−−−−−−−−−−−−−−−−−−−
リンク中...
登録を行っています
サーバー登録が完了しました!  ←← ここ
ブラウザ データベースを作成中...

HOGEHOGE.exe - エラー 0、警告 0
−−−−−−−−−−−−−−−−−−−−−−−−−−−

「サーバー登録が完了しました!」と出てました、詳細は不明(説明できません)ですが
普段「エラー 0、警告 0」しか見ていませんでしたから気づきませんでしたけど

何サーバーか良くわからないけど、たとえローカル(単体マシン)OSでも
サーバーと言う種類のものに何かしてるんですね  

シャノン 2004/09/10(金) 09:34:55
サービスってのを作ったことが無いので詳しくは知りませんが
サーバってのは必ずしもネットワークの向こうにあるコンピュータを指しません。

たとえば、COM インプロセスサーバなんてのは、実体はローカルコンピュータ内にある
EXE だったり DLL だったりしますが、他のプログラムに機能を提供するという意味で
広義の「サーバ」と呼ばれます。

ただ、前述の MSDN 抜粋のサーバってのは狭義の意味で、ネットワークサーバのこと
でしょうから、そのビルド時のメッセージに出たサーバ云々と 
GetFileInformationByHandle の成功/失敗は無関係だと思われますが。

シャノン 2004/09/10(金) 09:36:32
あぁ… ATL 使ってるからですね。
ATL ってのは COM コンポーネントを簡単に作るためのものですから。
まさに例に出した「COM サーバ」を作ってたわけですね。

あいる 2004/09/10(金) 09:50:33
> そこで 変わりに
> Uninstall();を記述するか
これって本当に問題ない?用途的におかしいような・・・
# 言葉通りの動作するはずですけど・・・(^^;

>  PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
> このようにすると正常に終了するみたいです

これの意図がわかりませんが、Run 内にメッセージループがあるから
メッセージ飛ばさなくてもreturn しちゃえば済むのでは・・・(^^;
気になるのは、PostThreadMessage の後にメッセージループを書いてるんじゃないの?
と言うことだけなんですけど、これって問題ないのかな?
# 個人的にはあまりよろしくないような気がする・・・(^^;
# 動作自体には問題ないのでしょうけどね・・・

サーバー云々は・・・COM からみてのサーバーとかだったような?
どっかにその辺りの記述があったような気もする・・・
# その辺りの言葉の使い方は別にどうでもいいと思うけどね・・・動作がはっきりしてれば
(^^;
なんにせよ、OS 種別としてのServer = サーバーと言ってるとは限らないって事ですね。
サービスやCOM から見ると、実行時の親をサーバーと呼んでるみたいです。
# 私の認識なので、違ったらどなたか訂正よろしく(^^;

wood 2004/09/11(土) 08:56:47
シャノン さんへ
私の参考書「VISUAL C++6.0 ATLによる COM プログラミング入門」の14ページ
にこんなことが書かれていて「サーバー」と言う機能に該当しないものを作っている
意識で降りました

書籍一部引用
「ビューを持つコントロールをACTIVEX COMコントロールと呼び
 ビューが無いものをACTIVEX COMサービスと呼びます
 また、
 ACTIVEX COMの呼び出しをサポートする実行モジュールを
 ACTIVEX COM実行モジュールと呼びます(EXEタイプ)
 これらは
 どれもクライアント/サーバーで分類するとサーバーに属します」

「これらは」の意味を「ビューを持つEXE」だけが「サーバー」と呼ばれるのだと
勘違いしていたようです
つまり、ビューを持つと言う意味と、サーバーと言う意味にはビューは関係なく
「ACTIVEX COM」を使用するすべては、呼び出され方または、実行の仕方で
「サーバー」になりえると言うことのようです

大変申し訳ございませんが、「サーバー解釈論議」ついては尽きる事がなさそうなので
まことに勝手ながら、ここらで打ち切らさせていただきます
ありがとうございました

wood 2004/09/11(土) 08:58:31
あいる さんへ

「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が生成したコードを眺めなおしたら
ただの直感で「アンインストール」と言う言葉に引かれて使ってしまいました

wood 2004/09/11(土) 08:59:41
現在の最終ソース(一部割愛)
ーーーーーーーーーーーーーーーーーーーーーーーーーーー
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

ぽち 2004/09/11(土) 11:38:29
はじめまして
ぽち といいます

ご存知かも知れませんが「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

あいる 2004/09/11(土) 12:15:55
えーとですね・・・Uninstall は、MSDN より・・・
「実行中のサービスを停止し、サービス コントロール マネージャ データベースから削除しま
す。」
と言う動作します。問題大有りではないかと・・・(^^;
# 起動毎にインストール/アンインストールは不思議な動作かと・・・

なんにせよ、atlbase.h をまずは見た方がいいかと・・・
# VC6 にあったかな?ないかも?(^^;

それと、サービスステータスの意味ももう一度確認した方がいいと思います。
# 後始末してからPENDING ってのはちょっとね・・・

もうひとつ・・・return する前に後始末はきちんと終わらせましょう。
    _Module.RevokeClassObjects();
    CoUninitialize();
が呼ばれてないですね・・・

蛇足ですが、CoInitialize とCoUninitialize はいらないような・・・
AppWizard ではWinMain もServiceMain も書き出してくれてないと思いますが、
ServiceMain で呼んでるはずです。
# 手元にATL7.0 のソースしかなくていまいち自信なし(^^;
# ATL7.0 では開発がかなり楽にできるようなってます(^^;

wood 2004/09/12(日) 08:46:07
ぽち さん 情報ありがとうございます
>mService
探してみます

wood 2004/09/14(火) 04:51:58
[[解決]]
あいるさんへ
>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 ;
−−−−−−−−−−−−−−−−

一度ここで済みにさせていただきます
ご両名の方々、いろいろ親切に解説していただき真にありがとうございました

古いスレッドには追加発言できません。