//
***************************************************************************
// MAIN.CPP
//
// WinMain and WndProcΪԼڡ
//

#include "winmine.h"

// ȫֱ岿
HINSTANCE	g_hInst;
TCHAR		g_tszTitle[80];
TCHAR		g_tszAppName[80];
HWND		g_hwndMain;
HWND		g_hwndTimer;
HWND		g_hwndMines;
HWND		g_hwndMB;
HPEN		g_hpenBorder = NULL;
HPEN		g_hpenSelection = NULL;
HDC			g_hdcImage;
HBITMAP		g_hbmpBlocks = NULL;
int			g_iDefaults[3][3] = {{10, 8, 8}, {20, 10, 10}, {30, 12, 12}};
HighScores	g_hsScores[3];
int			g_iCurX = 0;
int			g_iCurY = 0;
int			g_iOffX;
int			g_iOffY;
int			g_iWindowWidth;
int			g_iWindowHeight;
RECT		g_rcBoard;
UINT		g_uiTimerID = 0;
HKEY		g_hkWinMine = NULL;
BOOL		g_bIgnoreTimer = TRUE;
GameData g_gd;

int WINAPI WinMain (
 HINSTANCE hInstance,
 HINSTANCE hPreviousInstance,
 LPWSTR lpCmdLine,
 int nShowCmd
 )
{
 MSG Msg;

// س
LoadString(hInstance, IDS_WINMINE_TITLE, g_tszTitle, ARRAY_LENGTH(g_tszTitle));
LoadString(hInstance, IDS_WINMINE_APPNAME, g_tszAppName, ARRAY_LENGTH(g_tszAppName));

// һȫmutex֤HelloSMS
   const HANDLE hMutex = CreateMutex(0, 0, TEXT("_WINMINE_EXE_MUTEX_"));

  // 
if(0 != hMutex)
      {
          // ?...
    if(ERROR_ALREADY_EXISTS != GetLastError())
    {
      // 洢hInstance
      g_hInst = hInstance;

        // ʼ

        if (FALSE == InitApplication())
            {
               return FALSE;
        }

// ʼ
if (FALSE == InitInstance(nShowCmd))
    {
        return FALSE;
}

// ʼϢpump
while (GetMessage(&Msg, NULL, 0,0) == TRUE)
  {
      TranslateMessage(&Msg);
      DispatchMessage(&Msg);
}

// 
if (FALSE == SaveSettings())
    {
        MessageBox(NULL, UseString(IDS_WINMINE_SAVEFAIL),
                     UseString(IDS_WINMINE_ERROR), MB_OK | MB_ICONERROR);
}

// бĶ
CleanUp();

VERIFY(CloseHandle(hMutex));
return Msg.wParam;
}

else
{
// һѾ-л˳
const HWND hWndExistingInstance = FindWindow(g_tszAppName, g_tszTitle);
HWND hwndRestore = GetLastActiveAppWindow(hWndExistingInstance);
VERIFY((0 == hwndRestore) || SetForegroundWindow(hwndRestore));
VERIFY(CloseHandle(hMutex));
    }
}

return TRUE;
}

BOOL InitInstance(
    int iShow
    )
{
g_hwndMain = CreateWindow(g_tszAppName, g_tszTitle, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hInst, NULL );

if (NULL == g_hwndMain)
    {
      return FALSE;
}
ShowWindow(g_hwndMain, iShow);
UpdateWindow(g_hwndMain);

return TRUE;
}

BOOL InitApplication()
{
 WNDCLASS wc;

 wc.style = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc = (WNDPROC) MainWndProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hIcon = NULL;
 wc.hInstance = g_hInst;
 wc.hCursor = NULL;
 wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
 wc.lpszMenuName = NULL;
 wc.lpszClassName = g_tszAppName;

 return RegisterClass(&wc);
}

