ATL COM AppWizard サービスでDB接続

[戻る]
4plus 2004/01/14(水) 11:21:56
WindowsXP & VC++6.0でサービスの作成を行おうと思っています。

VC++6.0起動→新規作成→ATL COM AppWizardを選択し、
サーバータイプをサービス(EXE)で作成を始めました。

サービスにやらせたいことは、
 A.一定時間時間置きにサービス内部の関数(BやCを行う)を呼び出す。
 B.オラクルデータベースにアクセスする(select文やupdate文)。
 C.(データベースから取得した情報をもとに)メールを送信する。
の3点です。
サービスにする理由は、windowsが不慮の事故等により勝手に再起動した場合に、
ユーザがログインしなくても上記動作を行えるようにしたいためです。

上記のうちA.はSetTimer、C.はBsmtp.libを使うことで何とか解決しそうな気配ですが、
B.のデータベースアクセスがうまくいきません。
MFCのサポートがないらしく、CDATABASEなどが使えないらしかったので、

TESTTBL.Hを

#define __TESTTBL_H_

class CTESTBLAccessor
{
public:
    TCHAR m_TEST1[10];

BEGIN_COLUMN_MAP(CTESTTBLAccessor)
    COLUMN_ENTRY(1, m_TEST1)
END_COLUMN_MAP()

DEFINE_COMMAND(CTESTTBLAccessor, _T(" \
    SELECT \
        TEST1, \
        FROM TEST.TBL"))

    // レコードを挿入しているときにこの関数を呼び出そうとする可能性があり
ます、また
    // 明確にそれらすべてを設定しない場合にすべてのフィールドを初期化する
可能性があります。
    void ClearRecord()
    {
        memset(this, 0, sizeof(*this));
    }
};

のように作成し、サービスのRUN()内から以下の関数を呼び出して処理を行おうと思いま
した。

int CServiceModule::callDB()
{
    CDataSource connection;
    CSession session;

        CDBPropSet    dbinit(DBPROPSET_DBINIT);
        dbinit.AddProperty(DBPROP_AUTH_PASSWORD, OLESTR("pass"));
        dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("usrid"));
        dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR
("testdata"));
        dbinit.AddProperty(DBPROP_INIT_MODE, (long)3);
        dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
        dbinit.AddProperty(DBPROP_INIT_LCID, (long)1041);
    CCommand<CAccessor<CTESTTBLAccessor> > dbtbl;
    connection.Open(_T("MSDASQL"), &dbinit);
    session.Open(connection);
    dbtbl.Open(session,"select * from tbl;");
    dbtbl.Open(session,"update tbl set test = 'aaa';");
    dbtbl.Close();
    session.Close();
    
    return 0;
}

上記のような方法で実行してみると、
select文の発行は成功し、後でデータを取得することは可能なのですが、
update文の方を実行するとexeの強制終了が起こってしまいます(強制終了されるが、更新
処理は反映されている)。
(以上からデータベースには接続できているはず)

何とかうまくデータベースにアクセスしたいのですが、改善策や他のいい方法がありまし
たら、
是非ご教授ください。

以上、よろしくお願いします。

渋木宏明(ひどり) [E-Mail] [HomePage] 2004/01/14(水) 14:15:24
>update文の方を実行するとexeの強制終了が起こってしまいます(

CCommand は、エラー発生時に例外を throw するとリファレンスで説明されています。

アプリケーションが強制終了するのは、例外を捕捉しないでほったらかしにしているか
らだと思われます。

>改善策や他のいい方法がありましたら、是非ご教授ください。

例外をきちんと捕捉して、どんなエラーが発生しているのかを確認しましょう。

どんなエラーが発生しているのか知ることは、解決のための大きな手がかりになりま
す。

4plus 2004/01/14(水) 19:48:26
渋木宏明(ひどり) 様、回答ありがとうございます。

書き忘れてしまっていたことですが、
EXE終了時にはダイアログが表示され、
ダイアログには×マークがあり、

プログラム〜〜.exeでエラーが起きました
ファイルatldbcli.hでエラーです
Expression: GetInterface() != 0
ボタンを押すと再試行します

といったメッセージが書かれています。
〜〜.exeは終了したexeで、
atldbcli.hはVCインストール時からあるデフォルトのファイルのようです。

>CCommand は、エラー発生時に例外を throw するとリファレンスで説明されています。
>アプリケーションが強制終了するのは、例外を捕捉しないでほったらかしにしているか
>らだと思われます。

例外を捕捉とは、例外処理を行うということでしょうか。
例外処理を行うには、try〜catchだろうと思い、

try
{
    dbtbl.Open(session,"update tbl set test = 'aaa';");

}
catch(・・・

のように作成してみたのですが結果は変わらず、
update文のところでEXEが終了してしまいます。

そもそもtryの使い方がよくわかってなかったり・・・
throwすると、結果どうなるかというのもわかってなかったり・・・

また、CCommandの代わりにCTableとやって実行してみたところ
update文のところでエラーは発生しなかったものの、
更新処理はされていませんでした。

>例外をきちんと捕捉して、どんなエラーが発生しているのかを確認しましょう。
>どんなエラーが発生しているのか知ることは、解決のための大きな手がかりになりま
す。

すみません、結局どんなエラーが発生しているのかよくわかりませんでした。

以上から例外処理についても勉強したほうがよいことがわかりました。

何か他にヒントなどありましたらよろしくお願いします。

渋木宏明(ひどり) [E-Mail] [HomePage] 2004/01/15(木) 03:35:03
>プログラム〜〜.exeでエラーが起きました
>ファイルatldbcli.hでエラーです
>Expression: GetInterface() != 0
>ボタンを押すと再試行します

それだけだと良く分からないですが、↑は強制終了ではなく、アサーションなんじゃな
いですか?

デバッグ実行していれば、アサーションが発生した箇所のソースコードが表示されませ
んか?

ATL のソース内でアサーションが発生しているなら、大抵、その周辺にはヒントになる
コメントが書かれていたりします。

>Expression: GetInterface() != 0

だけに注目してコメントする(=問題の傾向も分からないので、ソースは読んでませ
ん)と、クラスの使い方というか順番が間違っているようにも見えます。

>そもそもtryの使い方がよくわかってなかったり・・・
>throwすると、結果どうなるかというのもわかってなかったり・・・

エラーコードを返す代わりに例外を throw するような設計のクラスもあるので、「例外
を throw する」仕様のクラスを扱うなら、それでは駄目です。

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