【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);
    }
     

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

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

     



    calendar

    S M T W T F S
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    << December 2017 >>

    profile

    others

    mobile

    qrcode