LRESULT CALLBACK MainWndProc(
   HWND hWnd,
   UINT Msg,
   WPARAM wParam,
   LPARAM lParam
   )
{
    LRESULT lResult = TRUE;
LPCREATESTRUCT lpcs;

switch(Msg)
{
      case WM_CREATE:
            // ˵
if (FALSE == InitMenu(hWnd, IDR_WINMINE_MAINMENU))
    {
       MessageBox(hWnd, UseString(IDS_WINMINE_MENUFAIL), UseString(IDS_WINMINE_ERROR), MB_OK | MB_ICONERROR);
       return (-1);
}

// 洰Ⱥ͸߶
lpcs = (LPCREATESTRUCT) lParam;
g_iWindowWidth = lpcs->cx;
g_iWindowHeight = lpcs->cy;

// ʼȫϷ״̬
if (FALSE == InitGame(hWnd))
    {
        MessageBox(hWnd, UseString(IDS_WINMINE_INITFAIL),
                      UseString(IDS_WINMINE_ERROR), MB_OK | MB_ICONERROR);
        return (-1);
}

break;

case WM_COMMAND:
switch (wParam)
{
case IDM_WINMINE_QUIT:
// ˳ǰȡʱ(ڵĻ)
StopTimer();
SendMessage(hWnd, WM_CLOSE, 0, 0);
break;

case IDM_WINMINE_HELP:
DialogBox(g_hInst,
MAKEINTRESOURCE(IDD_WINMINE_HELP), hWnd, (DLGPROC) HelpDlgProc);
       break;



case IDM_WINMINE_SHOWHIGH:
                       DialogBox(g_hInst, MAKEINTRESOURCE(IDD_WINMINE_HIGH), hWnd, (DLGPROC) HighDlgProc);
                  break;

                case IDM_WINMINE_PREFS:
                       DialogBox(g_hInst, MAKEINTRESOURCE(IDD_WINMINE_PREFS), hWnd, (DLGPROC) PrefsDlgProc);
                       break;

                case IDM_WINMINE_BEGINNER:
                       g_gd.gtType = BEGINNER;
                       NewGame();
                       break;

                case IDM_WINMINE_INTERMEDIATE:
                       g_gd.gtType = INTERMEDIATE;
                       NewGame();
                       break;

                case IDM_WINMINE_EXPERT:
                       g_gd.gtType = EXPERT;
                       NewGame();
                       break;

                case IDM_WINMINE_NEWGAME:
                       NewGame();
                       break;

                case IDM_WINMINE_PAUSE:
                       MessageBox(hWnd, UseString(IDS_WINMINE_PAUSEMB), g_tszTitle, MB_OK | MB_ICONWARNING);
                       break;

                default:
                       lResult = DefWindowProc(hWnd, Msg, wParam, lParam);
        }
        break;

  case WM_KEYDOWN:
        switch (wParam)
          {



             case VK_RIGHT:
                    g_iCurX = (g_iCurX+1) % g_iDefaults[g_gd.gtType][INDEX_XBLOCKS];
                    break;

             case VK_LEFT:
                   if (--g_iCurX < 0)
                    {
                           g_iCurX = g_iDefaults[g_gd.gtType][INDEX_XBLOCKS] - 1;
                   }
                   break;

             case VK_DOWN:
                   g_iCurY = (g_iCurY+1) % g_iDefaults[g_gd.gtType][INDEX_YBLOCKS];
                   break;

             case VK_UP:
                   if (--g_iCurY < 0)
                   {
                           g_iCurY =
g_iDefaults[g_gd.gtType][INDEX_YBLOCKS] - 1;
                   }
                   break;

               default:
// Ǽͷ,ôһ
// һȷİ.ڶǳǲ
//л,ҪָаHAK...
    if (FALSE == HandleActionKeys(wParam))
     {
          lResult = DefWindowProc(hWnd, Msg, wParam, lParam);
    }
}

      // һЩ,
      InvalidateRect(g_hwndMain, &g_rcBoard, FALSE);
      break;

case WM_PAINT:
      DrawScreen();
      break;

case WM_DESTROY:
      PostQuitMessage(0);
      break;

case WM_TIMER:
      // Ӽʱ
      if ((g_gd.dwCurTime != 999) && (!g_bIgnoreTimer))
           {
               ++g_gd.dwCurTime;
               UpdateTimer();
      }
      break;

case WM_ACTIVATE:
      // κԭѡ,ֹͣʱ
      if (wParam)
          {
              g_bIgnoreTimer = FALSE;
      }
          else
      {
          g_bIgnoreTimer = TRUE;
      }
      break;

default:
      lResult = DefWindowProc(hWnd, Msg, wParam, lParam);
      break;
}

return (lResult);
}

BOOL HandleActionKeys(WPARAM wParam)
{
int iResult;

// Ƕֹͣ...
if (!((wParam == g_gd.dwKeyMakeMove) ||
         (wParam == g_gd.dwKeyMakeMark) ||
         (wParam == g_gd.dwKeyUncover)))
    {
      return FALSE;
}

// һϷ,...
if (g_gd.gsStatus == NEWGAME)
      {
      // ʱһϷ,Ϸֹͣ
      if (!StartGame())
            {
              MessageBox(g_hwndMain, UseString(IDS_WINMINE_STARTFAIL), UseString(IDS_WINMINE_ERROR), MB_OK | MB_ICONERROR);
              PostQuitMessage(0);
              // ǲϣƻϵͳ,˳˷ǲҪ
              return TRUE;
          }
    }

    // ûʾǰ
    if (wParam == g_gd.dwKeyMakeMove)
          {
            if (!MakeMove(g_iCurX, g_iCurY))
                  {
                    myPlaySound(SOUND_BOMB, SND_ASYNC | SND_NODEFAULT);
                    EndGame();
            }
    }

    // ûԱ/ȡǵǰ
    if (wParam == g_gd.dwKeyMakeMark)
         {
            if (!MakeMark())
                {
                    myPlaySound(SOUND_BOMB, SND_ASYNC | SND_NODEFAULT);
                    EndGame();
            }
    }

    // ûʾڵǰΧķ
    if (wParam == g_gd.dwKeyUncover)
          {
            if (!UncoverNeighbors())
                  {
                    myPlaySound(SOUND_BOMB, SND_ASYNC | SND_NODEFAULT);
                    EndGame();
            }
    }

    // ˲ʤ
    if (IsWinner())
    {
      // ֹͣʱ
      EndGame();

    // Ƿ߷,
    myPlaySound(SOUND_WIN, SND_ASYNC | SND_NODEFAULT);

    // ˲Ƿʱ䳬ǰõ
    if (IsHighScore())
        {
          iResult = DialogBox(g_hInst, MAKEINTRESOURCE(IDD_WINMINE_NEWHIGH), g_hwndMain, (DLGPROC) NewHighDlgProc);
    }
}

return TRUE;
}

