WAKEUP.C的詳細註釋

/*---------------------------------------
   WAKEUP.C -- Alarm Clock Program
               (c) Charles Petzold, 1998
  ---------------------------------------*/

#include <windows.h>
#include <commctrl.h>  //包含通用控件頭文件

     // ID values for 3 child windows三個子窗口ID

#define ID_TIMEPICK 0    //時間控件ID
#define ID_CHECKBOX 1  //核取方塊ID
#define ID_PUSHBTN  2    //關閉響鈴按鈕ID

     // Timer ID計時器ID

#define ID_TIMER    1

     // Number of 100-nanosecond increments (ie FILETIME ticks) in an hour一小時包含多少個100納秒的
    //數量

#define FTTICKSPERHOUR (60 * 60 * (LONGLONG) 10000000)

     // Defines and structure for waveform "file"   定義音頻流結構文件

#define SAMPRATE  11025    //取樣頻率
#define NUMSAMPS  (3 * SAMPRATE)    //取樣的數量
#define HALFSAMPS (NUMSAMPS / 2)   //取樣數量的一半

typedef struct
{
     char  chRiff[4] ;
     DWORD dwRiffSize ;
     char  chWave[4] ;
     char  chFmt [4] ;
     DWORD dwFmtSize ;
     PCMWAVEFORMAT pwf ;
     char  chData[4] ;
     DWORD dwDataSize ;
     BYTE  byData[0] ;
}
WAVEFORM ;  //定義一個音頻流結構體

     // The window proc and the subclass proc主窗口過程與子窗口類過程函數

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;  //主窗口過程函數
LRESULT CALLBACK SubProc (HWND, UINT, WPARAM, LPARAM) ;  //子窗口類過程函數

     // Original window procedure addresses for the subclassed windows儲存原子窗口過程函數數組

WNDPROC SubbedProc [3] ;

     // The current child window with the input focus   具有輸入焦點的當前子窗口

HWND hwndFocus ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst,  //主函數
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName [] = TEXT ("WakeUp") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = 0 ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) (1 + COLOR_BTNFACE) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, szAppName,
                          WS_OVERLAPPED | WS_CAPTION |
                                          WS_SYSMENU | WS_MINIMIZEBOX,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

