この時生成されるプロジェクトはATLで記述したCOMをサービスするものですが, これを改造して通常のコンソールアプリとするための修正内容をメモします。
ウィザードで生成されるメインコードは, 次のようなCAtlExeModuleTテンプレート派生クラスと メイン関数のみでできています。
class CMyAppModule : public CAtlExeModuleT< CMyAppModule > { public : DECLARE_LIBID(LIBID_MyAppLib) DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYAPP, "{E115D6B3-7016-4740-AF95-D2B76569B56F}") } CMyAppModule _AtlModule; extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int nShowCmd) { return _AtlModule.WinMain(nShowCmd); }
この _tWinMain で行っている処理を別スレッドにして,メインスレッドで 必要な処理をするように変更できれば,目的が達成できそうです。
方法はいろいろありますが,次のような形式で実装してみました。
1. _AtlModule::WinMain から CMyAppModule::Run メソッドがコールされるので これをオーバーロードします。
HRESULT CMyAppModule::Run(int nShowCmd) throw() { this->showcmd_ = nShowCmd; unsigned int threadID; HANDLE hThread; startThread(hThread, threadID); doMyOperation(); stopThread(hThread, threadID); return S_OK; }
startThread / stopThread はスレッドの起動/停止メソッドで, ここで起動するスレッドで元々の Run メソッドを実行してやります。
void CMyAppModule::startThread(HANDLE& hThread, unsigned int& threadID) { hThread = (HANDLE)::_beginthreadex(NULL, 0, threadFunc, (LPVOID)this, 0, &threadID); } void CMyAppModule::stopThread(HANDLE hThread, DWORD threadID) { do { ::PostThreadMessage(threadID, WM_QUIT, NULL, NULL); } while(::WaitForSingleObject(hThread, 500) == WAIT_TIMEOUT); }
stopThread では, スレッドに WM_QUIT を投げた後,停止の待ち合わせをしています。
スレッド関数 threadFunc はこんな感じ:
static unsigned int __stdcall threadFunc(LPVOID param) { ::CoInitialize(NULL); CMyAppModule* this_ = (CMyAppModule*)param; return this_->CAtlExeModuleT::Run(this_->showcmd_); }
インスタンス変数 showcmd_ は Run メソッドに渡された引数をスレッド関数に 引き渡すためのものです。
doMyOperation( ) は実際に行いたい処理を実装する場所です。
コード全体としては,おおよそ以下のような形式です。 エラー処理などは必要に応じて実装してください(^^;)。
class CMyAppModule : public CAtlExeModuleT< CMyAppModule > { public : DECLARE_LIBID(LIBID_MyAppLib) DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYAPP, "{E115D6B3-7016-4740-AF95-D2B76569B56F}") HRESULT CMyAppModule::Run(int nShowCmd) throw() { showcmd_ = nShowCmd; unsigned int threadID; HANDLE hThread; startThread(hThread, threadID); doMyOperation( ); stopThread(hThread, threadID); return S_OK; } private: int showcmd_; void startThread(HANDLE& hThread, unsigned int& threadID) { hThread = (HANDLE)::_beginthreadex(NULL, 0, threadFunc, (LPVOID)this, 0, &threadID); } void stopThread(HANDLE hThread, DWORD threadID) { do { ::PostThreadMessage(threadID, WM_QUIT, NULL, NULL); } while(::WaitForSingleObject(hThread, 500) == WAIT_TIMEOUT); } static unsigned int __stdcall threadFunc(LPVOID param) { ::CoInitialize(NULL); CMyAppModule* this_ = (CMyAppModule*)param; return this_->CAtlExeModuleT::Run(this_->showcmd_); } void doMyOperation( ) { // ここに必要な処理を実装します。 // このメソッドが終了すると,アプリケーションも停止します。 } }; CMyAppModule _AtlModule; extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int nShowCmd) { return _AtlModule.WinMain(nShowCmd); }