開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 プロジェクト
プロジェクト名 EzTimer
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト

EzTimer.cpp
#pragma comment(lib, "winmm")
 
#include <stdio.h>
#include <time.h>
#include <Windows.h>
#include <WindowsX.h>
#include "resource.h"
 
#define SECT L"General"
#define MAKESMSG(st,ch,d1,d2) (st)<<4|(ch)|(d1)<<8|(d2)<<16
#define CH 0
#define NOTE_NO 69
 
// 関数プロトタイプ宣言
void GetIniFileName();
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnInitDialog(HWND hDlg);
void OnDestroy(HWND hDlg);
void OnTimer(HWND hDlg);
void OnDrawItem(WPARAM wParam, LPARAM lParam);
void OnOK(HWND hDlg);
BOOL GetDlgData(HWND hDlg);
 
// 外部変数
TCHAR szIniFile[MAX_PATH];
HFONT hFont;
HWND hClock;
HWND hMessage;
TCHAR szMessage[16];
INT_PTR uIDEvent;
HMIDIOUT hmo;
BOOL alarm = FALSE;
BOOL note = FALSE;
int mode;
int alarmH;
int alarmM;
int timerMS;
time_t timer;
time_t base;
int test = BST_UNCHECKED;
int mute = BST_UNCHECKED;
 
//==============================================================================
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
	GetIniFileName();
 
	midiOutOpen(&hmo, MIDI_MAPPER, NULL, 0, CALLBACK_NULL);
	midiOutShortMsg(hmo, MAKESMSG(0xc, CH, 0, 0));	// Program Change: Piano
 
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);
 
	midiOutReset(hmo);
	midiOutClose(hmo);
	return 0;
}
 
void GetIniFileName()
{
	TCHAR szPath	[_MAX_PATH];
	TCHAR szDrive	[_MAX_DRIVE];
	TCHAR szDir	[_MAX_DIR];
	TCHAR szFName	[_MAX_FNAME];
	TCHAR szExt	[_MAX_EXT];
 
	GetModuleFileName(NULL, szPath, _countof(szPath));
	_wsplitpath_s(szPath, szDrive, szDir, szFName, szExt);
	_wmakepath_s(szIniFile, szDrive, szDir, szFName, L"ini");
}
 
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	INT_PTR res = TRUE;	// メッセージを処理した
 
	switch (uMsg) {
	case WM_TIMER:
		OnTimer(hDlg);
		break;
	case WM_DRAWITEM:
		OnDrawItem(wParam, lParam);
		break;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDC_TEST:
			test = Button_GetCheck(GetDlgItem(hDlg, IDC_TEST));
			break;
		case IDC_MUTE:
			mute = Button_GetCheck(GetDlgItem(hDlg, IDC_MUTE));
			break;
		case IDOK:	// Start
			OnOK(hDlg);
			break;
		case IDCANCEL:	// Stop
			mode = 0;
			alarm = FALSE;
			szMessage[0] = L'\0';
			InvalidateRect(hMessage, NULL, FALSE);
			break;
		}
		break;
	case WM_INITDIALOG:
		OnInitDialog(hDlg);
		//SetFocus(GetDlgItem(hDlg, IDC_ALARM_H));
		//res = FALSE;	// SetFocusでフォーカスを設定した場合はFALSE
		break;
	case WM_CLOSE:
		EndDialog(hDlg, 0);
		break;
	case WM_DESTROY:
		OnDestroy(hDlg);
		break;
	default:
		res = FALSE;	// メッセージを処理しなかった
	}
	return res;
}
 
void OnInitDialog(HWND hDlg)
{
	int nX = GetPrivateProfileInt(SECT, L"X", 100, szIniFile);
	int nY = GetPrivateProfileInt(SECT, L"Y", 100, szIniFile);
	SetWindowPos(hDlg, HWND_TOP, nX, nY, 0, 0, SWP_NOSIZE);
 
	// フォント作成
	LOGFONT lf;
	ZeroMemory(&lf, sizeof lf);
	lf.lfCharSet	= DEFAULT_CHARSET;
	lf.lfHeight	= 60;
	wcscpy_s(lf.lfFaceName, L"Arial Black");
	hFont = CreateFontIndirect(&lf);
 
	hClock = GetDlgItem(hDlg, IDC_CLOCK);
	hMessage = GetDlgItem(hDlg, IDC_MESSAGE);
	uIDEvent = SetTimer(hDlg, 1, 1000, NULL);
	Button_SetCheck(GetDlgItem(hDlg, IDC_RADIO1), BST_CHECKED);
	mode = 0;
	time(&timer);
}
 
void OnDestroy(HWND hDlg)
{
	RECT rc;
	GetWindowRect(hDlg, &rc);
 
	TCHAR szBuf[16];
	swprintf_s(szBuf, L"%d", rc.left);
	WritePrivateProfileString(SECT, L"X", szBuf, szIniFile);
	swprintf_s(szBuf, L"%d", rc.top);
	WritePrivateProfileString(SECT, L"Y", szBuf, szIniFile);
 
	DeleteObject(hFont);
	KillTimer(hDlg, uIDEvent);
}
 
