C言語やC++で何か処理を書ける人は多いですが、Windowプログラムとなると実装方法が難しいです。VisualStudioのプロジェクトの雛形にボタンを配置し、そこから手持ちのコードを起動すれば動きそうです。
しかし、その方法では「未応答」状態になったり、ウィンドウの操作すらできなくなります。もちろん処理が終われば正常に動きはしますが、見た目は悪いです。
進捗バーを表示しようと配置しても、当然それを動かすためのコードも必要です。
メッセージループを処理しながら、自前のコードを動かしたり、「状態機械」にコードを移植した後でメッセージループに組み込むなど方法はありますが、非常に可読性が悪くなります。
今回は、スレッドを一本発行することで手持ちのコードを動作させます。完全に無改造では動かないですが、手持ちの関数に2つの処理を埋め込むだけで対応できます。
1つ目は進捗バーに状態を知らせるためのグローバル変数を更新することです。処理に応じて増分させた数値を定期的に書き込んでください。
2つ目は強制終了フラグを監視し、検出したら処理ループを安全に停止させる処理を行うことです。外部からスレッドを停止させる方法は、処理中のファイルやリソースのクローズがされないので問題があります。 強制終了フラグを検知したら、区切りの良い場所まで処理して、その後クロージング処理などが出来ます。
このように簡単に手持ちのC,C++コードを今風に作り上げることが出来ます。個人的に、仕事で変換プログラムなどを持っている人はリニューアルしてみてください。
- /*******************************************************
- G++ .\progress2.cpp -mwindows -lvfw32 -municode -o progress2 でコンパイルしてください。
- 手持ちのC言語やC++で作成した時間がかかる変換プログラムも簡単にウィンドウアプリに出来ます。
- Tiktok @pistalove 好きなことをやらない人生は最高 も御覧ください。
- ********************************************************/
- #include <windows.h>
- #include <commctrl.h>
- HWND hWnd; //メインウィンドウハンドル
- HWND hProgress; //進捗表示用ハンドル
- HWND hButton; //ボタン表示用ハンドル
- HWND hText; //文字表示用ハンドル
- int iProgress = 0; //進捗状態
- int bAbort = false; //強制終了フラグ
- /******************************************
- ここに時間がかかる手持ちのコードを書きます。仕様は
- ・bAbortがtrueになったら親ウィンドウの停止ボタンが押されています。安全に処理を終了してください。
- ・iProgressに進捗状況をパーセントで書き込んでください。進捗バーが動きます。
- ・処理が完全に終了したら SendMessageで親ウィンドウを閉じてください。
- ・手持ちのGUIに対応していないプログラムをコピペすれば進捗バーと停止ボタンが付いて見た目が良いです。
- ********************************************/
- DWORD WINAPI MyThreadFunction( LPVOID lpParam ){
- for (int i = 0; i <= 100; ++i) {
- if(bAbort) break; //強制終了指示が出たら終了する
- iProgress = i;
- Sleep(500); //試験的に待っています。
- }
- SendMessage(hWnd, WM_DESTROY, 0, 0);
- return 0;
- }
- //以下のコードは基本的にそのままで動きます。表示される文字やウィンドウの体裁だけ整えてください。
- //ウィンドウプロシージャ
- LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
- switch (message) {
- case WM_CREATE:
- // プログレスバーの作成
- hProgress = CreateWindowEx(0, PROGRESS_CLASS, NULL,WS_CHILD | WS_VISIBLE | PBS_SMOOTH,10,40,280,10,hWnd,NULL,NULL,NULL);
- SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
- SendMessage(hProgress, PBM_SETSTEP, 1, 0);
- hText = CreateWindowEx(0,L"STATIC",
- L"Tiktok @pistalove", // 表示するテキスト
- WS_VISIBLE | WS_CHILD | SS_CENTER,10, 10,280, 20,hWnd,NULL,NULL,NULL);
- hButton = CreateWindow(L"BUTTON",L"停止",WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,230,55,60,30,hWnd,(HMENU)1,NULL,NULL);
- SetTimer(hWnd, 1, 100, NULL);//進捗画面更新用タイマー設定100ミリ秒に一回
- CreateThread(NULL, 0, MyThreadFunction, NULL, 0, NULL); //手持ちのコードの関数が実行されます。
- return 0;
- case WM_COMMAND:
- if (LOWORD(wParam) == 1) { //ボタンクリック
- bAbort = true; //停止フラグを設定
- }
- return 0;
- case WM_TIMER:
- SendMessage(hProgress, PBM_SETPOS, iProgress, 0);
- return 0;
- case WM_CLOSE:
- return 0;
- case WM_DESTROY:
- KillTimer(hWnd, 1);
- PostQuitMessage(0);
- return 0;
- default:
- return DefWindowProc(hWnd, message, wParam, lParam);
- }
- }
- int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpCmdLine, int nCmdShow){
- WNDCLASS wc = {};
- wc.lpfnWndProc = WindowProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = L"ProgressDemo";
- RegisterClass(&wc);
- hWnd = CreateWindowEx(0, L"ProgressDemo", L"Tiktok @Pistalove", WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME|WS_MAXIMIZEBOX) | WS_VISIBLE,CW_USEDEFAULT, CW_USEDEFAULT, 320, 200, NULL,NULL,hInstance, NULL);
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }