////////////////////////////////////////
// ECCSkelton
// ダイアログ基本クラスCDLG定義ファイル
// Copyright (c) August, 2022
//        By Ysama
////////////////////////////////////////

class CDLG
{
protected:
	HANDLE	m_hMutex = 0;
	WCHAR	m_UniqName[MAX_PATH] = {L"\0"};
	bool	m_Mode = TRUE;						//TRUE - Modal dialog, FALSE - Modeless dialog
public:		//メンバー変数
	HWND		m_hWnd = 0;						//ウィンドウハンドル
	HWND		m_hParent = 0;					//親ウィンドウハンドル
	HINSTANCE	m_hInstance = 0;				//インスタンス変数
	MSG			m_Msg;							//ウィンドウメッセージ
	HACCEL		m_Accel = 0;					//Acceleratorの有無

public:	//メンバー関数
	CDLG();										//デフォールトコンストラクター
	CDLG(WCHAR*);								//UniqueName付コンストラクター
	~CDLG();									//デストラクター
	HWND GetHandle() {return m_hWnd;}			//ダイアログハンドルを返す
	void SetHandle(HWND h) {m_hWnd = h;}		//ダイアログのハンドルを設定
	HINSTANCE GetInstance()
					{return m_hInstance;}		//ダイアログのインスタンスを返す
	void SetInstance(HINSTANCE hInst)
					{m_hInstance = hInst;}		//ダイアログのインスタンスを設定
	int DoModal(HWND, LPCWSTR, HINSTANCE);		//モーダルダイアログを開く
	bool EndModal(int);							//モーダルダイアログを閉める
	bool Create(HWND, HINSTANCE, LPCWSTR);		//モードレスダイアログを開く
	bool Destroy();								//モードレスダイアログを閉める
	static BOOL CALLBACK DummyProc(HWND, UINT, WPARAM, LPARAM);	//ダミーのコールバック関数
	virtual BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);	//本来のコールバック関数
	virtual	bool OnInit(WPARAM, LPARAM);			//WM_INITDIALOG
	virtual bool OnActivate(WPARAM, LPARAM);		//WM_ACTIVATE
	virtual bool OnEnable(WPARAM, LPARAM);			//WM_ENABLE
	virtual bool OnTimer(WPARAM, LPARAM);			//WM_TIMER
	virtual bool OnSetFocus(WPARAM, LPARAM);		//WM_SETFOCUS
	virtual	bool OnNotify(WPARAM, LPARAM);			//WM_NOTIFY
	virtual	bool OnCommand(WPARAM, LPARAM);			//WM_COMMAND
	virtual bool OnKeyDown(WPARAM, LPARAM);			//WM_KEYDOWN
	virtual bool OnKeyUp(WPARAM, LPARAM);			//WM_KEYUP
	virtual bool OnChar(WPARAM, LPARAM);			//WM_CHAR
	virtual bool OnLButtonDblclk(WPARAM, LPARAM);	//WM_LBUTTONDBLCLK
	virtual bool OnLButtonDown(WPARAM, LPARAM);		//WM_LBUTTONDOWN
	virtual bool OnLButtonUp(WPARAM, LPARAM);		//WM_LBUTTONUP
	virtual bool OnMButtonDblclk(WPARAM, LPARAM);	//WM_MBUTTONDBLCLK
	virtual bool OnMButtonDown(WPARAM, LPARAM);		//WM_MBUTTONDOWN
	virtual bool OnMButtonUp(WPARAM, LPARAM);		//WM_MBUTTONUP
	virtual bool OnMouseMove(WPARAM, LPARAM);		//WM_MOUSEMOVE
	virtual bool OnRButtonDblclk(WPARAM, LPARAM);	//WM_RBUTTONDBLCLK
	virtual bool OnRButtonDown(WPARAM, LPARAM);		//WM_RBUTTONDOWN
	virtual bool OnRButtonUp(WPARAM, LPARAM);		//WM_RBUTTONUP
	virtual bool OnPaint(WPARAM, LPARAM);			//WM_PAINT
	virtual bool OnEraseBkgnd(WPARAM, LPARAM);		//WM_ERASEBKGND
	virtual bool OnMove(WPARAM, LPARAM);			//WM_MOVE
	virtual bool OnSize(WPARAM, LPARAM);			//WM_SIZE
	virtual bool OnHScroll(WPARAM, LPARAM);			//WM_HSCROLL
	virtual bool OnVScroll(WPARAM, LPARAM);			//WM_VSCROLL
	virtual bool OnDropFiles(WPARAM, LPARAM);		//WM_DROPFILES
	virtual bool OnGetMaxInfo(WPARAM, LPARAM);		//WM_GETMAXINFO
	virtual	bool OnClose(WPARAM, LPARAM);			//WM_CLOSE
	virtual	bool OnDestroy(WPARAM, LPARAM);			//WM_DESTROY
	bool InclAccel(LPWSTR);						//Modeless Dialog用アクセラレーターロード関数
	UINT Loop();								//Modeless Dialog用メッセージループ
	bool IsOnlyOne();							//２重起動防止関数
	LRESULT SendMsg(UINT, WPARAM, LPARAM);		//ウィンドウへのメッセージ
	LRESULT SendItemMsg(int, UINT,
						WPARAM, LPARAM);		//ウィンドウコントロールへのメッセージ
};

//デフォールトコンストラクター
CDLG::CDLG() {
}

//UniqueName付コンストラクター
CDLG::CDLG(WCHAR* UName) {

	wsprintfW(m_UniqName, L"%d", UName);
}

//デストラクター
CDLG::~CDLG() {

	if(m_hMutex)
		CloseHandle(m_hMutex);
}

//モーダルダイアログを開く
int CDLG::DoModal(HWND hParent, LPCWSTR DlgName, HINSTANCE hInstance) {

	if(m_hWnd)		//使用中の場合、そのまま戻る
		return FALSE;
	//親ウィンドウのハンドルを記録
	m_hParent = hParent;
	//親ウィンドウのインスタンスを取得して記録
	m_hInstance = hInstance;
	//ダイアログを開く
	int ret = DialogBoxParamW(m_hInstance, DlgName, hParent, DummyProc, (LPARAM)this);
	if(ret == -1)
		return FALSE;
	m_Mode = TRUE;	//Modal dialog として開く
	return ret;
}

//モーダルダイアログを閉める
bool CDLG::EndModal(int i) {

	EndDialog(m_hWnd, i);
	m_hWnd = 0;		//未使用状態にする
	return TRUE;
}

//モードレスダイアログを開く
bool CDLG::Create(HWND hParent, HINSTANCE hInstance, LPCWSTR DlgName) {

	if(m_hWnd)		//使用中の場合、そのまま戻る
		return FALSE;
	//親ウィンドウのハンドルを記録
	m_hParent = hParent;
	//インスタンスを取得して記録
	m_hInstance = hInstance;
	//ダイアログを開く
	m_hWnd = CreateDialogParamW(m_hInstance, DlgName, m_hParent, DummyProc, (LPARAM)this);
	if(!m_hWnd) {	//ダイアログ作成失敗
		MessageBoxW(0, L"ダイアログを作れませんでした。", L"エラー",
				MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}
	//ダイアログの表示と再描画
	ShowWindow(m_hWnd, SW_SHOWNORMAL);
	UpdateWindow(m_hWnd);
	m_Mode = FALSE;	//Modeless dialog として開く
	return TRUE;
}

//モードレスダイアログを閉める
bool CDLG::Destroy() {

	DestroyWindow(m_hWnd);
	m_hWnd = 0;		//未使用状態にする
	m_Mode = TRUE;	//Modal dialog
	return TRUE;
}

//ダミーコールバック関数
BOOL CALLBACK CDLG::DummyProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) {

	if(Message == WM_INITDIALOG) {
		//ウィンドウハンドルを取得し、
		((CDLG*)lParam)->m_hWnd = hWnd;
		//ウィンドウプロパティにCDLGクラスインスタンスへのポインターを書込む（重要）
		SetPropW(hWnd, L"CPP_CLASS", (HANDLE)lParam);
	}
	//Initメンバー関数が書き込んだこのクラスのインスタンスへのポインターを読む
	CDLG* pWnd = (CDLG*)GetPropW(hWnd, L"CPP_CLASS");
	//もしそれが読み込めたら
	if(pWnd) {
		//本来のコールバック関数（WndProc）を呼ぶ
		BOOL lResult = pWnd->DlgProc(hWnd, Message, wParam, lParam);
		//ウィンドウ破壊時にウィンドウプロパティを廃棄する
		if(Message == WM_DESTROY)
			RemovePropW(hWnd, L"CPP_CLASS");
		return lResult;
	}
	else
		//ウィンドウズの処理に任せる
		FALSE;
}