void OnTimer(HWND hDlg)
{
	InvalidateRect(hClock, NULL, FALSE);
	if (note) {
		midiOutShortMsg(hmo, MAKESMSG(0x8, CH, NOTE_NO, 0));	// Note Off
		note = FALSE;
	}
 
	time(&timer);
	alarm = (test == BST_CHECKED);
	switch (mode) {
	case 1:	// Alarm
		{
			tm tm;
			localtime_s(&tm, &timer);
			if (tm.tm_hour == alarmH && tm.tm_min == alarmM) {
				alarm = TRUE;
			}
		}
		break;
	case 2:	// Timer
		{
			int count = int(base - timer);
			if (count <= 0) {
				count = 0;
				alarm = TRUE;
			}
			swprintf_s(szMessage, L"%d:%02d", count / 60, count % 60);
			InvalidateRect(hMessage, NULL, FALSE);
		}
		break;
	case 3:	// Stop Watch
		{
			int count = int(timer - base);
			swprintf_s(szMessage, L"%02d:%02d:%02d", count / 3600, (count / 60) % 60, count % 60);
			InvalidateRect(hMessage, NULL, FALSE);
		}
		break;
	}
 
	if (alarm && mute == BST_UNCHECKED) {
		midiOutShortMsg(hmo, MAKESMSG(0x9, CH, NOTE_NO, 127));	// Note On
		note = TRUE;
	}
}
 
void OnDrawItem(WPARAM wParam, LPARAM lParam)
{
	LPDRAWITEMSTRUCT pdi = (LPDRAWITEMSTRUCT)lParam;
	HDC hdc = pdi->hDC;
	SetBkMode(hdc, TRANSPARENT);	// 背景透過モード
	HGDIOBJ hFontOld = SelectObject(hdc, hFont);
 
	// 背景塗り潰し
	RECT rc;
	GetClientRect(pdi->hwndItem, &rc);
	FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
 
	switch (pdi->CtlID) {
	case IDC_CLOCK:
		tm tm;
		localtime_s(&tm, &timer);
		TCHAR clock[8+1];
		swprintf_s(clock, L"%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
		DrawText(hdc, clock, -1, &rc, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
		break;
	case IDC_MESSAGE:
		SetTextColor(hdc, RGB(255,0,0));
		DrawText(hdc, szMessage, -1, &rc, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
		break;
	}
	SelectObject(hdc, hFontOld);
}
 
void OnOK(HWND hDlg)
{
	GetDlgData(hDlg);
 
	switch (mode) {
	case 1:	// Alarm
		swprintf_s(szMessage, L"%02d:%02d:00", alarmH, alarmM);
		InvalidateRect(hMessage, NULL, FALSE);
		break;
	case 2:	// Timer
		base = timer + (timerMS / 100) * 60 + (timerMS % 100);
		break;
	case 3:	// Stop Watch
		base = timer;
		break;
	}
}
 
BOOL GetDlgData(HWND hDlg)
{
	mode = 0;
	for (int n = 0; n < 3; n++) {
		if (Button_GetCheck(GetDlgItem(hDlg, IDC_RADIO1 + n)) == BST_CHECKED) {
			mode = 1 + n;
			break;
		}
	}
 
	BOOL b;
	alarmH	= GetDlgItemInt(hDlg, IDC_ALARM_H, &b, FALSE);
	alarmM	= GetDlgItemInt(hDlg, IDC_ALARM_M, &b, FALSE);
	timerMS	= GetDlgItemInt(hDlg, IDC_TIMER_MS, &b, FALSE);
	return TRUE;
}
 

resource.h
#define IDD_DIALOG	100
 
#define IDC_STATIC	-1
#define IDC_CLOCK	1000
#define IDC_MESSAGE	1001
#define IDC_ALARM_H	1002
#define IDC_ALARM_M	1003
#define IDC_TIMER_MS	1004
//#define IDC_TIMER_S	1005
#define IDC_TEST	1006
#define IDC_MUTE	1007
#define IDC_RADIO1	1101	// Alarm
#define IDC_RADIO2	1102	// Timer
#define IDC_RADIO3	1103	// Stop Watch
 

EzTimer.rc
// resource script
#include <Windows.h>
#include "resource.h"
 
IDD_DIALOG DIALOGEX 100, 100, 140, 165
STYLE WS_POPUPWINDOW | WS_MINIMIZEBOX
EXSTYLE WS_EX_APPWINDOW
CAPTION "EzTimer"
FONT 10, "MS Pゴシック"
BEGIN
	LTEXT		"",IDC_CLOCK,5,5,130,35,WS_BORDER | SS_OWNERDRAW
	LTEXT		"",IDC_MESSAGE,5,45,130,35,WS_BORDER | SS_OWNERDRAW
	CONTROL		"Alarm",IDC_RADIO1,"button",BS_AUTORADIOBUTTON | WS_GROUP,5,85,50,15
	CONTROL		"Timer",IDC_RADIO2,"button",BS_AUTORADIOBUTTON,5,105,50,15
	CONTROL		"Stop Watch",IDC_RADIO3,"button",BS_AUTORADIOBUTTON,5,125,50,15
	EDITTEXT	IDC_ALARM_H,70,86,15,13,WS_GROUP
	LTEXT		"h",IDC_STATIC,90,88,10,15
	EDITTEXT	IDC_ALARM_M,105,86,15,13
	LTEXT		"m",IDC_STATIC,125,88,10,15
	EDITTEXT	IDC_TIMER_MS,70,106,25,13
	LTEXT		"mmss",IDC_STATIC,100,108,25,15
//	EDITTEXT	IDC_TIMER_S,105,106,15,13
//	LTEXT		"s",IDC_STATIC,125,108,10,15
	AUTOCHECKBOX	"Test",IDC_TEST,5,145,30,15
	AUTOCHECKBOX	"Mute",IDC_MUTE,35,145,30,15
	PUSHBUTTON	"Start",IDOK,70,145,30,15
	PUSHBUTTON	"Stop",IDCANCEL,105,145,30,15
END