BOOL InitMenu(
    HWND hWnd,
    UINT nToolBarId
    )
{
// ˵Ϣstruct
SHMENUBARINFO mbi;
ZeroMemory(&mbi, sizeof(SHMENUBARINFO));
mbi.cbSize = sizeof(SHMENUBARINFO);
mbi.hwndParent = hWnd;
mbi.nToolBarId = nToolBarId;
mbi.hInstRes = g_hInst;

if (FALSE == SHCreateMenuBar(&mbi))
    {
      return FALSE;
}

// һ䵽˵
  g_hwndMB = mbi.hwndMB;
  return TRUE;
}

LPCTSTR UseString(UINT uID)
{
 return (LPCTSTR) LoadString(g_hInst, uID, NULL, 0);
}

void CleanUp()
{
// ͷŸ߷ַ
for (int i = 0; i < 3; i++)
      {
        free(g_hsScores[i].szName);
}

// bitmapľ
if (g_hbmpBlocks)
      {
        DeleteObject(g_hbmpBlocks);
}

// pens
if (g_hpenBorder)
      {
        DeleteObject(g_hpenBorder);
}

if (g_hpenSelection)
      {
        DeleteObject(g_hpenSelection);
}

// ؼݵHDC
if (g_hdcImage)
      {
        DeleteDC(g_hdcImage);
}

// رעİ
if (g_hkWinMine)
      {
        RegCloseKey(g_hkWinMine);
 }

}

BOOL SaveSettings()
{
 // ʱԱregkey
 TCHAR tszTemp[10];

 // ߷
 for (int i = 0; i < 3; i++)
      {
      _sntprintf(tszTemp, ARRAY_LENGTH(tszTemp), TEXT("%s%d"), REGISTRY_VALUE_HIGHTIME, i);
      if (!SetRegDWORD(tszTemp, g_hsScores[i].dwTime))
          {
            return FALSE;
      }

      // ӵǼǻȡ
      _sntprintf(tszTemp, ARRAY_LENGTH(tszTemp), TEXT("%s%d"), REGISTRY_VALUE_HIGHNAME, i);
      if (FALSE == SetRegString(tszTemp, g_hsScores[i].szName))
           {
            return FALSE;
      }
}

// gamedata
if (FALSE == SetRegBinary(REGISTRY_VALUE_GAMEDATA, (PBYTE) &g_gd, sizeof(GameData)))
      {
      return FALSE;
}

return TRUE;
}

void UpdateMenus()
{
// ò˵ϵĺ˲־
TBBUTTONINFO tbbi;
tbbi.cbSize = sizeof(tbbi);
tbbi.dwMask = TBIF_LPARAM;
SendMessage(g_hwndMB, TB_GETBUTTONINFO, IDM_WINMINE_OPTIONS, (LPARAM)&tbbi);
HMENU hm = (HMENU)tbbi.lParam;

CheckMenuItem(hm, IDM_WINMINE_BEGINNER, (g_gd.gtType == BEGINNER) ? MF_CHECKED : MF_UNCHECKED); 
CheckMenuItem(hm, IDM_WINMINE_INTERMEDIATE, (g_gd.gtType == INTERMEDIATE) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hm, IDM_WINMINE_EXPERT, (g_gd.gtType == EXPERT) ? MF_CHECKED : MF_UNCHECKED);

// 
TBBUTTONINFO tbbiContext;
tbbiContext.cbSize = sizeof(tbbi);
tbbiContext.dwMask = TBIF_COMMAND | TBIF_TEXT;

// ϷϣϷ
// , ϣܹͣϷ
if (GAMEOVER == g_gd.gsStatus) {
      tbbiContext.idCommand = IDM_WINMINE_NEWGAME;
      tbbiContext.pszText = _tcsdup(UseString(IDS_WINMINE_NEWGAME));
      SendMessage(g_hwndMB, TB_SETBUTTONINFO, IDM_WINMINE_PAUSE, (LPARAM) &tbbiContext);
}

    else
    {
      tbbiContext.idCommand = IDM_WINMINE_PAUSE;
      tbbiContext.pszText = _tcsdup(UseString(IDS_WINMINE_PAUSE));
      SendMessage(g_hwndMB, TB_SETBUTTONINFO,
      IDM_WINMINE_NEWGAME, (LPARAM) &tbbiContext);
}

// 
free(tbbiContext.pszText);
}

HWND GetLastActiveAppWindow(HWND hwndMain)
{
    LASTACTIVEWINDOW law;

    law.hwndLastActive = NULL;
    law.dwMainWindowThread = GetWindowThreadProcessId(hwndMain, NULL);
    if (EnumWindows(GetLastActiveAppWindowEnum, (LPARAM)&law))
    {
        return law.hwndLastActive;
    }
    else
    {
        return NULL;
    }
}