//主窗口過程
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HWND          hwndDTP, hwndCheck, hwndPush ;  //定義時間、核取與響鈴關閉按鈕控件句柄
     static WAVEFORM      waveform = { "RIFF", NUMSAMPS + 0x24, "WAVE", "fmt ",
                                       sizeof (PCMWAVEFORMAT), 1, 1, SAMPRATE,
                                       SAMPRATE, 1, 8, "data", NUMSAMPS } ;  //初始化音頻流結構體
     static WAVEFORM    * pwaveform ;  //定義音頻流結構體指針
     FILETIME             ft ;  //定義一個文件時間變量
     HINSTANCE            hInstance ;  //定義一個執行實例句柄
     INITCOMMONCONTROLSEX icex ;  //定義一個初始化通用控件結構體句柄
     int                  i, cxChar, cyChar ;
     LARGE_INTEGER        li ;   //定義一個用於儲存時間的大整數結構體變量
     SYSTEMTIME           st ;   //定義一個系統時間結構體變量

     switch (message)
     {
     case WM_CREATE:    //處理窗口創建消息
               // Some initialization stuff初始化某些數據

          hInstance = (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE) ; //取得窗口執行實例句柄

          //初始化時間通用控件
          icex.dwSize = sizeof (icex) ;
          icex.dwICC  = ICC_DATE_CLASSES ;
          InitCommonControlsEx (&icex) ;

               // Create the waveform file with alternating square waves用方波數據交替創建波形文件

          pwaveform = malloc (sizeof (WAVEFORM) + NUMSAMPS) ;  //爲音頻流結構分配內存
          * pwaveform = waveform ;  //填入音頻流結構體數據

          for (i = 0 ; i < HALFSAMPS ; i++)  //用方波數據給byData賦值
               if (i % 600 < 300)
                    if (i % 16 < 8)
                         pwaveform->byData[i] = 25 ;
                    else
                         pwaveform->byData[i] = 230 ;
               else
                    if (i % 8 < 4)
                         pwaveform->byData[i] = 25 ;
                    else
                         pwaveform->byData[i] = 230 ;

               // Get character size and set a fixed window size.取得字符尺寸和設置主窗口尺寸

          cxChar = LOWORD (GetDialogBaseUnits ()) ;
          cyChar = HIWORD (GetDialogBaseUnits ()) ;

          SetWindowPos (hwnd, NULL, 0, 0,    //設置主窗口的位置與尺寸
                        42 * cxChar,
                        10 * cyChar / 3 + 2 * GetSystemMetrics (SM_CYBORDER) +
                                              GetSystemMetrics (SM_CYCAPTION),
                        SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE) ;

               // Create the three child windows創建三個子窗口控件

          hwndDTP = CreateWindow (DATETIMEPICK_CLASS, TEXT (""),   //創建時間窗口控件
                         WS_BORDER | WS_CHILD | WS_VISIBLE | DTS_TIMEFORMAT,
                         2 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3,
                         hwnd, (HMENU) ID_TIMEPICK, hInstance, NULL) ;

          hwndCheck = CreateWindow (TEXT ("Button"), TEXT ("Set Alarm"),  //創建鬧鐘核取控件
                         WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
                         16 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3,
                         hwnd, (HMENU) ID_CHECKBOX, hInstance, NULL) ;

          hwndPush = CreateWindow (TEXT ("Button"), TEXT ("Turn Off"),   //創建響鈴關閉按鈕控件
                         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
                         28 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3,
                         hwnd, (HMENU) ID_PUSHBTN, hInstance, NULL) ;

          hwndFocus = hwndDTP ;  //設置時間控件具有輸入焦點

               // Subclass the three child windows子窗口類化三個子窗口控件

          //將三個子窗口控件的默認處理函數儲存起來並替換爲SubProc
          SubbedProc [ID_TIMEPICK] = (WNDPROC)
                         SetWindowLong (hwndDTP, GWL_WNDPROC, (LONG) SubProc) ;
          SubbedProc [ID_CHECKBOX] = (WNDPROC)
                         SetWindowLong (hwndCheck, GWL_WNDPROC, (LONG) SubProc);
          SubbedProc [ID_PUSHBTN] = (WNDPROC)
                         SetWindowLong (hwndPush, GWL_WNDPROC, (LONG) SubProc) ;
          
          // Set the date and time picker control to the current time將時間控件設爲當前時間加上9小時,
          // plus 9 hours, rounded down to next lowest hour   並調整爲最接近的小時數       
          GetLocalTime (&st) ;  //獲取用戶當前時間
          SystemTimeToFileTime (&st, &ft) ;  //將時間轉換爲文件時間
          li = * (LARGE_INTEGER *) &ft ;  //將時間存入一個大整數結構體
          li.QuadPart += 9 * FTTICKSPERHOUR ;   //加上9個小時包含的100納秒的數量
          ft = * (FILETIME *) &li ;  //將大整數結構體轉換爲文件時間
          FileTimeToSystemTime (&ft, &st) ;  //將文件時間轉換爲系統時間
          st.wMinute = st.wSecond = st.wMilliseconds = 0 ;
          SendMessage (hwndDTP, DTM_SETSYSTEMTIME, 0, (LPARAM) &st) ;  //設置時間控件的時間
          return 0 ;

     case WM_SETFOCUS:  //處理設置輸入焦點消息
          SetFocus (hwndFocus) ;  //設置控件具有輸入焦點
          return 0 ;

     case WM_COMMAND:  //處理控件命令
          switch (LOWORD (wParam))      // control ID
          {
          case ID_CHECKBOX:  //處理鬧鐘核取控件
              
                    // When the user checks the "Set Alarm" button, get the當按下時,取得控件時間並減去當前
                    // time in the date and time control and subtract from 系統時間
                    // it the current PC time.

               if (SendMessage (hwndCheck, BM_GETCHECK, 0, 0))  //測試控件是否選取
               {
                    SendMessage (hwndDTP, DTM_GETSYSTEMTIME, 0, (LPARAM) &st) ;//獲取控件時間
                    SystemTimeToFileTime (&st, &ft) ;
                    li = * (LARGE_INTEGER *) &ft ;

                    GetLocalTime (&st) ;  //獲取用戶當前時間
                    SystemTimeToFileTime (&st, &ft) ;
                    li.QuadPart -= ((LARGE_INTEGER *) &ft)->QuadPart ;  //減去當前時間

                         // Make sure the time is between 0 and 24 hours!確定時間位於24小時內
                         // These little adjustments let us completely ignore這些小調整讓我們完全忽略系統時間
                         // the date part of the SYSTEMTIME structures.結構體的日期部分

                    while (li.QuadPart < 0)
                         li.QuadPart += 24 * FTTICKSPERHOUR ;

                    li.QuadPart %= 24 * FTTICKSPERHOUR ;

                         // Set a one-shot timer! (See you in the morning.)設置一個一次性的計時器(早上好)

                    SetTimer (hwnd, ID_TIMER, (int) (li.QuadPart / 10000), 0) ;  //設置計時器
               }
                    // If button is being unchecked, kill the timer.如果沒選中核取方塊,刪除計時器

               else
                    KillTimer (hwnd, ID_TIMER) ;

               return 0 ;

               // The "Turn Off" button turns off the ringing alarm, and also關閉按鈕關閉響鈴,同時也使
               // unchecks the "Set Alarm" button and disables itself.鬧鐘核取方塊不選中

          case ID_PUSHBTN:  //處理關閉按鈕
               PlaySound (NULL, NULL, 0) ;  //播放關閉警告聲音
               SendMessage (hwndCheck, BM_SETCHECK, 0, 0) ;  //不選中核取方塊
               EnableWindow (hwndDTP, TRUE) ;  //允許時間控件
               EnableWindow (hwndCheck, TRUE) ;  //允許核取方塊
               EnableWindow (hwndPush, FALSE) ;  //不允許關閉按鈕
               SetFocus (hwndDTP) ;  //設置時間控件具有輸入焦點
               return 0 ;
          }
          return 0 ;

               // The WM_NOTIFY message comes from the date and time picker.這個WM_NOTIFY消息來自
               // If the user has checked "Set Alarm" and then gone back to 時間控件,如果用戶選取核取方塊
               // change the alarm time, there might be a discrepancy between然後又改變響鈴時間,那顯示時
               // the displayed time and the one-shot timer. So the program間與計時器之間可能是不同的,因此
               // unchecks "Set Alarm" and kills any outstanding timer.程序不選中核取方塊且刪除所有不一樣

              //的計時器
     case WM_NOTIFY:
          switch (wParam)          // control ID
          {
          case ID_TIMEPICK:
               switch (((NMHDR *) lParam)->code)       // notification code提醒代碼
               {
               case DTN_DATETIMECHANGE:   //時間改變消息
                    if (SendMessage (hwndCheck, BM_GETCHECK, 0, 0))  //測試核取方塊是否選中
                    {
                         KillTimer (hwnd, ID_TIMER) ; //如果選中則刪除計時器
                         SendMessage (hwndCheck, BM_SETCHECK, 0, 0) ;  //不選中核取方塊
                    }
                    return 0 ;
               }
          }
          return 0 ;

          // The WM_COMMAND message comes from the two buttons.

     case WM_TIMER:

               // When the timer message comes, kill the timer (because we only當響鈴時間到來時,刪除計時
               // want a one-shot) and start the annoying alarm noise going.器(因爲只需一次)並開始響鈴

          KillTimer (hwnd, ID_TIMER) ;  //刪除計時器
          PlaySound ((PTSTR) pwaveform,  NULL,   //用異步方式循環播放響鈴
                     SND_MEMORY | SND_LOOP | SND_ASYNC);

               // Let the sleepy user turn off the timer by slapping the 讓用戶自己用按鈕關閉響鈴,如果窗口最
               // space bar. If the window is minimized, it's restored; then it's小化,自動恢復;然後窗口置前;
               // brought to the forefront; then the pushbutton is enabled and並讓按鈕取得輸入焦點
               // given the input focus.

          EnableWindow (hwndDTP, FALSE) ; //不允許時間控件
          EnableWindow (hwndCheck, FALSE) ;  //不允許核取方塊
          EnableWindow (hwndPush, TRUE) ;  //允許按鈕

          hwndFocus = hwndPush ; //設置按鈕具有輸入焦點
          ShowWindow (hwnd, SW_RESTORE) ;  //恢復主窗口
          SetForegroundWindow (hwnd) ;  //將主窗口設置到前臺,並且激活該窗口
          return 0 ;

          // Clean up if the alarm is ringing or the timer is still set.清除響鈴或者計時器如果存在的話

     case WM_DESTROY: //處理註銷窗口消息
          free (pwaveform) ;  //釋放內存

          if (IsWindowEnabled (hwndPush)) //測試按鈕控件
               PlaySound (NULL, NULL, 0) ;

          if (SendMessage (hwndCheck, BM_GETCHECK, 0, 0)) //測試核取方塊
               KillTimer (hwnd, ID_TIMER) ;

          PostQuitMessage (0) ;  //發送退出消息
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;  //返回默認窗口過程
}

LRESULT CALLBACK SubProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) //子窗口控件回調函數
{
     int idNext, id = GetWindowLong (hwnd, GWL_ID) ; //獲取窗口控件ID
         
     switch (message)  //處理窗口控件消息
     {
     case WM_CHAR:  //處理字符消息
          if (wParam == '\t')  //處理按下Tab鍵消息
          {
               idNext = id ;

               do
                    idNext = (idNext +
                         (GetKeyState (VK_SHIFT) < 0 ? 2 : 1)) % 3 ;  //在三個窗口控件間切換
               while (!IsWindowEnabled (GetDlgItem (GetParent (hwnd), idNext)));  //當窗口控件允許時使idNext等於窗口控件ID              
              SetFocus (GetDlgItem (GetParent (hwnd), idNext)) ;  //使窗口控件具有輸入焦點
               return 0 ;
          }
          break ;

     case WM_SETFOCUS:  //設置輸入焦點消息
          hwndFocus = hwnd ;  //使輸入焦點句柄等於窗口控件句柄
          break ;
     }
     return CallWindowProc (SubbedProc [id], hwnd, message, wParam, lParam) ;  //返回默認子窗口控件回調函數
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章