右クリックで出てくるメニューに「タイマー」「タイマーセット」が加わりました。
「タイマーセット」を選択すると左のようなダイアログボックスが出てきます。
これに希望の時間をセットします。左の例では1時間5秒(半端な時間です)にセットしてあります。
セットできる最大値は23時間59分59秒です。
「スタート」ボタンを押すと・・・
今まで、日付が表示されていた部分に残り時間が、刻々と表示されます。
0秒になるとWave音が鳴ります。途中でやめたい時は、右クリックして 「タイマー設定」ダイアログを出し、「ストップ」ボタンを押します。 (今回のプログラムでは一度ストップすると、その時間から再スタートすることはできません。)
では、プログラムを見てみましょう。
// clock07.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU BEGIN POPUP "ダミーです" BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)...", IDM_END END POPUP "オプション(&O)" BEGIN MENUITEM "背景色(&B)...", IDM_BACKGROUND MENUITEM "文字色(&T)...", IDM_TEXT MENUITEM "文字盤の色(&P)...", IDM_PLATE MENUITEM "長針の色(&L)...", IDM_LONG MENUITEM "短針の色(&S)...", IDM_SHORT MENUITEM "秒針の色(&O)...", IDM_SECOND END POPUP "アラーム(&L)" BEGIN MENUITEM "時刻設定(&S)...", IDM_ALARMSET END POPUP "タイマー(&T)" BEGIN MENUITEM "タイマーセット(&T)...", IDM_TIMER END END END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // CAT BITMAP "bitmap1.bmp" MASK BITMAP "bmp00001.bmp" ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYALARM DIALOGEX 0, 0, 115, 73 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "アラーム設定" FONT 10, "MS ゴシック", 400, 0, 0x80 BEGIN DEFPUSHBUTTON "OK",IDOK,7,52,50,14 PUSHBUTTON "キャンセル",IDCANCEL,58,52,50,14 CONTROL "アラームをセットする",IDC_CHECK1,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,15 CONTROL "",IDC_DATETIMEPICKER1,"SysDateTimePick32", DTS_RIGHTALIGN | DTS_UPDOWN | WS_TABSTOP,30,25,54,17 END MYTIMER DIALOGEX 0, 0, 123, 54 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "タイマー設定" FONT 10, "MS ゴシック", 400, 0, 0x80 BEGIN DEFPUSHBUTTON "スタート",IDOK,7,33,50,14 PUSHBUTTON "ストップ",IDCANCEL,65,33,50,14 CONTROL "",IDC_DATETIMEPICKER1,"SysDateTimePick32", DTS_RIGHTALIGN | DTS_UPDOWN | WS_TABSTOP,35,7,53,19 END ///////////////////////////////////////////////////////////////////////////// // // WAVE // BELL WAVE "ringin.wav"リソース・スクリプトです。
メニュー項目が追加になっています。
タイマーセットのダイアログボックスが追加となっています。
// clock07.cpp #define hParentKey HKEY_CURRENT_USER #define lpszSubKey "Software\\Kumei\\Clock" #define PAI 3.14159 #define CLOCK_WIDTH 250 //時計全体のウィンドウ幅 #define CLOCK_HEIGHT 60 //高さ #define MYTIMER 1 //タイマーID #include <windows.h> #include <windowsx.h> #include <math.h> #include <commctrl.h> #include <Mmsystem.h> #include "resource.h" typedef struct MYDATA { COLORREF cr_bg; //背景色 COLORREF cr_txt; //文字色 COLORREF cr_plate; //文字盤の色 COLORREF cr_short; //短針の色 COLORREF cr_long; //長針の色 COLORREF cr_second; //秒針の色 int x; int y; char szAlarmSet[8]; char szAlarmTime[16]; char szTimerTime[16]; } INIDATA; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK MyAlarmProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK MyTimerProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); HFONT SetMyFont(LPCTSTR, int); BOOL GetMyColor(HWND, COLORREF *, COLORREF); void GetInitialSettings(INIDATA *); BOOL GetDataDWORD(char *, DWORD *); BOOL GetDataString(char *, char *); BOOL SetInitialSettings(INIDATA); BOOL SetDataDWORD(char *, DWORD); BOOL SetDataString(char *, char *); BOOL ShowClock(HDC, char *, INIDATA); BOOL GetHMS(char *, int *, int *, int *); BOOL ShowBitmap(HDC, INIDATA); BOOL MyTimerShow(HDC, int, int, INIDATA, DWORD); BOOL SetHMS(char *, DWORD); char szClassName[] = "clock07"; //ウィンドウクラス char szAppName[] = "猫クロック"; //アプリケーション名 HINSTANCE hInst;MYDATA構造体にszTimerTimeメンバが増えました。一度セットした タイマー時間は、次回タイマーセットダイアログが出てきた時に反映されます。
タイマーセットダイアログのプロシージャ、MyTimerShow関数、SetHMS関数が増えました。
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; BOOL bRet; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) { if (bRet == -1) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int)msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); wc.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindowEx(WS_EX_TOPMOST, //拡張ウィンドウスタイル szClassName, "猫でもわかるWindowsプログラミング", //タイトルバーにこの名前が表示されます WS_POPUP, //ウィンドウの種類 0, //X座標 0, //Y座標 CLOCK_WIDTH, //幅 CLOCK_HEIGHT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }これらの関数に変更はありません。
//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id, x, y; SYSTEMTIME st; PAINTSTRUCT ps; HDC hdc; HFONT hFont; SIZE s; HRGN hRgn, hRgn1, hRgn2, hRound1Rgn, hRound2Rgn, hRectRgn; HBRUSH hBrush; HMENU hMenu, hSubMenu; POINT pt; COLORREF cr; static INIDATA inidata; RECT rc; char szYobi[8]; static char szBuf[64], szBuf2[64]; //時刻表示用 INITCOMMONCONTROLSEX ic; static BOOL bTimer; //タイマ表示かどうか static DWORD dwStartMs; MMTIME mm; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_DATE_CLASSES; InitCommonControlsEx(&ic); GetInitialSettings(&inidata); MoveWindow(hWnd, inidata.x, inidata.y, CLOCK_WIDTH, CLOCK_HEIGHT, TRUE); SetTimer(hWnd, MYTIMER, 1000, NULL); hRgn = CreateRectRgn(0, 0, 1, 1); hRgn1 = CreateRectRgn(0, 0, 1, 1); hRgn2 = CreateRectRgn(0, 0,1, 1); hRound1Rgn = CreateEllipticRgn(0, 0, CLOCK_HEIGHT, CLOCK_HEIGHT); hRectRgn = CreateRectRgn(CLOCK_HEIGHT / 2, 0, CLOCK_WIDTH - CLOCK_HEIGHT / 2, CLOCK_HEIGHT); CombineRgn(hRgn1, hRound1Rgn, hRectRgn, RGN_OR); hRound2Rgn = CreateEllipticRgn(CLOCK_WIDTH - CLOCK_HEIGHT, 0, CLOCK_WIDTH, CLOCK_HEIGHT); CombineRgn(hRgn2, hRound2Rgn, hRectRgn, RGN_OR); CombineRgn(hRgn, hRgn1, hRgn2, RGN_OR); SetWindowRgn(hWnd, hRgn, TRUE); DeleteObject(hRound1Rgn); DeleteObject(hRound2Rgn); DeleteObject(hRectRgn); DeleteObject(hRgn1); DeleteObject(hRgn2); break; case WM_RBUTTONDOWN: pt.x = LOWORD(lp); pt.y = HIWORD(lp); hMenu = LoadMenu(hInst, "MYMENU"); hSubMenu = GetSubMenu(hMenu, 0); ClientToScreen(hWnd, &pt); TrackPopupMenu(hSubMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL); DestroyMenu(hMenu); break; case WM_LBUTTONDOWN: PostMessage(hWnd, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lp); break; case WM_TIMER: if (wp != MYTIMER) return DefWindowProc(hWnd, msg, wp, lp); GetLocalTime(&st); wsprintf(szBuf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); switch (st.wDayOfWeek) { case 0: strcpy(szYobi, "Sun"); break; case 1: strcpy(szYobi, "Mon"); break; case 2: strcpy(szYobi, "Tue"); break; case 3: strcpy(szYobi, "Wed"); break; case 4: strcpy(szYobi, "Thu"); break; case 5: strcpy(szYobi, "Fri"); break; case 6: strcpy(szYobi, "Sat"); break; } wsprintf(szBuf2, "%d/%02d/%02d(%s)", st.wYear, st.wMonth, st.wDay, szYobi); if (strcmp(inidata.szAlarmSet, "Yes") == 0 && strcmp(szBuf, inidata.szAlarmTime) == 0) { PlaySound("BELL", hInst, SND_RESOURCE | SND_ASYNC | SND_LOOP); MessageBox(hWnd, "時間ですよ", szAppName, MB_OK); PlaySound(NULL, hInst, SND_PURGE); } InvalidateRect(hWnd, NULL, TRUE); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); hBrush = CreateSolidBrush(inidata.cr_bg); SelectObject(hdc, hBrush); PatBlt(hdc, 0, 0, CLOCK_WIDTH, CLOCK_HEIGHT, PATCOPY); ShowBitmap(hdc, inidata); hFont = SetMyFont("MS ゴシック", 30); SelectObject(hdc, hFont); GetTextExtentPoint32(hdc, szBuf, (int)strlen(szBuf), &s); x = (CLOCK_WIDTH - s.cx) / 2 + 4; y = (CLOCK_HEIGHT - s.cy) / 2 + 10; SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, inidata.cr_txt); TextOut(hdc, x, y, szBuf, (int)strlen(szBuf)); DeleteObject(hFont); hFont = SetMyFont("MS ゴシック", 16); SelectObject(hdc, hFont); GetTextExtentPoint32(hdc, szBuf2, (int)strlen(szBuf2), &s); x = (CLOCK_WIDTH - s.cx) / 2 + 4; if (!bTimer) { TextOut(hdc, x, 4, szBuf2, (int)strlen(szBuf2)); } else { if (MyTimerShow(hdc, x, 4, inidata, dwStartMs)) { bTimer = FALSE; PlaySound("BELL", hInst, SND_RESOURCE | SND_ASYNC | SND_LOOP); MessageBox(hWnd, "時間ですよ", szAppName, MB_OK); PlaySound(NULL, hInst, SND_PURGE); } } DeleteObject(hFont); DeleteObject(hBrush); ShowClock(hdc, szBuf, inidata); EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_BACKGROUND: if (GetMyColor(hWnd, &cr, inidata.cr_bg)) { inidata.cr_bg = cr; } break; case IDM_TEXT: if (GetMyColor(hWnd, &cr, inidata.cr_txt)) { inidata.cr_txt = cr; } break; case IDM_PLATE: if (GetMyColor(hWnd, &cr, inidata.cr_plate)) { inidata.cr_plate = cr; } break; case IDM_SHORT: if (GetMyColor(hWnd, &cr, inidata.cr_short)) { inidata.cr_short = cr; } break; case IDM_LONG: if (GetMyColor(hWnd, &cr, inidata.cr_long)) { inidata.cr_long = cr; } break; case IDM_SECOND: if (GetMyColor(hWnd, &cr, inidata.cr_second)) { inidata.cr_second = cr; } break; case IDM_ALARMSET: DialogBoxParam(hInst, "MYALARM", hWnd, (DLGPROC)MyAlarmProc, (LPARAM)&inidata); break; case IDM_TIMER: if (DialogBoxParam(hInst, "MYTIMER", hWnd, (DLGPROC)MyTimerProc, (LPARAM)&inidata) == IDOK) { bTimer = TRUE; memset(&mm, 0, sizeof(MMTIME)); mm.wType = TIME_MS; timeGetSystemTime(&mm, sizeof(MMTIME)); dwStartMs = mm.u.ms; } else { bTimer = FALSE; } break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよろしいですか", szAppName, MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { GetWindowRect(hWnd, &rc); inidata.x = rc.left; inidata.y = rc.top; DestroyWindow(hWnd); } break; case WM_DESTROY: SetInitialSettings(inidata); KillTimer(hWnd, MYTIMER); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }メインウィンドウのプロシージャです。
WM_TIMERメッセージが来た時、bTimerがTRUEの時(タイマー作動中の時) MyTimerShow関数を呼んでタイマーの残り時間を表示するようにしました。
また、MyTimerShow関数がTRUEを返した時(残り時間が0となった時)PlaySound関数で Wave音を鳴らします。この場合、タイマーはもう作動しなくてよいので、bTimerをFALSE にしておきます。
PlaySound関数については第342章に解説があります。
メニューからIDM_TIMERが選択された時は、DialogBoxParam関数でタイマーセット ダイアログを出します。
そして、このダイアログがIDOK(「スタート」ボタンが押された)を返したら タイマーをスタートさせないといけないので、bTimerをTRUEにします。
そして、timeGetSystemTime関数でこの時のシステム時間を取得します。 これは、Windowsが起動してからのミリセコンドです。これをstaticな変数dwStartMsに保存しておきます。
MMRESULT timeGetSystemTime( LPMMTIME pmmt, UINT cbmmt );システム時刻(Windowsが起動してからの経過時間)をミリセコンドで取得します。
pmmtには、MMTIME構造体のアドレスを指定します。
cbmmtには、MMTIME構造体のサイズ(バイト)を指定します。
この関数を使うにはmmsystem.hをインクルードし、プロジェクトにwinmm.libを参加 させる必要があります。
MMTIME構造体は次のように定義されています。
typedef struct mmtime_tag { UINT wType; union { DWORD ms; DWORD sample; DWORD cb; DWORD ticks; struct { BYTE hour; BYTE min; BYTE sec; BYTE frame; BYTE fps; BYTE dummy; BYTE pad[2] } smpte; struct { DWORD songptrpos; } midi; } u; } MMTIME;時間フォーマットを指定します。次の中から1つを選びます。
値 | 意味 |
---|---|
TIME_BYTES | ファイルの先頭からの現在の位置のオフセット(バイト) |
TIME_MIDI | MIDI時間 |
TIME_MS | ミリセコンド |
TIME_SAMPLES | WAVE形式オーディオサンプルの数 |
TIME_SMPTE | SMPTE規格フォーマットの時間 |
TIME_TICKS | MIDIストリーム内のtick数
msには、ミリセコンドが格納されます。(TIME_MSを指定した場合)
sampleには、先頭からのサンプル数が格納されます。(TIME_SAMPLES)
cbには、ファイルの先頭からのオフセットが格納されます。(TIME_BYTES)
ticksには、MIDIストリーム内のtick数が格納されます。(TIME_TICKS)
hourはSMPTE企画の時です。
minは分、secは秒、frameはフレーム番号、fpsは1秒あたりのフレーム数、 songptrposは、ソングポインタの位置です。
さて、システムタイムをミリセコンドで取得するだけならtimeGetTime関数 の方が簡単ですが、ここではあえてtimeGetSystemTime関数を使いました。 気にくわない人は書き換えてください。
DWORD timeGetTime(VOID);システム時間をミリセコンドで返します。
HFONT SetMyFont(LPCTSTR face, int h) { HFONT hFont; hFont = CreateFont(h, //フォント高さ 0, //文字幅 0, //テキストの角度 0, //ベースラインとx軸との角度 FW_REGULAR, //フォントの重さ(太さ) FALSE, //イタリック体 FALSE, //アンダーライン FALSE, //打ち消し線 SHIFTJIS_CHARSET, //文字セット OUT_DEFAULT_PRECIS, //出力精度 CLIP_DEFAULT_PRECIS,//クリッピング精度 PROOF_QUALITY, //出力品質 FIXED_PITCH | FF_MODERN,//ピッチとファミリー face); //書体名 return hFont; } BOOL GetMyColor(HWND hWnd, COLORREF *lpcr, COLORREF org_cr) { CHOOSECOLOR cc; static DWORD dwCustColors[16]; cc.lStructSize = sizeof(CHOOSECOLOR); cc.hwndOwner = hWnd; cc.lpCustColors = dwCustColors; cc.rgbResult = org_cr; cc.Flags = CC_RGBINIT; if (ChooseColor(&cc)) { *lpcr = cc.rgbResult; return TRUE; } return FALSE; }これらの関数に変更はありません。
void GetInitialSettings(INIDATA *lpini) { DWORD dwData; char szData[32]; if (GetDataDWORD("background-color", &dwData)) { lpini->cr_bg = (COLORREF)dwData; } else { lpini->cr_bg = RGB(0, 255, 255); } if (GetDataDWORD("text-color", &dwData)) { lpini->cr_txt = (COLORREF)dwData; } else { lpini->cr_txt = RGB(0, 0, 0); } if (GetDataDWORD("x", &dwData)) { lpini->x = (int)dwData; } else { lpini->x = 0; } if (GetDataDWORD("y", &dwData)) { lpini->y = (int)dwData; } else { lpini->y = 0; } if (GetDataDWORD("short-color", &dwData)) { lpini->cr_short = (COLORREF)dwData; } else { lpini->cr_short = RGB(0, 0, 255); } if (GetDataDWORD("long-color", &dwData)) { lpini->cr_long = (COLORREF)dwData; } else { lpini->cr_long = RGB(0, 0, 0); } if (GetDataDWORD("second-color", &dwData)) { lpini->cr_second = (COLORREF)dwData; } else { lpini->cr_second = RGB(255, 0, 0); } if (GetDataDWORD("plate-color", &dwData)) { lpini->cr_plate = (COLORREF)dwData; } else { lpini->cr_plate = RGB(0, 255, 255); } if (GetDataString("alarm-set", szData)) { strcpy(lpini->szAlarmSet, szData); } else { strcpy(lpini->szAlarmSet, "No"); } if (GetDataString("alarm-time", szData)) { strcpy(lpini->szAlarmTime, szData); } else { strcpy(lpini->szAlarmTime, "00:00:00"); } if (GetDataString("timer-time", szData)) { strcpy(lpini->szTimerTime, szData); } else { strcpy(lpini->szTimerTime, "00:00:00"); } return; }レジストリから値を読み出しINIDATA構造体にセットします。
timer-timeエントリが増えています。読み込みに失敗した時は"00:00:00"に設定します。
BOOL GetDataDWORD(char *szName, DWORD *dwValue) { HKEY hKey; DWORD dwPosition; DWORD dwType = REG_DWORD; DWORD dwByte = 32; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); if (RegQueryValueEx(hKey, szName, NULL, &dwType, (BYTE *)dwValue, &dwByte) != ERROR_SUCCESS) { RegCloseKey(hKey); return FALSE; } RegCloseKey(hKey); return TRUE; } BOOL GetDataString(char *szName, char *szValue) { HKEY hKey; DWORD dwPosition; DWORD dwType = REG_SZ; DWORD dwByte = 32; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); if (RegQueryValueEx(hKey, szName, NULL, &dwType, (BYTE *)szValue, &dwByte) != ERROR_SUCCESS) { return FALSE; } RegCloseKey(hKey); return TRUE; }これらの関数に変更はありません。
BOOL SetInitialSettings(INIDATA inidata) { SetDataDWORD("background-color", inidata.cr_bg); SetDataDWORD("text-color", inidata.cr_txt); SetDataDWORD("x", inidata.x); SetDataDWORD("y", inidata.y); SetDataDWORD("short-color", inidata.cr_short); SetDataDWORD("long-color", inidata.cr_long); SetDataDWORD("second-color", inidata.cr_second); SetDataDWORD("plate-color", inidata.cr_plate); SetDataString("alarm-set", inidata.szAlarmSet); SetDataString("alarm-time", inidata.szAlarmTime); SetDataString("timer-time", inidata.szTimerTime); return TRUE; }INIDATA構造体の値をレジストリに書き込みます。timer-timeエントリへの 書き込みが増えています。
BOOL SetDataDWORD(char *szName, DWORD dwData) { HKEY hKey; DWORD dwPosition; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); RegSetValueEx(hKey, szName, 0, REG_DWORD, (CONST BYTE *)&dwData, sizeof(DWORD)); RegCloseKey(hKey); return TRUE; } BOOL SetDataString(char *szName, char *szData) { HKEY hKey; DWORD dwPosition; LONG lResult; RegCreateKeyEx(hParentKey, lpszSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwPosition); lResult = RegSetValueEx(hKey, szName, 0, REG_SZ, (CONST BYTE *)szData, lstrlen(szData)); RegCloseKey(hKey); return TRUE; } BOOL ShowClock(HDC hdc, char *lpszBuf, INIDATA inidata) { HBRUSH hBrush; HPEN hPen; int h, m, s, x0, y0, x, y; int l = CLOCK_HEIGHT / 2; if (strcmp(lpszBuf, "") == 0) return FALSE; hBrush = CreateSolidBrush(inidata.cr_plate); SelectObject(hdc, hBrush); Ellipse(hdc, 1, 1, CLOCK_HEIGHT - 1, CLOCK_HEIGHT - 1); Ellipse(hdc, 4, 4, CLOCK_HEIGHT - 4, CLOCK_HEIGHT - 4); DeleteObject(hBrush); GetHMS(lpszBuf, &h, &m, &s); x0 = y0 = CLOCK_HEIGHT / 2; //短針 if (h > 11) h -= 12; hPen = CreatePen(PS_SOLID, 4, inidata.cr_short); SelectObject(hdc, hPen); MoveToEx(hdc, x0, y0, NULL); x = (int)(x0 + (l - 16) * sin(h * PAI / 6 + m * PAI / 360)); y = (int)(x0 - (l - 16) * cos(h * PAI / 6 + m * PAI / 360)); LineTo(hdc, x, y); DeleteObject(hPen); //長針 hPen = CreatePen(PS_SOLID, 2, inidata.cr_long); SelectObject(hdc, hPen); MoveToEx(hdc, x0, y0, NULL); x = (int)(x0 + (l - 10) * sin(m * PAI / 30 + s * PAI / 1800)); y = (int)(y0 - (l - 10) * cos(m * PAI / 30 + s * PAI / 1800)); LineTo(hdc, x, y); DeleteObject(hPen); //秒針 hPen = CreatePen(PS_SOLID, 1, inidata.cr_second); SelectObject(hdc, hPen); MoveToEx(hdc, x0, y0, NULL); x = (int)(x0 + (l - 5) * sin(s * PAI / 30)); y = (int)(y0 - (l - 5) * cos(s * PAI / 30)); LineTo(hdc, x, y); DeleteObject(hPen); return TRUE; } BOOL GetHMS(char *lpszBuf, int *lpH, int *lpM, int *lpS) { char szTemp[64], *token, szSep[] = ":"; strcpy(szTemp, lpszBuf); token = strtok(szTemp, szSep); *lpH = atoi(token); token = strtok(NULL, szSep); *lpM = atoi(token); token = strtok(NULL, szSep); *lpS = atoi(token); return TRUE; } BOOL ShowBitmap(HDC hdc, INIDATA inidata) { HBITMAP hBmp, hMask; BITMAP bmp_info; HDC hdc_mem; int wx,wy; HBRUSH hBrush; hBrush = CreateSolidBrush(inidata.cr_bg); SelectObject(hdc, hBrush); hBmp = (HBITMAP)LoadImage(hInst, "CAT", IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); hMask = (HBITMAP)LoadImage(hInst, "MASK", IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); if (hMask == NULL) { MessageBox(NULL, "Error", szAppName, MB_OK); return FALSE; } GetObject(hBmp, (int)sizeof(BITMAP), &bmp_info); wx = bmp_info.bmWidth; wy = bmp_info.bmHeight; hdc_mem = CreateCompatibleDC(hdc); SelectObject(hdc_mem, hBmp); MaskBlt(hdc, CLOCK_WIDTH - wx - 5, 5, wx, wy, hdc_mem, 0, 0, hMask, 0, 0, MAKEROP4(SRCCOPY, PATCOPY)); DeleteObject(hBmp); DeleteObject(hMask); DeleteObject(hBrush); DeleteDC(hdc_mem); return TRUE; } BOOL CALLBACK MyAlarmProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { SYSTEMTIME st; static HWND hTime, hCheck; char szBuf[32]; static INIDATA *lpinidata; int h, m, s; switch (msg) { case WM_INITDIALOG: hTime = GetDlgItem(hDlg, IDC_DATETIMEPICKER1); hCheck = GetDlgItem(hDlg, IDC_CHECK1); SendMessage(hTime, DTM_SETFORMAT, 0, (LPARAM)"HH:mm:ss"); lpinidata = (INIDATA *)lp; if (strcmp(lpinidata->szAlarmSet, "No") == 0) { EnableWindow(hTime, FALSE); Button_SetCheck(hCheck, BST_UNCHECKED); } else { EnableWindow(hTime, TRUE); Button_SetCheck(hCheck, BST_CHECKED); GetHMS(lpinidata->szAlarmTime, &h, &m, &s); GetLocalTime(&st); st.wHour = h; st.wMinute = m; st.wSecond = s; DateTime_SetSystemtime(hTime, GDT_VALID, &st); } return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: if (Button_GetCheck(hCheck) == BST_CHECKED) { strcpy(lpinidata->szAlarmSet, "Yes"); DateTime_GetSystemtime(hTime, &st); wsprintf(szBuf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); strcpy(lpinidata->szAlarmTime, szBuf); } else { strcpy(lpinidata->szAlarmSet, "No"); strcpy(lpinidata->szAlarmTime, "00:00:00"); } EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; case IDC_CHECK1: if (Button_GetCheck(hCheck) == BST_CHECKED) { EnableWindow(hTime, TRUE); } else EnableWindow(hTime, FALSE); return TRUE; } return FALSE; } return FALSE; }これらの関数に変更はありません。
BOOL CALLBACK MyTimerProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hTime; SYSTEMTIME st; char szBuf[64]; static INIDATA *lpini; int h, m, s; switch (msg) { case WM_INITDIALOG: hTime = GetDlgItem(hDlg, IDC_DATETIMEPICKER1); SendMessage(hTime, DTM_SETFORMAT, 0, (LPARAM)"HH:mm:ss"); lpini = (INIDATA *)lp; GetLocalTime(&st); GetHMS(lpini->szTimerTime, &h, &m, &s); st.wHour = h; st.wMinute = m; st.wSecond = s; DateTime_SetSystemtime(hTime, GDT_VALID, &st); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: DateTime_GetSystemtime(hTime, &st); wsprintf(szBuf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond); strcpy(lpini->szTimerTime, szBuf); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }タイマー設定ダイアログのプロシージャです。
WM_INITDIALOGメッセージが来たら、Date and Time Pickerコントロールのフォーマットを 指定します。そして、INIDATA構造体に指定してある時間にセットします。
スタートボタン(IDOK)が押されたらDate and Time Pickerコントロールに指定してある時間を取得して、szBufに書き込みます。
また、INIDATA構造体に書き込みます。
BOOL MyTimerShow(HDC hdc, int x, int y, INIDATA inidata, DWORD dwStart) { MMTIME mm; char szBuf[64]; DWORD dwNow, dwTimerSec; int h, m, s; GetHMS(inidata.szTimerTime, &h, &m, &s); dwTimerSec = h * 60 * 60 + m * 60 + s; timeGetSystemTime(&mm, (UINT)sizeof(MMTIME)); dwNow = mm.u.ms; SetHMS(szBuf, dwTimerSec - (dwNow - dwStart) / 1000); TextOut(hdc, x, y, szBuf, (int)strlen(szBuf)); if (strcmp(szBuf, "00:00:00") == 0) return TRUE; return FALSE; }タイマーの残り時間を表示する関数です。
GetHMS関数を利用して、inidata構造体のszTimerTimeメンバの"XX:XX:XX"形式の文字列から時、分、秒を取得します。これから、セットした時間の秒数をdwTimerSecに格納します。
timeGetSystemTime関数で現在のシステム時間を取得します。
現在のシステム時間から、スタート時のシステム時間の差を1000で割ったものを、 dwTimerSecから引くと残り時間(秒)がわかります。
秒を"XX:XX:XX"形式の文字列に変換するのが、SetHMS関数です。
変換後の文字列が"00:00:00"となった場合はTRUEを返し、そうでない場合はFALSEを返します。
BOOL SetHMS(char *lpszBuf, DWORD dwTm) { int h, m, s; h = dwTm / (60 * 60); m = (dwTm - h * 60 * 60) / 60; s = dwTm - h * 60 * 60 - m * 60; if (h > 23) { h = 0; m = 0; s = 0; } wsprintf(lpszBuf, "%02d:%02d:%02d", h, m, s); return TRUE; }時、分、秒の値から"XX:XX:XX"形式の文字列を作ります。 これは、眺めるとわかりますね。
今回は、ちょっと面倒くさいところもありましたが比較的簡単でした。
Update 22/Jan/2003 By Y.Kumei