BOOL CALLBACK GetLastActiveAppWindowEnum(HWND hWnd, LPARAM lParam)
{
    LASTACTIVEWINDOW *plaw;
    DWORD dwThread;
    plaw = (LASTACTIVEWINDOW *)lParam;
    dwThread = GetWindowThreadProcessId(hWnd, NULL);


    // Ѱͬ-߳, , !WS_EX_NOACTIVATE.
    // ÿapp's dialogs/messageboxesȡԼֻһ.
    if (dwThread == plaw->dwMainWindowThread &&
          IsWindowVisible(hWnd) &&
          IsWindowEnabled(hWnd) &&
          !(WS_EX_NOACTIVATE & GetWindowLong(hWnd, GWL_EXSTYLE))
        )
    {
        // ֻ
        plaw->hwndLastActive = hWnd;
        return FALSE;
    }

    // о
    return TRUE;
}
7.2.2  game.cpp ģ
ģִУҲǿϷĹ̡
//
***************************************************************************
// GAME.CPP
//

#include "winmine.h"

BOOL LoadScores()
{
// ʱԱregkey
TCHAR szTemp[10];
for (int i = 0; i < 3; i++)
    {
      _sntprintf(szTemp, ARRAY_LENGTH(szTemp), TEXT("%s%d"), REGISTRY_VALUE_HIGHTIME, i);
      if (FALSE == GetRegDWORD(szTemp, &g_hsScores[i].dwTime))
           {
              return FALSE;
      }

      // Դregistryȡ
      _sntprintf(szTemp, ARRAY_LENGTH(szTemp), TEXT("%s%d"), REGISTRY_VALUE_HIGHNAME, i);
      if (FALSE == GetRegString(szTemp, &g_hsScores[i].szName))
           {
              return FALSE;
      }

      // ʱ䲻ȷΪĬ
      if (0 == g_hsScores[i].dwTime)
          {
            g_hsScores[i].dwTime = 999;
            g_hsScores[i].szName = _tcsdup(TEXT("Anonymous"));
      }
  }

  return TRUE;
}

void NewGame()
{
// Ϸ״̬
g_gd.gsStatus = NEWGAME;

// Ϸ
for (int i = 0; i < ARRAY_WIDTH; i++)
     {
       for (int j = 0; j < ARRAY_WIDTH; j++)
            {
              g_gd.cBoard[i][j] = INVALID_ENTRY;
      }
}

// ù
g_iCurX = 0;
g_iCurY = 0;

// ķ֧
g_iOffX = (g_iWindowWidth -
(g_iDefaults[g_gd.gtType][INDEX_XBLOCKS] * IMAGE_SIZE)) / 2;
g_iOffY = ((g_iWindowHeight - LABEL_HEIGHT) - (g_iDefaults[g_gd.gtType][INDEX_YBLOCKS] * IMAGE_SIZE)) / 2;

// board + a 1 ر߽ķΧ
g_rcBoard.left = g_iOffX - 1;
g_rcBoard.right = g_rcBoard.left +
(g_iDefaults[g_gd.gtType][INDEX_XBLOCKS] * IMAGE_SIZE) + 2;
g_rcBoard.top = g_iOffY - 1;
g_rcBoard.bottom = g_rcBoard.top +
(g_iDefaults[g_gd.gtType][INDEX_YBLOCKS] * IMAGE_SIZE) + 2;

//  block & flag 
g_gd.iBlocksLeft = g_iDefaults[g_gd.gtType][INDEX_XBLOCKS] *
g_iDefaults[g_gd.gtType][INDEX_YBLOCKS];
g_gd.iFlagsLeft = g_iDefaults[g_gd.gtType][INDEX_MINES];

// ֹͣʱ, 
StopTimer();
g_gd.dwCurTime = 0;
UpdateTimer();

// ¼
UpdateMines();
// ²˵(,Ч)
UpdateMenus();

  // ϶Ļ
  InvalidateRect(g_hwndMain, NULL, TRUE);
  }

  BOOL ResumeGame(
      HWND hwnd
      )
{
// ڲ̫ܵûϷ֮޸Ŀִ״̬
// λõĴ뱻

// ķ֧
g_iOffX = (g_iWindowWidth -
(g_iDefaults[g_gd.gtType][INDEX_XBLOCKS] * IMAGE_SIZE)) / 2;
g_iOffY = ((g_iWindowHeight - LABEL_HEIGHT) -
(g_iDefaults[g_gd.gtType][INDEX_YBLOCKS] * IMAGE_SIZE)) / 2;

// board + a 1 رԵԾ
g_rcBoard.left = g_iOffX - 1;
g_rcBoard.right = g_rcBoard.left +
(g_iDefaults[g_gd.gtType][INDEX_XBLOCKS] * IMAGE_SIZE) + 2;
g_rcBoard.top = g_iOffY - 1;
g_rcBoard.bottom = g_rcBoard.top +
(g_iDefaults[g_gd.gtType][INDEX_YBLOCKS] * IMAGE_SIZE) + 2;

// ʱ
if (!(g_uiTimerID = SetTimer(hwnd, IDR_WINMINE_TIMER, 1000, NULL)))
{
return FALSE;
  }

// ʾ
UpdateMines();
UpdateTimer();
UpdateMenus();
return TRUE;
}

