もともと DOS や Win32 Console アプリで作成されているものを GUI に変更する.
ダイアログベースにしてプログレスバーで処理進行状況を表示する.
BOOL CxxxApp::InitInstance()
{
....
CCatLogDlg dlg;
m_pMainWnd = &dlg;
// int nResponse = dlg.DoModal(); // これを変更
int nResponse = dlg.Create(IDD_CATLOG_DIALOG);
Main();
dlg.DestroyWindow();
return FALSE;
}
void CxxxApp::Main()
{
CCatLogDlg *dlg;
dlg = (CCatLogDlg *)m_pMainWnd;
CProgressCtrl *prog; // ダイアログに貼り付けたプログレスバー
prog = &dlg -> m_pgrsRun;
while( 1 ) {
// ここでファイル整形処理
....
prog -> SetPos(50); // 進行状況をセット
// メッセージ処理
MSG msg;
while( ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
}
}
こんな感じで可能だが,もっと MFC を活用,スレッドを活用する方法を考えてみる.
もとの DOS ベースの処理をワーカースレッドとして起動すれば,DOS ベースのソースがほとんど使えて,UI とファイル処理とに明確に分離できる.
1. ファイル変換処理ルーチンをクラスに依存しない形で用意する
(ダイアログクラスのstaticメンバ関数としても良い)
2. プログレスバー進捗処理,ファイル変換処理ルーチンの呼び出しはダイアログクラス内で行う.
3. ダイアログクラスの OnInitDialog(WM_INITDIALOG) にて,自分自身に処理開始の PostMessage する.
4. ダイアログクラスの処理開始ルーチンでファイル変換処理ルーチンをスレッドとして呼び出す.
5. ファイル変換処理ルーチンは定期的に呼び出し元のダイアログクラスに進捗具合を PostMessage で通知する.通知を受け取ったダイアログクラスは,その度にプログレスバーを更新する.
6. スレッド側から処理終了の通知を受け取ったダイアログクラスは,任意のタイミングで EndDialog して終了する.
起動
起動 (中断)
+------------------+ →→ +------------+ →→ +----------------+
| アプリケーション | | ダイアログ | | file converter |
+------------------+ ←← +------------+ ←← +----------------+
return 処理進行状況報告
return
また,以下のような構成であれば,よりモジュールの分離が進められる.
起動
プログレスバー更新依頼
終了依頼
+------------------+ →→ +------------+
| | | ダイアログ |
| | ←← +------------+
| | 処理起動依頼
| | (処理中断依頼)
| | return
| アプリケーション |
| | 起動
| | (中断)
| | →→ +----------------+
| | | file converter |
+------------------+ ←← +----------------+
進行状況報告
return
変更するとこんな感じになる.
-- CTESTDlg.h --
...
#define WM_USER_RUN (WM_USER + 100)
----------------
ユーザーメッセージを define します.
-- CTESTDlg.cpp --
...
BEGIN_MESSAGE_MAP(CTESTDlg, CDialog)
//{{AFX_MSG_MAP(CTESTDlg)
...
//}}AFX_MSG_MAP
ON_MESSAGE(WM_USER_RUN, OnMyMessage)
END_MESSAGE_MAP()
BOOL CTESTDlg::OnInitDialog()
{
...
AfxBeginThread(MyThreadProc, m_hWnd);
return TRUE;
}
LRESULT CTESTDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
m_prgsRun.SetPos(wParam);
return 0;
}
UINT MyThreadProc( LPVOID pParam )
{
HWND hWnd = (HWND)pParam;
while( 1 ) {
// ここでファイル処理
::PostMessage(hWnd, WM_USER_RUN, 50, 0);
}
return 0;
}
------------------
参照