【VC++】モードレスダイアログをDLLで実装して呼び出す
<機能>
・プログレスバーをDLL(共通部品)として実装します
(モードレスダイアログとして実装します)
・呼び出し側(親ダイアログ)のボタン押下によりDLL(子ダイアログ)を表示します
・[中断]ボタン押下によりプログレスバーを中止できます
(親ダイアログにユーザ定義メッセージをSendMessageします)
<イメージ>
親ダイアログ(ProgressCall.exe)
ボタン押下によりプログレスバーを表示します
[中断]ボタン押下により中断確認メッセージを表示します
<動作検証&開発環境>
Visual Studio Community 2015
<使い方>
1.DLLの作成
(1)ProgressSampleプロジェクトを作成します
MFC DLLを選択してください
(2)ProgressSampleプロジェクトのプリプロセッサを定義
C/C++ → プリプロセッサ → プリプロセッサの定義 に
PROGRESSSAMPLE_EXPORTSを定義してください。
(Debug構成/Release構成とも)
(3)ダイアログをプロジェクトに追加
(4)プログレスコントロールとボタンを配置
ダイアログ:IDD_DIALOG1
プログレスコントロール:IDC_PROGRESS1
中断ボタン:IDC_BUTTON1
(5)CDialogを基底クラスとしてクラスを追加
クラス名をCProgressSampleDlgとしてください。
(6)メンバ変数を追加
プログレスコントロールのメンバ変数
名前:m_Prog
種類:CProgressCtrl
カテゴリ:Control(コントロール変数にチェック)
中断ボタンのメンバ変数
名前:m_Btn
種類:CButton
カテゴリ:Control(コントロール変数にチェック)
(7)CProgressSampleDlgクラスに仮想関数をオーバーライド
PostNcDestroy
OnInitDialog
※中断ボタン押下イベントハンドラはソースを参照してください
(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ボタンをそのまま使います
ダイアログ: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);
}
よろしければポチッと押してください