BOOL StartGame()
{
 int iMinesLeft;
 int x, y;
 char cType;

// mines
iMinesLeft = g_iDefaults[g_gd.gtType][INDEX_MINES];
do
    {
      do
        {
            x = rand() % g_iDefaults[g_gd.gtType][INDEX_XBLOCKS];
            y = rand() % g_iDefaults[g_gd.gtType][INDEX_XBLOCKS];
      } while (IsMine(x, y) || ((x == g_iCurX) && (y == g_iCurY)));
      SETBLOCK(x, y, STATE_COVERED | TYPE_MINE);
} while(--iMinesLeft);

// Ԥȼֵ
for (y = 0; y < g_iDefaults[g_gd.gtType][INDEX_YBLOCKS]; y++)
    {
      for (x = 0; x < g_iDefaults[g_gd.gtType][INDEX_XBLOCKS]; x++)
          {
            // ʣblocks
            if (!IsMine(x,y))
               {
                   cType = 0;
                   if (IsMine(x-1, y-1)) ++cType;
                   if (IsMine(x-1, y)) ++cType;
                   if (IsMine(x-1, y+1)) ++cType;
                   if (IsMine(x, y-1)) ++cType;
                   if (IsMine(x, y+1)) ++cType;
                   if (IsMine(x+1, y-1)) ++cType;
                   if (IsMine(x+1, y)) ++cType;
                   if (IsMine(x+1, y+1)) ++cType;
                   SETBLOCK(x, y, STATE_COVERED | cType);
            }
       }
}


// Ϸ״̬
g_gd.gsStatus = PLAYING;

// ʱ
    g_uiTimerID = SetTimer(g_hwndMain, IDR_WINMINE_TIMER, 1000, NULL);
  if (0 == g_uiTimerID)
        {
          return FALSE;
  }
  g_gd.dwCurTime = 0;

  return TRUE;
}

BOOL MakeMove(int ix, int iy)
{
  BOOL bRetVal = TRUE;

// Ϸ״̬ƶ
switch (g_gd.gsStatus) {
    case NEWGAME:
          // Ӧڱ⴦ C  false
          return FALSE;

    case PLAYING:
          // ˲ѱѡblock ״̬
          switch (BLOCKSTATE(ix, iy)) {
               case STATE_COVERED:
               case STATE_QUESTION:
                     // in both these cases we uncover the block
                     SETSTATE(ix, iy, STATE_UNCOVERED);
                     --g_gd.iBlocksLeft;

                     // ˲ block 
                    switch (BLOCKTYPE(ix, iy))
                     {
                         case TYPE_BLANK:
                               // ڸݽ, дֵ
                               if (!MakeMove(ix-1, iy-1)) bRetVal = FALSE;
                               if (!MakeMove(ix-1, iy)) bRetVal = FALSE;
                               if (!MakeMove(ix-1, iy+1)) bRetVal = FALSE;
                               if (!MakeMove(ix, iy-1)) bRetVal = FALSE;
                               if (!MakeMove(ix, iy+1)) bRetVal = FALSE;
                               if (!MakeMove(ix+1, iy-1)) bRetVal = FALSE;
                               if (!MakeMove(ix+1, iy)) bRetVal = FALSE;
                               if (!MakeMove(ix+1, iy+1)) bRetVal = FALSE;
                               break;

                        case TYPE_MINE:
                              // false
                              bRetVal = FALSE;
                              break;

                        default:
                              // ޵ķ,ֻ
                              break;
                    }
                    break;

             case STATE_MARKED:
             case STATE_UNCOVERED:
                    // ʲô
                    break;
          }
          break;

  case GAMEOVER:
       //ʲô
        break;
  } 

  return bRetVal;
}

BOOL MakeMark()
{
  // ǲݵǰϷ/ block ״̬
  switch (g_gd.gsStatus)
       {
        case NEWGAME:
              // Ӧڱ⴦ C ش
              return FALSE;

        case PLAYING:
               // ˲ѱѡblock״̬
               switch (BLOCKSTATE(g_iCurX, g_iCurY)) {
                    case STATE_COVERED:
                           SETSTATE(g_iCurX, g_iCurY, STATE_MARKED);
                           --g_gd.iBlocksLeft;
                           --g_gd.iFlagsLeft;
                           break;

                    case STATE_QUESTION:
                          SETSTATE(g_iCurX, g_iCurY, STATE_COVERED);
                          break;

                    case STATE_MARKED:
                          SETSTATE(g_iCurX, g_iCurY, STATE_QUESTION);
                          ++g_gd.iBlocksLeft;
                          ++g_gd.iFlagsLeft;
                          break;

                    case STATE_UNCOVERED:
                          // ʲô
                          break;
                }
                break;

                    case GAMEOVER:
                          // ʲô
                          break;
             }

  UpdateMines();

  return TRUE;
}