//本来のコールバック関数（仮想関数）
BOOL CALLBACK CDLG::DlgProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) {

	bool Done = FALSE;
	switch(Message) {
		case WM_INITDIALOG:
			//最初にDummyProcから呼ばれる時にm_hWndを記録する
			m_hWnd = hWnd;
			Done = OnInit(wParam, lParam);
			break;
		case WM_NOTIFY:
			Done = OnNotify(wParam, lParam);
			break;
		case WM_COMMAND:
			Done = OnCommand(wParam, lParam);
			break;
		case WM_ACTIVATE:
			Done = OnActivate(wParam, lParam);
			break;
		case WM_ENABLE:
			Done = OnEnable(wParam, lParam);
			break;
		case WM_TIMER:
			Done = OnTimer(wParam, lParam);
			break;
		case WM_SETFOCUS:
			Done = OnSetFocus(wParam, lParam);
			break;
		case WM_KEYDOWN:
			Done = OnKeyDown(wParam, lParam);
			break;
		case WM_KEYUP:
			Done = OnKeyUp(wParam, lParam);
			break;
		case WM_CHAR:
			Done = OnChar(wParam, lParam);
			break;
		case WM_LBUTTONDBLCLK:
			Done = OnLButtonDblclk(wParam, lParam);
			break;
		case WM_LBUTTONDOWN:
			Done = OnLButtonDown(wParam, lParam);
			break;
		case WM_LBUTTONUP:
			Done = OnLButtonUp(wParam, lParam);
			break;
		case WM_MBUTTONDBLCLK:
			Done = OnMButtonDblclk(wParam, lParam);
			break;
		case WM_MBUTTONDOWN:
			Done = OnMButtonDown(wParam, lParam);
			break;
		case WM_MBUTTONUP:
			Done = OnMButtonUp(wParam, lParam);
			break;
		case WM_MOUSEMOVE:
			Done = OnMouseMove(wParam, lParam);
			break;
		case WM_RBUTTONDBLCLK:
			Done = OnRButtonDblclk(wParam, lParam);
			break;
		case WM_RBUTTONDOWN:
			Done = OnRButtonDown(wParam, lParam);
			break;
		case WM_RBUTTONUP:
			Done = OnRButtonUp(wParam, lParam);
			break;
		case WM_PAINT:
			Done = OnPaint(wParam, lParam);
			break;
		case WM_ERASEBKGND:
			Done = OnEraseBkgnd(wParam, lParam);
			break;
		case WM_MOVE:
			Done = OnMove(wParam, lParam);
			break;
		case WM_SIZE:
			Done = OnSize(wParam, lParam);
			break;
		case WM_HSCROLL:
			Done = OnHScroll(wParam, lParam);
			break;
		case WM_VSCROLL:
			Done = OnVScroll(wParam, lParam);
			break;
		case WM_DROPFILES:
			Done = OnDropFiles(wParam, lParam);
			break;
		case WM_GETMINMAXINFO:
			Done = OnGetMaxInfo(wParam, lParam);
			break;
		case WM_CLOSE:
			Done = OnClose(wParam, lParam);
			if(Done) {		//終了ならば
				if(m_Mode)	//Modal ダイアログ
					EndModal(Done);
				else		//Modeless ダイアログ
					Destroy();
			}
			break;
		case WM_DESTROY:
			Done = OnDestroy(wParam, lParam);
			break;
	}
	return Done;
}

