この時生成されるプロジェクトは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);
}