BOOL UncoverNeighbors()
{
int iBlockVal, iNumBombs = 0;
BOOL bRetVal = TRUE;

// ֻصϽ
if (STATE_UNCOVERED != BLOCKSTATE(g_iCurX, g_iCurY))
      {
        return TRUE;
}

// ֻڼķϽ
if (!(iBlockVal = BLOCKTYPE(g_iCurX, g_iCurY)))
       {
         return TRUE;
}

// ˲
if (TYPE_MINE == iBlockVal)
     {
        return FALSE;
}

// ˲ը
if (BLOCKSTATE(g_iCurX-1, g_iCurY-1) == STATE_MARKED) ++iNumBombs;
if (BLOCKSTATE(g_iCurX-1, g_iCurY) == STATE_MARKED) ++iNumBombs;
if (BLOCKSTATE(g_iCurX-1, g_iCurY+1) == STATE_MARKED) ++iNumBombs;
if (BLOCKSTATE(g_iCurX, g_iCurY-1) == STATE_MARKED) ++iNumBombs;
if (BLOCKSTATE(g_iCurX, g_iCurY+1) == STATE_MARKED) ++iNumBombs;
if (BLOCKSTATE(g_iCurX+1, g_iCurY-1) == STATE_MARKED) ++iNumBombs;
if (BLOCKSTATE(g_iCurX+1, g_iCurY) == STATE_MARKED) ++iNumBombs;
if (BLOCKSTATE(g_iCurX+1, g_iCurY+1) == STATE_MARKED) ++iNumBombs;

// if iNumBombs != iBlockVal, ignore command
if (iBlockVal != iNumBombs)
       {
       return TRUE;
}

// recurse
if (!MakeMove(g_iCurX-1, g_iCurY-1)) bRetVal = FALSE;
if (!MakeMove(g_iCurX-1, g_iCurY)) bRetVal = FALSE;
if (!MakeMove(g_iCurX-1, g_iCurY+1)) bRetVal = FALSE;
if (!MakeMove(g_iCurX, g_iCurY-1)) bRetVal = FALSE;
if (!MakeMove(g_iCurX, g_iCurY+1)) bRetVal = FALSE;
if (!MakeMove(g_iCurX+1, g_iCurY-1)) bRetVal = FALSE;
if (!MakeMove(g_iCurX+1, g_iCurY)) bRetVal = FALSE;
if (!MakeMove(g_iCurX+1, g_iCurY+1)) bRetVal = FALSE;

return bRetVal;
}

BOOL InitGame(HWND hwnd)
{
  DWORD dwDisposition;
  int iResult;
  // ϶ؼ
  if (!AddControls(hwnd))
        {
         RETAILMSG(1, (TEXT("InitGame: unable to draw the controls\n")));
          return FALSE;
}

// ȡо
if (!GetHandles(hwnd))
     {
      RETAILMSG(1, (TEXT("InitGame: unable to get all the handles\n")));
       return FALSE;
}

// עᰴ
if (!InitRegistry(&dwDisposition))
      {
       RETAILMSG(1, (TEXT("InitGame: unable to open the registry key\n")));
       return FALSE;
}

// ظ߷
if (!LoadScores())
      {
       RETAILMSG(1, (TEXT("InitGame: unable to load the high scores\n")));
        return FALSE;
}

// ʼGameData ܹ
if (!InitGameData())
      {
      RETAILMSG(1, (TEXT("InitGame: unable to initialize the GameData structure\n")));
      return FALSE;
}

// һϷ
srand(GetTickCount());

// Ϸ,ָ
if (PLAYING == g_gd.gsStatus)
     {
      // ԻָϷ
      iResult = MessageBox(hwnd, UseString(IDS_WINMINE_RESUME),
               g_tszTitle, MB_YESNO | MB_ICONQUESTION);
      if (IDYES == iResult) {
            if (FALSE == ResumeGame(hwnd))
                {
                   return FALSE;
            }
       }
          else
          {
             NewGame();
      }
  }
    else
    {
      NewGame();
  }

  return TRUE;
}

BOOL InitGameData()
{
// עûϷ,g_gdΪĬ
if (!GetRegBinary(REGISTRY_VALUE_GAMEDATA, (PBYTE) &g_gd, sizeof(GameData)))
    {
      // Ĭ
      g_gd.dwCurTime = 0;
      g_gd.gsStatus = NEWGAME;
      g_gd.gtType = BEGINNER;
      g_gd.dwKeyMakeMark = DEFAULT_KEY_MAKEMARK;
      g_gd.dwKeyMakeMove = DEFAULT_KEY_MAKEMOVE;
      g_gd.dwKeyUncover = DEFAULT_KEY_UNCOVER;
      g_gd.bSounds = TRUE;
  }

  return TRUE;
}

void EndGame()
{
  g_gd.gsStatus = GAMEOVER;
  StopTimer();
  UpdateMenus();
}

void StopTimer()
{
if (g_uiTimerID)
      {
        if (FALSE == KillTimer(g_hwndMain, IDR_WINMINE_TIMER))
              {
                 MessageBox(g_hwndMain, UseString(IDS_WINMINE_BADTIMER), UseString(IDS_WINMINE_ERROR), MB_OK | MB_ICONERROR);
      }
      g_uiTimerID = 0;
  }
}

void UpdateTimer()
{
 TCHAR tszCurTime[5];

 _sntprintf(tszCurTime, ARRAY_LENGTH(tszCurTime), TEXT("%d"), g_gd.dwCurTime);
 SendMessage(g_hwndTimer, WM_SETTEXT, 0, (LPARAM) tszCurTime);
}

  void UpdateMines()
  {
   TCHAR tszMinesLeft[4];
  _sntprintf(tszMinesLeft, ARRAY_LENGTH(tszMinesLeft), TEXT("%d"), g_gd.iFlagsLeft);
   SendMessage(g_hwndMines, WM_SETTEXT, 0, (LPARAM) tszMinesLeft);
  }

  BOOL IsMine(
      int ix,
      int iy
      )
  {
  return (TYPE_MINE == BLOCKTYPE(ix, iy));
}