//WM_INITDIALOG時処理（仮想関数）
bool CDLG::OnInit(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_ACTIVATE時処理（仮想関数）
bool CDLG::OnActivate(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_ENABLE時処理（仮想関数）
bool CDLG::OnEnable(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_TIMER時処理（仮想関数）
bool CDLG::OnTimer(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_SETFOCUS時処理（仮想関数）
bool CDLG::OnSetFocus(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_NOTIFY時処理（仮想関数）
bool CDLG::OnNotify(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_COMMAND時処理（仮想関数）
bool CDLG::OnCommand(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_KEYDOWN時処理（仮想関数）
bool CDLG::OnKeyDown(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_KEYUP時処理（仮想関数）
bool CDLG::OnKeyUp(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_CHAR時処理（仮想関数）
bool CDLG::OnChar(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_LBUTTONDBLCLK時処理（仮想関数）
bool CDLG::OnLButtonDblclk(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_LBUTTONDOWN時処理（仮想関数）
bool CDLG::OnLButtonDown(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_LButtonUp時処理（仮想関数）
bool CDLG::OnLButtonUp(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_MBUTTONDBLCLK時処理（仮想関数）
bool CDLG::OnMButtonDblclk(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_MBUTTONDOWN時処理（仮想関数）
bool CDLG::OnMButtonDown(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_MButtonUp時処理（仮想関数）
bool CDLG::OnMButtonUp(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_MOUSEMOVE時処理（仮想関数）
bool CDLG::OnMouseMove(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_RBUTTONDBLCLK時処理（仮想関数）
bool CDLG::OnRButtonDblclk(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_RBUTTONDOWN時処理（仮想関数）
bool CDLG::OnRButtonDown(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_RButtonUp時処理（仮想関数）
bool CDLG::OnRButtonUp(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_PAINT時処理（仮想関数）
bool CDLG::OnPaint(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_ERASEBKGND時処理（仮想関数）
bool CDLG::OnEraseBkgnd(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_MOVE時処理（仮想関数）
bool CDLG::OnMove(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_SIZE時処理（仮想関数）
bool CDLG::OnSize(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_HSCROLL時処理（仮想関数）
bool CDLG::OnHScroll(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_VSCROLL時処理（仮想関数）
bool CDLG::OnVScroll(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_DROPFILES時処理（仮想関数）
bool CDLG::OnDropFiles(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_GETMINMAXINFO時処理（仮想関数）
bool CDLG::OnGetMaxInfo(WPARAM wParam, LPARAM lParam) {
	return FALSE;
}

//WM_CLOSE時処理(仮想関数）
bool CDLG::OnClose(WPARAM wParam, LPARAM lParam) {

	return FALSE;
}

//WM_DESTROY時処理(仮想関数）
bool CDLG::OnDestroy(WPARAM wParam, LPARAM lParam) {

	return FALSE;
}

//アクセラレーター
bool CDLG::InclAccel(LPWSTR Name) {

	if(!(m_Accel = LoadAcceleratorsW(m_hInstance, Name))) {
		MessageBoxW(NULL, L"アクセラレーターの読込に失敗しました",
					L"エラー", MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}
	return TRUE;
}

//メッセージループ
UINT CDLG::Loop() {

	while(GetMessageW(&m_Msg, NULL, 0, 0)) {
		//アクセラレーター処理
		if(!TranslateAcceleratorW(m_hWnd, m_Accel, &m_Msg) &&
		//本モードレスダイアログ処理
		!IsDialogMessageW(m_hWnd, &m_Msg)) {
			TranslateMessage(&m_Msg);
			DispatchMessageW(&m_Msg);
		}
	}
	return m_Msg.wParam;
}

bool CDLG::IsOnlyOne() {

	m_hMutex = CreateMutexW(NULL, TRUE, m_UniqName);
	if (!m_hMutex)
		return FALSE;
	// もしGetLastError()が、ERROR_ALREADY_EXISTSなら、
	// すでにアプリケーションが起動している
	if (GetLastError() == ERROR_ALREADY_EXISTS) {
    //二重起動時の処理
    	return FALSE;
	}
	return TRUE;
}

//コントロールへのへのメッセージ
LRESULT CDLG::SendMsg(UINT Msg, WPARAM wParam, LPARAM lParam) {

	return SendMessageW(m_hWnd, Msg, wParam, lParam);
}

//ウィンドウコントロールへのへのメッセージ
LRESULT CDLG::SendItemMsg(int ID, UINT Msg, WPARAM wParam, LPARAM lParam) {

	return SendDlgItemMessageW(m_hWnd, ID, Msg, wParam, lParam);
}
