【VC++】簡単なマルチスレッド その2

0

    <機能>

    (1)AfxBeginThreadを使用したマルチスレッドサンプルです

    (2)セマフォ(CSemaphoreクラス)を使って排他制御します

    (3)public変数 count を5スレッドからカウントアップします

     ※1スレッドあたり100カウントアップするためcount=500となります

     (排他制御(CSingleLock::Lock/Unlock)がないとcount<500)

     

    <イメージ>

    排他制御実装前の結果は、100カウントアップするスレッドを5つ起動してcount=500になりません

    CSemaphoreを使用しない結果

    セマフォを使ってcountをいずれか1スレッドからしか使えないように排他制御(CSingleLock::Lock/Unlock)するとcount=500となりました

    CSemaphoreを使用した結果

     

    <動作検証&開発環境>
    Visual Studio Community 2017

    <使い方>
    1.ダイアログベースでThreadSample2プロジェクトを作成
    2.エディットボックスとボタンを配置

     

    ダイアログにGUI配置
    IDC_EDIT1/IDC_EDIT2:ReadOnly=TRUE
    3.コントロール変数を追加
    エディットボックスにコントロース変数設定
    IDC_EDIT1 : m_EdtCount(種類EDIT/カテゴリControl)
    IDC_EDIT2 : m_EdtThread(種類EDIT/カテゴリControl)
    4.ソース追加

    ThreadSample2Dlg.h
    class CThreadSample2Dlg : public CDialogEx
    {
        //~~省略~~
    public:
        afx_msg void OnBnClickedButton1();
        int count;
        int threadno;
        CWinThread *mythread;
        CEdit m_EdtCount;
        CEdit m_EdtThread;
        //セマフォオブジェクト(スレッド間のロックに使用)
        CSemaphore m_cSmp;
    };
    ThreadSample2Dlg.cpp
    //プロトタイプ宣言
    UINT __cdecl CountUpThread(LPVOID p);
    BOOL CThreadSample2Dlg::OnInitDialog()
    {
        CDialogEx::OnInitDialog();
        // このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
        //  Framework は、この設定を自動的に行います。
        SetIcon(m_hIcon, TRUE);            // 大きいアイコンの設定
        SetIcon(m_hIcon, FALSE);        // 小さいアイコンの設定
        //エディットボックスの初期表示
        m_EdtCount.SetWindowTextW(L"0");
        m_EdtThread.SetWindowTextW(L"0");
        return TRUE;
    }
    /*************************************************
    関数名 OnBnClickedButton1
    機能   セマフォで同期 ボタン押下イベント
    *************************************************/

    void CThreadSample2Dlg::OnBnClickedButton1()
    {
        MSG msg;
        count = 0;
        threadno = 0;
        //複数スレッド(5スレッド)起動
        for (int i = 0; i < 5; i++) {
            //スレッド番号(IDC_EDIT2に表示する)
            threadno = (i+1);
            TRACE(L"スレッド %d 起動¥n",threadno);
            AfxBeginThread(CountUpThread, this, 0, 0, NULL);
            while (PeekMessage(&msg, this->GetSafeHwnd(), 0, 0, PM_REMOVE)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            Sleep(300);
        }
    }
    /*************************************************
    関数名 CountUpThread
    機能   ダイアログの変数をカウントアップして表示
    *************************************************/

    UINT __cdecl CountUpThread(LPVOID p) {
       
        CThreadSample2Dlg* pDlg = (CThreadSample2Dlg*)p;
        CString cs;
        MSG msg;
        CSingleLock singlelock(&(pDlg->m_cSmp));
        //スレッド番号を更新
        cs.Format(L"%d", pDlg->threadno);
        pDlg->m_EdtThread.SetWindowTextW(cs);
        //1スレッドで100カウントアップする
        for(int i=0;i<100;i++){
           
            //複数スレッドからcountにアクセスする際に、いずれか1スレッドからしか
            //使用できないように排他制御する
            //CSingleLockについてはDeveloperNetWork参照

            singlelock.Lock();
            pDlg->count++;
            singlelock.Unlock();
            //ダイアログのエディットボックスに表示
            cs.Format(L"%d", pDlg->count);
            pDlg->m_EdtCount.SetWindowTextW(cs);
            while (PeekMessage(&msg, pDlg->GetSafeHwnd(), 0, 0, PM_REMOVE)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            TRACE(L"count = " + cs + L"¥n");
            Sleep(100);
        }
        return 0;
    }
     

    よろしければポチッと押してください

    プログラマー ブログランキングへ

     


    【VC++】簡単なマルチスレッド その1

    0

      <機能>

      (1)AfxBeginThreadを使用したマルチスレッドサンプルです

      (2)マルチスレッドでカウントアップ処理を行います

      (3)バックグラウンドプログラムの中断、再開ができます

       中断:ResumeThread

       再開:SuspendThread

      (4)バックグラウンド処理が終了を通知します

      (5)ダイアログは終了通知を受け取り終了処理をします

       

      <イメージ>

      スレッド開始 ボタン押下によりカウントアップを開始

      スレッド開始イメージ,AfxBeginThread

      中断 ボタン押下により中断します(中断→再開に変更)

      中断ボタンを再開ボタンに変更,AfxBeginThread

      処理が終了したらユーザ定義メッセージで通知します

      終了メッセージ,AfxBeginThread

       

      <動作検証&開発環境>
      Visual Studio Community 2017

       

      <使い方>

      1.ダイアログベースでThreadSampleプロジェクトを作成

      2.エディットボックスとボタンを配置

      IDC_EDIT : ReadOnly=TRUE

      3.コントロール変数を追加

      IDC_EDIT : m_EdtCount(種類EDIT/カテゴリControl)

      IDC_BTNST : m_BtnStart(種類BUTTON)

      IDC_BTNSTOP : m_BtnStop(種類BUTTON)

      IDOK : m_BtnOk(種類BUTTON)

      4.終了通知イベントハンドラ追加

      カスタムWindowsメッセージ : WM_MYMSG

      メッセージハンドラ名 : OnMyMsg

      5.ソースを追加

       

      ThreadSampleDlg.h

       

      class CThreadSampleDlg : public CDialogEx
      {

        //〜〜省略〜〜

      public:
          afx_msg void OnBnClickedOk();
          int count;
          CButton m_BtnStart;
          CButton m_BtnStop;
          CButton m_BtnOk;
          afx_msg void OnBnClickedBtnst();
          afx_msg void OnBnClickedBtnstop();
          CEdit m_EdtCount;
          CWinThread* mythread;
      protected:
          afx_msg LRESULT OnMyMsg(WPARAM wParam, LPARAM lParam);
      };

       

      ThreadSampleDlg.cpp

      //プロトタイプ宣言
      UINT __cdecl CountUpThread(LPVOID p);
      //ユーザ定義メッセージ
      #define WM_MYMSG (WM_USER + 100)
      CThreadSampleDlg::CThreadSampleDlg(CWnd* pParent /*=NULL*/)
          : CDialogEx(IDD_THREADSAMPLE_DIALOG, pParent)
      {
          m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
      }
      void CThreadSampleDlg::DoDataExchange(CDataExchange* pDX)
      {
          CDialogEx::DoDataExchange(pDX);
          DDX_Control(pDX, IDC_BTNST, m_BtnStart);
          DDX_Control(pDX, IDC_BTNSTOP, m_BtnStop);
          DDX_Control(pDX, IDOK, m_BtnOk);
          DDX_Control(pDX, IDC_EDIT, m_EdtCount);
      }
      BEGIN_MESSAGE_MAP(CThreadSampleDlg, CDialogEx)
          ON_WM_SYSCOMMAND()
          ON_WM_PAINT()
          ON_WM_QUERYDRAGICON()
          ON_BN_CLICKED(IDOK, &CThreadSampleDlg::OnBnClickedOk)
          ON_BN_CLICKED(IDC_BTNST, &CThreadSampleDlg::OnBnClickedBtnst)
          ON_BN_CLICKED(IDC_BTNSTOP, &CThreadSampleDlg::OnBnClickedBtnstop)
          ON_MESSAGE(WM_MYMSG, &CThreadSampleDlg::OnMyMsg)
      END_MESSAGE_MAP()

      // CThreadSampleDlg メッセージ ハンドラー
      BOOL CThreadSampleDlg::OnInitDialog()
      {
          CDialogEx::OnInitDialog();
          // "バージョン情報..." メニューをシステム メニューに追加します。
          // IDM_ABOUTBOX は、システム コマンドの範囲内になければなりません。
          ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
          ASSERT(IDM_ABOUTBOX < 0xF000);
          CMenu* pSysMenu = GetSystemMenu(FALSE);
          if (pSysMenu != NULL)
          {
              BOOL bNameValid;
              CString strAboutMenu;
              bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
              ASSERT(bNameValid);
              if (!strAboutMenu.IsEmpty())
              {
                  pSysMenu->AppendMenu(MF_SEPARATOR);
                  pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
              }
              //バツボタン(「×」ボタン)を無効にする
              pSysMenu->EnableMenuItem(SC_CLOSE, MF_GRAYED);
          }
          // このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
          //  Framework は、この設定を自動的に行います。
          SetIcon(m_hIcon, TRUE);            // 大きいアイコンの設定
          SetIcon(m_hIcon, FALSE);        // 小さいアイコンの設定
          //ボタンの初期状態
          m_BtnStart.EnableWindow(TRUE);
          m_BtnStop.EnableWindow(FALSE);
          m_BtnOk.EnableWindow(TRUE);
          m_BtnStop.SetWindowTextW(L"中 断");
          m_EdtCount.SetWindowTextW(L"0");
          return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
      }
      /*************************************************
      関数名 OnBnClickedOk
      機能   閉じる ボタン押下イベント
      *************************************************/

      void CThreadSampleDlg::OnBnClickedOk()
      {
          CDialogEx::OnOK();
      }
      /*************************************************
      関数名 OnBnClickedBtnst
      機能   スレッド開始 ボタン押下イベント
      *************************************************/

      void CThreadSampleDlg::OnBnClickedBtnst()
      {
          DWORD dwExitCode;
          MSG msg;
          //ボタンの状態をセット(中断のみ活性化)
          m_BtnStart.EnableWindow(FALSE);
          m_BtnStop.EnableWindow(TRUE);
          m_BtnOk.EnableWindow(FALSE);
          //カウントを初期化
          count = 0;
          //新しいスレッドを作成する
          //AfxBeginThreadについてはDeveloper Network参照
          mythread = AfxBeginThread(CountUpThread, this,0,0,NULL);
        
      }
      /*************************************************
      関数名 OnBnClickedBtnstop
      機能   中断 ボタン押下イベント
      *************************************************/

      void CThreadSampleDlg::OnBnClickedBtnstop()
      {
          CString cs;
          DWORD dwExitCode;
          //ボタンの状態をセット(中断のみ活性化)
          m_BtnStart.EnableWindow(FALSE);
          m_BtnStop.EnableWindow(TRUE);
          m_BtnOk.EnableWindow(FALSE);
          //ボタンのキャプションを取得
          m_BtnStop.GetWindowTextW(cs);
          if (cs == L"中 断") {
              m_BtnStop.SetWindowTextW(L"再 開");
              //スレッドを再開
              if (GetExitCodeThread(mythread->m_hThread, &dwExitCode)) {
                  if (dwExitCode == STILL_ACTIVE) {
                      mythread->SuspendThread();
                  }
              }
          }
          else {
              m_BtnStop.SetWindowTextW(L"中 断");
              //スレッドを中断
              if (GetExitCodeThread(mythread->m_hThread, &dwExitCode)) {
                  if (dwExitCode == STILL_ACTIVE) {
                      mythread->ResumeThread();
                  }
              }
          }
      }
      /*************************************************
      関数名 CountUpThread
      機能   ダイアログの変数をカウントアップして表示
      *************************************************/

      UINT __cdecl CountUpThread(LPVOID p) {
          CThreadSampleDlg* pDlg = (CThreadSampleDlg*)p;
          CString cs;
          while(1){
              //100までカウントアップ
              pDlg->count++;
              if (pDlg->count > 100) break;
              //ダイアログのエディットボックスに表示
              cs.Format(L"%d",pDlg->count);
              pDlg->m_EdtCount.SetWindowTextW(cs);
              Sleep(100);
          }
         
          ::SendMessage(pDlg->m_hWnd, WM_MYMSG, 0, 0);
          return 0;
      }
      /*************************************************
      関数名 OnMyMsg
      機能   ユーザ定義メッセージのイベントハンドラ
      *************************************************/

      afx_msg LRESULT CThreadSampleDlg::OnMyMsg(WPARAM wParam, LPARAM lParam)
      {
          AfxMessageBox(L"スレッドが終了しました", MB_ICONINFORMATION);
          //処理終了
          m_BtnStart.EnableWindow(TRUE);
          m_BtnStop.EnableWindow(FALSE);
          m_BtnOk.EnableWindow(TRUE);
         
          return 0;
      }

      よろしければポチッと押してください

      プログラマー ブログランキングへ

       


      【VC++】モードレスダイアログをDLLで実装して呼び出す

      0

        <機能>

        ・プログレスバーをDLL(共通部品)として実装します

        (モードレスダイアログとして実装します)

        ・呼び出し側(親ダイアログ)のボタン押下によりDLL(子ダイアログ)を表示します

        ・[中断]ボタン押下によりプログレスバーを中止できます

        (親ダイアログにユーザ定義メッセージをSendMessageします)

         

        <イメージ>

        親ダイアログ(ProgressCall.exe)

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,

        ボタン押下によりプログレスバーを表示します

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,

        [中断]ボタン押下により中断確認メッセージを表示します

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,

         

        <動作検証&開発環境>
        Visual Studio Community 2015

         

        <使い方>

         

        1.DLLの作成

        (1)ProgressSampleプロジェクトを作成します

         MFC DLLを選択してください

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,エクスポート,

        (2)ProgressSampleプロジェクトのプリプロセッサを定義

         C/C++ → プリプロセッサ → プリプロセッサの定義 に

         PROGRESSSAMPLE_EXPORTSを定義してください。 

         (Debug構成/Release構成とも)

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,エクスポート,

        (3)ダイアログをプロジェクトに追加

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,エクスポート,

        (4)プログレスコントロールとボタンを配置

        子ダイアログ(DLL)のリソースID

         ダイアログ:IDD_DIALOG1

         プログレスコントロール:IDC_PROGRESS1

         中断ボタン:IDC_BUTTON1

         

        (5)CDialogを基底クラスとしてクラスを追加

         クラス名をCProgressSampleDlgとしてください。

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,エクスポート,

        (6)メンバ変数を追加

         プログレスコントロールのメンバ変数

         名前:m_Prog

         種類:CProgressCtrl

         カテゴリ:Control(コントロール変数にチェック)

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,エクスポート,

         中断ボタンのメンバ変数

         名前:m_Btn

         種類:CButton

         カテゴリ:Control(コントロール変数にチェック)

         

        (7)CProgressSampleDlgクラスに仮想関数をオーバーライド

         PostNcDestroy

         OnInitDialog

         ※中断ボタン押下イベントハンドラはソースを参照してください

        VC++,MFC,DLL,モードレスダイアログ,プログレスバー,エクスポート,

         

        (8)ProgressSampleAPI.h を追加

        (9)下記を参考にソースを実装

         

        //////ProgressSampleAPI.h

        #pragma once

        #ifdef PROGRESSSAMPLE_EXPORTS
        #define DLL_API __declspec( dllexport )
        #else
        #define DLL_API __declspec( dllimport )
        #endif

         

        //[中断]ボタン押下メッセージ
        #define UM_PROGRESS WM_USER + 100

         

        #ifdef __cplusplus
        extern "C" {
        #endif  /* __cplusplus */

            //エクスポート
            //プログレスバーを初期化

            DLL_API HWND InitProgressBar(HWND myWnd,int iMin, int iMax, wchar_t* cTitle);

            //プログレスバーダイアログを破棄

            DLL_API void CloseProgressBar(HWND childWnd);

            //プログレスバーを進める

            DLL_API void MoveProgressBar(HWND childWnd, int iVal);

        #ifdef __cplusplus
        }
        #endif

         

        //////ProgressSample.h

        // ProgressSample.h : ProgressSample.DLL のメイン ヘッダー ファイル
        //

        #pragma once

        #ifndef __AFXWIN_H__
            #error "PCH に対してこのファイルをインクルードする前に 'stdafx.h' をインクルードしてください"
        #endif

        #include "resource.h"        // メイン シンボル


        // CProgressSampleApp
        // このクラスの実装に関しては ProgressSample.cpp を参照してください。
        //

        class CProgressSampleApp : public CWinApp
        {
        public:
            CProgressSampleApp();


        // オーバーライド
        public:
            virtual BOOL InitInstance();

            DECLARE_MESSAGE_MAP()
        };

         

        //////ProgressSample.cpp

        // ProgressSample.cpp : DLL の初期化ルーチンです。
        //

        #include "stdafx.h"
        #include "ProgressSample.h"
        #include "ProgressSampleAPI.h"
        #include "ProgressSampleDlg.h"

        #ifdef _DEBUG
        #define new DEBUG_NEW
        #endif

        //
        //TODO: この DLL が MFC DLL に対して動的にリンクされる場合、
        //        MFC 内で呼び出されるこの DLL からエクスポートされたどの関数も
        //        関数の最初に追加される AFX_MANAGE_STATE マクロを
        //        持たなければなりません。
        //
        //        例:
        //
        //        extern "C" BOOL PASCAL EXPORT ExportedFunction()
        //        {
        //            AFX_MANAGE_STATE(AfxGetStaticModuleState());
        //            // 通常関数の本体はこの位置にあります
        //        }
        //
        //        このマクロが各関数に含まれていること、MFC 内の
        //        どの呼び出しより優先することは非常に重要です。
        //        これは関数内の最初のステートメントでなければな 
        //        らないことを意味します、コンストラクターが MFC
        //        DLL 内への呼び出しを行う可能性があるので、オブ
        //        ジェクト変数の宣言よりも前でなければなりません。
        //
        //        詳細については MFC テクニカル ノート 33 および
        //        58 を参照してください。
        //

        // CProgressSampleApp

        BEGIN_MESSAGE_MAP(CProgressSampleApp, CWinApp)
        END_MESSAGE_MAP()


        // CProgressSampleApp コンストラクション

        CProgressSampleApp::CProgressSampleApp()
        {

            // TODO: この位置に構築用コードを追加してください。
            // ここに InitInstance 中の重要な初期化処理をすべて記述してください。

        }


        // 唯一の CProgressSampleApp オブジェクトです。

        CProgressSampleApp theApp;


        // CProgressSampleApp 初期化

        BOOL CProgressSampleApp::InitInstance()
        {
            CWinApp::InitInstance();

            return TRUE;
        }


        /*************************************************
        関数名 InitProgressBar
        機能   プログレスバーを初期化
        *************************************************/

        DLL_API HWND InitProgressBar(HWND myWnd,int iMin, int iMax, wchar_t* cTitle)
        {
            AFX_MANAGE_STATE(AfxGetStaticModuleState());
            
            CProgressSampleDlg *mydlg = new CProgressSampleDlg();
            mydlg->m_iMin = iMin;
            mydlg->m_iMax = iMax;
            mydlg->m_csCap = cTitle;
            mydlg->m_oyaHwnd = myWnd;

            //モードレスダイアログを作成
            mydlg->Create(IDD_DIALOG1);
            mydlg->ShowWindow(SW_SHOW);

            return mydlg->m_hWnd;
        }

        /*************************************************
        関数名 CloseProgressBar
        機能   プログレスバーダイアログを破棄
        *************************************************/

        DLL_API void CloseProgressBar(HWND childWnd)
        {
            AFX_MANAGE_STATE(AfxGetStaticModuleState());

            CWnd* wkdlg = CWnd::FromHandle(childWnd);
            ((CProgressSampleDlg*)wkdlg)->DestroyWindow();
        }

        /*************************************************
        関数名 MoveProgressBar
        機能   プログレスバーを進める
        *************************************************/

        DLL_API void MoveProgressBar(HWND childWnd,int iVal)
        {
            AFX_MANAGE_STATE(AfxGetStaticModuleState());
            int iMin, iMax;

            CWnd* wkdlg = CWnd::FromHandle(childWnd);
            ((CProgressSampleDlg*)wkdlg)->m_Prog.SetPos(iVal);

            //プログレスバーが最後まで進んでいたらボタンキャプション変更
            ((CProgressSampleDlg*)wkdlg)->m_Prog.GetRange(iMin, iMax);
            if (iVal == iMax) {
                ((CProgressSampleDlg*)wkdlg)->m_Btn.SetWindowText(_T("閉じる"));
            }
        }
         

        //////ProgressSampleDlg.h

        #pragma once
        #include "afxcmn.h"
        #include "afxwin.h"

        // CProgressSampleDlg ダイアログ

        class CProgressSampleDlg : public CDialog
        {
            DECLARE_DYNAMIC(CProgressSampleDlg)

        public:
            CProgressSampleDlg(CWnd* pParent = NULL);
          // 標準コンストラクター
            virtual ~CProgressSampleDlg();

            int m_iMin;
            int m_iMax;
            CString m_csCap;
            //[中断]ボタン押下時にSeneMessageする
            HWND m_oyaHwnd;

        // ダイアログ データ
        #ifdef AFX_DESIGN_TIME
            enum { IDD = IDD_DIALOG1 };
        #endif

        protected:
            virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV サポート

            DECLARE_MESSAGE_MAP()
        public:
            CProgressCtrl m_Prog;
            CButton m_Btn;
            virtual BOOL OnInitDialog();
            virtual void PostNcDestroy();
            afx_msg void OnBnClickedButton1();
        };
         

        //////ProgressSampleDlg.cpp

        // ProgressSampleDlg.cpp : 実装ファイル
        //

        #include "stdafx.h"
        #include "ProgressSample.h"
        #include "ProgressSampleDlg.h"
        #include "ProgressSampleAPI.h"
        #include "afxdialogex.h"
        #include <Windows.h>

        // CProgressSampleDlg ダイアログ

        IMPLEMENT_DYNAMIC(CProgressSampleDlg, CDialog)

        CProgressSampleDlg::CProgressSampleDlg(CWnd* pParent /*=NULL*/)
            : CDialog(IDD_DIALOG1, pParent)
        {

        }

        CProgressSampleDlg::~CProgressSampleDlg()
        {
        }

        void CProgressSampleDlg::DoDataExchange(CDataExchange* pDX)
        {
            CDialog::DoDataExchange(pDX);
            DDX_Control(pDX, IDC_PROGRESS1, m_Prog);
            DDX_Control(pDX, IDC_BUTTON1, m_Btn);
        }


        BEGIN_MESSAGE_MAP(CProgressSampleDlg, CDialog)
            ON_BN_CLICKED(IDC_BUTTON1, &CProgressSampleDlg::OnBnClickedButton1)
        END_MESSAGE_MAP()


        // CProgressSampleDlg メッセージ ハンドラー

        /*************************************************
        関数名 OnInitDialog
        機能   ダイアログの初期化
        *************************************************/

        BOOL CProgressSampleDlg::OnInitDialog()
        {
            CDialog::OnInitDialog();

            m_Prog.SetRange(m_iMin, m_iMax);
            SetWindowText(m_csCap);

            //閉じる[X]ボタンを無効(グレーアウト)
            CMenu* pSysMenu = GetSystemMenu(FALSE);
            pSysMenu->EnableMenuItem(SC_CLOSE, MF_GRAYED);

            return TRUE;
        }

        /*************************************************
        関数名 PostNcDestroy
        機能   ダイアログの破棄
        *************************************************/

        void CProgressSampleDlg::PostNcDestroy()
        {
            delete this;

            CDialog::PostNcDestroy();
        }

        /*************************************************
        関数名 OnBnClickedButton1
        機能   [中 断]ボタン押下イベントハンドラ
        *************************************************/

        void CProgressSampleDlg::OnBnClickedButton1()
        {
            //ユーザー定義メッセージを送信
            CWnd::FromHandle(m_oyaHwnd)->SendMessage(UM_PROGRESS, (WPARAM)NULL, (LPARAM)NULL);
        }
         

        2.呼び出し側(親ダイアログ)の作成

        (1)同一ソリューション内にProgressCallプロジェクトを作成します

         ダイアログベースで作成してください。

        (2)プロジェクトの依存関係を設定(ビルド順も同時設定できます)

         ProgressCallプロジェクトの依存先であるProgressSampleプロジェクトにチェックON

        プロジェクトの依存関係設定,プロジェクトのプロパティ,

         

        プロジェクトのビルド順序設定,プロジェクトのプロパティ,

        (3)IDOKボタン、IDCANCELボタンをそのまま使います

        親ダイアログのリソースID

         ダイアログ:IDD_PROGRESSCALL_DIALOG

         呼び出しボタン:IDOK

         終了ボタン:IDCANCEL

         

        (4)リンカー設定

         ProgressCallプロパティページにて下記を設定

         リンカー → 全般 → 追加のライブラリディレクトリ に

         Debug構成: ..¥Debug

         Release構成: ..¥Release

         

         リンカー → 全般 → 入力 に

         Debug構成/Release構成とも: ProgressSample.lib

         

        (5)下記を参考にソースを実装

         

        //////ProgressCallDlg.h

        // ProgressCallDlg.h : ヘッダー ファイル
        //

        #pragma once


        // CProgressCallDlg ダイアログ
        class CProgressCallDlg : public CDialogEx
        {

        // コンストラクション
        public:
            CProgressCallDlg(CWnd* pParent = NULL); 
           // 標準コンストラクター

        // ダイアログ データ
        #ifdef AFX_DESIGN_TIME
            enum { IDD = IDD_PROGRESSCALL_DIALOG };
        #endif

            protected:
            virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV サポート


        // 実装
        protected:
            HICON m_hIcon;

            // 生成された、メッセージ割り当て関数
            virtual BOOL OnInitDialog();
            afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
            afx_msg void OnPaint();
            afx_msg HCURSOR OnQueryDragIcon();
            afx_msg LRESULT OnButtonClose(WPARAM wParam, LPARAM lParam);
            DECLARE_MESSAGE_MAP()

        private:
            //プログレスバーダイアログのハンドル
            HWND childHWND;
            BOOL m_bProgress;
            HWND ShowProgress();

        public:
            afx_msg void OnBnClickedOk();
        };

         

        //////ProgressCallDlg.cpp

        // ProgressSampleDlg.cpp : 実装ファイル
        //

        #include "stdafx.h"
        #include "ProgressSample.h"
        #include "ProgressSampleDlg.h"
        #include "ProgressSampleAPI.h"
        #include "afxdialogex.h"
        #include <Windows.h>

        // CProgressSampleDlg ダイアログ

        IMPLEMENT_DYNAMIC(CProgressSampleDlg, CDialog)

        CProgressSampleDlg::CProgressSampleDlg(CWnd* pParent /*=NULL*/)
            : CDialog(IDD_DIALOG1, pParent)
        {

        }

        CProgressSampleDlg::~CProgressSampleDlg()
        {
        }

        void CProgressSampleDlg::DoDataExchange(CDataExchange* pDX)
        {
            CDialog::DoDataExchange(pDX);
            DDX_Control(pDX, IDC_PROGRESS1, m_Prog);
            DDX_Control(pDX, IDC_BUTTON1, m_Btn);
        }


        BEGIN_MESSAGE_MAP(CProgressSampleDlg, CDialog)
            ON_BN_CLICKED(IDC_BUTTON1, &CProgressSampleDlg::OnBnClickedButton1)
        END_MESSAGE_MAP()


        // CProgressSampleDlg メッセージ ハンドラー

        /*************************************************
        関数名 OnInitDialog
        機能   ダイアログの初期化
        *************************************************/

        BOOL CProgressSampleDlg::OnInitDialog()
        {
            CDialog::OnInitDialog();

            m_Prog.SetRange(m_iMin, m_iMax);
            SetWindowText(m_csCap);

            //閉じる[X]ボタンを無効(グレーアウト)
            CMenu* pSysMenu = GetSystemMenu(FALSE);
            pSysMenu->EnableMenuItem(SC_CLOSE, MF_GRAYED);

            return TRUE;
        }

        /*************************************************
        関数名 PostNcDestroy
        機能   ダイアログの破棄
        *************************************************/

        void CProgressSampleDlg::PostNcDestroy()
        {
            delete this;

            CDialog::PostNcDestroy();
        }


        /*************************************************
        関数名 OnBnClickedButton1
        機能   [中 断]ボタン押下イベントハンドラ
        *************************************************/

        void CProgressSampleDlg::OnBnClickedButton1()
        {
            //ユーザー定義メッセージを送信
            CWnd::FromHandle(m_oyaHwnd)->SendMessage(UM_PROGRESS, (WPARAM)NULL, (LPARAM)NULL);
        }
         

        よろしければポチッと押してください

        プログラマー ブログランキングへ

         


        【VC++】SetROP2を使用して十字線カーソルを実装する

        0

          <機能>

          (1)画面上に長い十字線カーソルを表示します

          (2)画面上をダブルクリックするとポイント座標を表示します

           ※サンプルのためOnLButtonDblClkで表示しています

           ※再描画するためにはWM_PAINTで描画する必要があります

           

          <動作検証&開発環境>
          Visual Studio Community 2015

           

          <イメージ>

          画面上に十字線カーソルが表示されます

          VC++,MFC,十字,カーソル,十字線,オリジナル,SetROP2,

          ダブルクリックするとポイント座標を表示します

          VC++,MFC,十字,カーソル,十字線,オリジナル,SetROP2,

           

          <使い方>

          (1)CrossCursorプロジェクトを作成

          VisualStudio,プロジェクト,2015,

          (2)シングルドキュメント(SDK)、MFC標準を選択

          VisualStudio,プロジェクト,2015,

          (3)システムメニュー以外のチェックを外す

           (閉じるボタン「X」のみ表示する)

          VisualStudio,プロジェクト,2015,

          (4)本サンプルでは使用しない機能を外す

          VisualStudio,プロジェクト,2015,

          (5)クラスウィザードにてDrawCrossLineメンバ関数を追加

           名前:DrawCrossLine

           戻り値:void

           パラメータ:CPoint cp

          VisualStudio,プロジェクト,2015,メンバ関数,メソッド,

          (6)メッセージハンドラを追加

           ・WM_LBUTTONDBLCLK(ダブルクリックイベント)

           ・WM_MOUSEMOVE(マウス移動イベント)

           ・WM_SETCURSOR(カーソルセット)

          VisualStudio,プロジェクト,2015,メッセージハンドラ,

          (7)ソースの追加

           

          /* CrossCursorView.h */

           

          private:
              CPoint oldpo; //十字線の古いポイント位置を保持するための変数
           

          /* CrossCursorView.cpp */

           

          /*************************************************
          関数名 DrawCrossLine
          機能   カーソルのポイント位置より十字線(縦線+横線)を表示します
          *************************************************/

          void CCrossCursorView::DrawCrossLine(CPoint po)
          {
              RECT rect;
              HWND hWnd = (HWND)this->GetSafeHwnd();
              HDC hdc = ::GetDC(hWnd);

              //描画できるクライアント領域を取得
              ::GetClientRect(hWnd, &rect);
              //前景の描画モードを設定(色を反転させる)
              //SetROP2については
          MSDNを参照してください
              SetROP2(hdc, R2_NOT);

              //縦線を描画
              MoveToEx(hdc, po.x, 0, NULL);
              LineTo(hdc, po.x, rect.bottom);
              //横線を描画
              MoveToEx(hdc, 0, po.y, NULL);
              LineTo(hdc, rect.right, po.y);

              //デバイスコンテキストを開放
              ::ReleaseDC(hWnd, hdc);
          }

           

          /*************************************************
          関数名 OnLButtonDblClk
          機能   ダブルクリックによりポイント座標を表示します
          ※実際の描画はWM_PAINTで行う必要があります(再描画されないため)
          *************************************************/

          void CCrossCursorView::OnLButtonDblClk(UINT nFlags, CPoint point)
          {
              HWND hWnd = (HWND)this->GetSafeHwnd();
              HDC hdc = ::GetDC(hWnd);
              HPEN pen, oldpen;

              //表示する文字列を生成
              TCHAR tcstr[255];
              ZeroMemory(&tcstr, sizeof(tcstr));
              wsprintf(tcstr, L"(%d,%d)", point.x, point.y);

              //緑のペン
              pen = CreatePen(PS_SOLID, 5, RGB(0, 255, 0));
              oldpen = (HPEN)SelectObject(hdc, pen);

              //十字線を消去
              DrawCrossLine(point);

              //ポイント位置を中心に円を描画
              Ellipse(hdc, point.x - 10, point.y - 10, point.x + 10, point.y + 10);
              //ポイント位置を左上座標として文字列を描画
              SetTextColor(hdc, RGB(255, 0, 0));
              TextOut(hdc, point.x, point.y, tcstr, lstrlen(tcstr));
              DrawCrossLine(point);

              //ペンを戻す
              SelectObject(hdc, oldpen);
              //デバイスコンテキストを開放
              ::ReleaseDC(hWnd, hdc);
              //ペンオブジェクトを開放
              DeleteObject(pen);

          }

           

          /*************************************************
          関数名 OnMouseMove
          機能   マウスの動きに合わせて十字線を表示します
          *************************************************/

          void CCrossCursorView::OnMouseMove(UINT nFlags, CPoint point)
          {
              CClientDC dc(this);

              //古い十字線を消去
              DrawCrossLine(oldpo);
              //現在位置の十字線を描画
              DrawCrossLine(point);
              //現在位置を保持
              oldpo = point;
          }

           

          /*************************************************
          関数名 OnSetCursor
          機能   デフォルトのカーソルを4方向矢印(IDC_SIZEALL)に設定します
          *************************************************/

          BOOL CCrossCursorView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
          {
              //カーソルの種類についてはMSDNを参照してください
              
              //ウェイトカーソル
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_WAIT));
              //ウェイトカーソル&矢印
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_APPSTARTING));
              //クロスカーソル
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
              //4方向矢印
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
              //斜め左下がり矢印
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENESW));
              //斜め右下がり矢印
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE));
              //上下両方向矢印
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
              //左右両方向矢印
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
              //上矢印
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_UPARROW));
              //アイビーム
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_IBEAM));
              //禁止
              //::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_NO));

           

              //4方向十字カーソルを選択

              ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
              return TRUE;

           

          よろしければポチッと押してください

          プログラマー ブログランキングへ

           

           

           


          【VC++】CArrayを使用した構造体可変配列のサンプル

          0

            <機能>

            (1)構造体(ユーザ定義)の可変配列をCArrayを使用して実装する

            (2)ユーザ定義構造体のメンバは以下の2つ

             urban(都市名) char[1024]

             ipopulation(人口) int

            (3)下記メソッドを使用してみる

             Add:要素を追加

             GetAt:指定インデックスから値を返す

             

            <動作検証&開発環境>
            Visual Studio Community 2015

             

            <イメージ>

            東京都の都市別人口(出典:総務省統計局)をコマンドプロンプトに出力します

            ユーザ定義構造体,可変配列,CArray,MFC,VC++,

             

            <使い方>
            (1)Win32コンソールアプリケーションでプロジェクトを作成

            (2)[次へ]を押下し、アプリケーション設定画面の共通ヘッダーファイルを追加にて「MFC」にチェック

            ユーザ定義構造体,可変配列,CArray,MFC,VC++,

            (3)ソースの追加

             

            //構造体定義
            typedef struct SCT_POPULATION {
                char urban[1024];
                int ipopulation;
            }sctPopulation;

             

            //プロトタイプ宣言
            void setPopulation(CArray<sctPopulation> *sctpop);


            // 唯一のアプリケーション オブジェクトです。

            CWinApp theApp;

            using namespace std;

            int main()
            {
                int nRetCode = 0;

                HMODULE hModule = ::GetModuleHandle(nullptr);

                if (hModule != nullptr)
                {
                    // MFC を初期化して、エラーの場合は結果を印刷します。
                    if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
                    {
                        // TODO: 必要に応じてエラー コードを変更してください。
                        wprintf(L"致命的なエラー: MFC の初期化ができませんでした。¥n");
                        nRetCode = 1;
                    }
                    else
                    {

                        //構造体可変配列を宣言
                        CArray <sctPopulation> sctpop;

                        //東京都の都市別人口を構造体可変配列にセット
                        setPopulation(&sctpop);

                        //構造体可変配列の内容をコンソールに出力
                        for (int i = 0; i < sctpop.GetSize(); i++)
                        {
                            printf(" %-20s %9d人¥n", sctpop.GetAt(i).urban, sctpop.GetAt(i).ipopulation);
                        }

                        //コマンドプロンプト画面が閉じないようにする
                        system("pause");
                    }
                }
                else
                {
                    // TODO: 必要に応じてエラー コードを変更してください。
                    wprintf(L"致命的なエラー: GetModuleHandle が失敗しました¥n");
                    nRetCode = 1;
                }

                return nRetCode;
            }

             

            /*************************************************
            関数名 setPopulation
            機能   可変構造体配列に東京都都市別人口データを設定
            出典   総務省統計局「都市別人口」
            *************************************************/

            void setPopulation(CArray<sctPopulation> *sctpop)
            {
                CString cbuf,cdat;
                
                sctPopulation wkpop;
                sctpop->RemoveAll();

                char *urbanPopulation[] = {
                    "千代田区,56873",
                    "中央区,138088",
                    "港区,240585",
                    "新宿区,327712",
                    "文京区,207413",
                    "台東区,189795",
                    "墨田区,258423",
                    "江東区,493952",
                    "品川区,372077",
                    "目黒区,269689",
                    "大田区,707455",
                    "世田谷区,874332",
                    "渋谷区,217008",
                    "中野区,316625",
                    "杉並区,547165",
                    "豊島区,275507",
                    "北区,338084",
                    "荒川区,209087",
                    "板橋区,544172",
                    "練馬区,714656",
                    "足立区,674111",
                    "葛飾区,449527",
                    "江戸川区,680262",
                    "八王子,562572",
                    "立川,179090",
                    "武蔵野,142138",
                    "三鷹,182092",
                    "青梅,137052",
                    "府中,254551",
                    "昭島,112727",
                    "調布,224191",
                    "町田,426648",
                    "小金井,117427",
                    "小平,186958",
                    "日野,180975",
                    "東村山,151412",
                    "国分寺,119379",
                    "国立,74558",
                    "福生,58553",
                    "狛江,79096",
                    "東大和,86162",
                    "清瀬,74374",
                    "東久留米,116494",
                    "武蔵村山,72092",
                    "多摩,147486",
                    "稲城,86594",
                    "羽村,56604",
                    "あきる野,81697",
                    "西東京,198267",
                    "0"
                };

                for (int i = 0;; i++)
                {
                    //ループ終了条件("0"が出現したらデータセット終了)
                    if (strcmp(urbanPopulation[i], "0") == 0) break;

                    //対象インデックスの文字列を取得
                    cbuf = urbanPopulation[i];

             

                    //cbufの1カラム目(都市名)をセット
                    AfxExtractSubString(cdat, cbuf, 0, ',');
                    //CStringをLPCSTRへマクロを使って変換する
                    strcpy_s(wkpop.urban, CT2CA(cdat));

             

                    //cbufの2カラム目(人口)をセット
                    AfxExtractSubString(cdat, cbuf, 1, ',');
                    wkpop.ipopulation = atoi(CStringA(cdat));

             

                    //構造体可変配列にセット
                    sctpop->Add(wkpop);
                }
                return;
            }

             

            よろしければポチッと押してください


            プログラマー ブログランキングへ

             



            << | 2/5PAGES | >>

            calendar

            S M T W T F S
            1234567
            891011121314
            15161718192021
            22232425262728
            2930     
            << April 2018 >>

            profile

            others

            mobile

            qrcode         スマホ表示に戻す