BOOL IsWinner()
{
  return ((PLAYING == g_gd.gsStatus) && (0 == g_gd.iBlocksLeft) && (0 == g_gd.iFlagsLeft));
}

BOOL IsHighScore()
{
 return (g_gd.dwCurTime < g_hsScores[g_gd.gtType].dwTime);
}

BOOL myPlaySound(
    LPCTSTR lpctszSoundName,
    UINT uiSound
    )
{
if (g_gd.bSounds)
      {
        return sndPlaySound(lpctszSoundName, uiSound);
    }
    else
    {
      return TRUE;
  }
}
7.2.3  graphics.cppģ
ģҪǻͼΡ
//
***************************************************************************
// GRAPHICS.CPP
//
//

#include "winmine.h"
void DrawScreen()
{
HDC hdc;
PAINTSTRUCT ps;
RECT rc;

if ((hdc = BeginPaint(g_hwndMain, &ps)))
      {
        DrawBoard(hdc);
        DrawRectangle(hdc, g_hpenBorder, &g_rcBoard);

        // ϷҪ϶ѡ
        if (g_gd.gsStatus != GAMEOVER)
              {
                // ѡӦȥδ
                // Ӧһϲͨblock λõ
         rc.top = SCREENY(g_iCurY, g_iOffY);
         rc.left = SCREENX(g_iCurX, g_iOffX);
         rc.bottom = rc.top + IMAGE_SIZE;
         rc.right = rc.left + IMAGE_SIZE;
         DrawRectangle(hdc, g_hpenSelection, &rc);
     }

     EndPaint(g_hwndMain, &ps);
 }
}

void DrawBoard(HDC hdc)
{
int iImg, x, y;

// ڴƻ»ȡһ
VERIFY(SelectObject(g_hdcImage, g_hbmpBlocks));

switch (g_gd.gsStatus)
    {
      case NEWGAME:
            for (y = 0; y < g_iDefaults[g_gd.gtType][INDEX_YBLOCKS]; y++)
              {
                 for (x = 0; x < g_iDefaults[g_gd.gtType][INDEX_XBLOCKS]; x++)
                 {
                     BitBlt(hdc, SCREENX(x, g_iOffX), SCREENY(y, g_iOffY), IMAGE_SIZE,
                         IMAGE_SIZE, g_hdcImage, 0, IMGY(IMAGE_COVERED), SRCCOPY);
                 }
            }
            break;

        case PLAYING:
            for (y = 0; y < g_iDefaults[g_gd.gtType][INDEX_YBLOCKS]; y++)
              {
                  for (x = 0; x < g_iDefaults[g_gd.gtType][INDEX_XBLOCKS]; x++)
              {
                switch (BLOCKSTATE(x, y)) {
                    case STATE_COVERED:
                          iImg = IMAGE_COVERED;
                          break;

                    case STATE_UNCOVERED:
                          iImg = BLOCKTYPE(x, y);
                          break;

                    case STATE_MARKED:
                          iImg = IMAGE_MARKED;
                          break;

                    case STATE_QUESTION:
                          iImg = IMAGE_QUESTION;
                          break;
                }

                // ֪ͼƬ, ը
                BitBlt(hdc, SCREENX(x, g_iOffX), SCREENY(y, g_iOffY), IMAGE_SIZE, IMAGE_SIZE, g_hdcImage, 0, IMGY(iImg), SRCCOPY);
            }
        }
        break;

    case GAMEOVER:
        for (y = 0; y < g_iDefaults[g_gd.gtType][INDEX_YBLOCKS]; y++)
          {
              for (x = 0; x < g_iDefaults[g_gd.gtType][INDEX_XBLOCKS]; x++)
                {
                    switch (BLOCKSTATE(x, y))
                    {
                        case STATE_COVERED:
                              if (IsMine(x, y))
                              {
                                  iImg = IMAGE_BOMB;
                              }
                              else
                              {
                                  iImg = IMAGE_COVERED;
                              }
                              break;

                        case STATE_UNCOVERED:
                              if (IsMine(x, y))
                              {
                                  iImg = IMAGE_REDBOMD;
                              }
                              else
                              {
                                  iImg = BLOCKTYPE(x, y);
                              }
                              break;

                        case STATE_MARKED:
                              if (IsMine(x, y))
                              {
                                    iImg = IMAGE_MARKED;
                              }
                              else
                              {
                                    iImg = IMAGE_WRONGBOMB;
                              }
                              break;

                        case STATE_QUESTION:
                              if (IsMine(x, y))
                              {
                                    iImg = IMAGE_BOMB;
                              }
                              else
                              {
                                    iImg = IMAGE_QUESTION;
                              }
                              break;

                      }
                      // ֪ͼƬ,ը
                        BitBlt(hdc, SCREENX(x, g_iOffX), SCREENY(y, g_iOffY), IMAGE_SIZE, IMAGE_SIZE, g_hdcImage, 0, IMGY(iImg), SRCCOPY);
                  }
            }
            break;
  }
}

void DrawRectangle(
      HDC hdc,
      HPEN hPen,
      LPRECT rc
      )
{
  HGDIOBJ hPenOld;
  HGDIOBJ hbrOld;

// ѡʺNULLʵhdc
hPenOld = SelectObject(hdc, hPen);
hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));

// ϵ߽緽
Rectangle(hdc, rc->left, rc->top, rc->right, rc->bottom);

// ͼ
  SelectObject(hdc, hPenOld);
  SelectObject(hdc, hbrOld);
}

  HPEN MyCreatePen(
      UINT uiStyle,
      UINT uiWidth,
      COLORREF crColor
      )
  {
  LOGPEN lp;
  POINT pt;

  // Ϣ
  pt.x = uiWidth;
  pt.y = 0;
  lp.lopnStyle = uiStyle;
  lp.lopnWidth = pt;
  lp.lopnColor = crColor;

  return CreatePenIndirect(&lp);
}

BOOL AddControls(
    HWND hwnd
    )
{
HDC hdc;
SIZE sTemp;
LPTSTR tszMaxNum = TEXT("999");
int ixOff, iyOff, iHeight, iMinesWidth, iTimeWidth, iNumWidth, ixTimeOff;

// ı
if (!(hdc = GetDC(hwnd)))
     {
        return FALSE;
}

// ȡַ"Mines:"Ŀ
if (!GetTextExtentPoint32(hdc, UseString(IDS_WINMINE_MINES),
       _tcslen(UseString(IDS_WINMINE_MINES)), &sTemp))
      {
        ReleaseDC(hwnd, hdc);
        return FALSE;
}
iMinesWidth = sTemp.cx;

// ȡַ"Time:"Ŀ
if (!GetTextExtentPoint32(hdc, UseString(IDS_WINMINE_TIME),
     _tcslen(UseString(IDS_WINMINE_TIME)), &sTemp))

       {
        ReleaseDC(hwnd, hdc);
        return FALSE;
}
iTimeWidth = sTemp.cx;

// ȡ(999)ַĿ
// hack:1ΪһЩֱɾ...
if (!GetTextExtentPoint32(hdc, tszMaxNum, _tcslen(tszMaxNum), &sTemp))
      {
        ReleaseDC(hwnd, hdc);
        return FALSE;
}
iNumWidth = sTemp.cx + 1;

ReleaseDC(hwnd, hdc);

// ߶ֻLABEL_HEIGHTȥѡ
// һ1ر߽
iHeight = LABEL_HEIGHT - 2;

// yOffset is LABEL_HEIGHTȥѡؽ
//һ 1 ر߽
iyOff = g_iWindowHeight - LABEL_HEIGHT + 2;

// xOffsetߵ
ixOff = (g_iWindowWidth - (IMAGE_SIZE * MAX_BOARDSIZE)) / 2;

// ixTimeOffұߵ, ȥ
// (iTimeWidth + iNumWidth)
ixTimeOff = (g_iWindowWidth - (ixOff)) - (iTimeWidth + iNumWidth);
// "Mines"ǩ
if (NULL == CreateWindow(TEXT("STATIC"), UseString(IDS_WINMINE_MINES), WS_CHILD | WS_VISIBLE | SS_LEFT, ixOff, iyOff, iMinesWidth, iHeight, hwnd, (HMENU) IDC_STATIC, g_hInst, NULL))
    {
      return FALSE;
};

// mine countıǩ
g_hwndMines = CreateWindow(TEXT("STATIC"), NULL, WS_CHILD | WS_VISIBLE | SS_LEFT, ixOff + iMinesWidth, iyOff, iNumWidth, iHeight, hwnd, (HMENU)IDC_STATIC, g_hInst, NULL);
if (NULL == g_hwndMines)
    {
      return FALSE;
}

//  "Time:"ǩ
if (!CreateWindow(TEXT("STATIC"), UseString(IDS_WINMINE_TIME), WS_CHILD | WS_VISIBLE | SS_LEFT, ixTimeOff, iyOff, iTimeWidth, iHeight, hwnd, (HMENU) IDC_STATIC, g_hInst, NULL))
    {
      return FALSE;
};

// ʱıǩ
g_hwndTimer = CreateWindow(TEXT("STATIC"), NULL, WS_CHILD | WS_VISIBLE | SS_LEFT, ixTimeOff + iTimeWidth, iyOff, iNumWidth, iHeight, hwnd, (HMENU) IDC_STATIC, g_hInst, NULL);
  if (NULL == g_hwndTimer)
       {
         return FALSE;
  }

  return TRUE;
}

BOOL GetHandles(
    HWND hwnd
    )
{
  HDC hdc;

// ȡλͼϵľ
    g_hbmpBlocks = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDR_WINMINE_BLOCKS));
if (NULL == g_hbmpBlocks)
      {
        return FALSE;
}

// ȡHDC
    hdc = GetDC(hwnd);
if (NULL == hdc)
      {
        return FALSE;
}
g_hdcImage = CreateCompatibleDC(hdc);
ReleaseDC(hwnd, hdc);
if (NULL == g_hdcImage)
      {
        return FALSE;
}

// 
g_hpenBorder = MyCreatePen(PS_SOLID, 1, COLOR_BORDER);
g_hpenSelection = MyCreatePen(PS_SOLID, 2, COLOR_SELECTION);
if ((NULL == g_hpenBorder) || (NULL == g_hpenSelection))
      {
        return FALSE;
 }

 return TRUE;


