home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / internet / scripting / spruuids / app.cpp next >
Encoding:
C/C++ Source or Header  |  1997-08-18  |  32.1 KB  |  1,253 lines

  1. //---------------------------------------------------------------------------
  2. // App.cpp
  3. //---------------------------------------------------------------------------
  4. // Shell for sample spr program
  5. //---------------------------------------------------------------------------
  6. // (C) Copyright 1992-1997 by Microsoft Corporation.  All rights reserved.
  7. //
  8. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
  9. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  10. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
  11. // PARTICULAR PURPOSE.
  12. //---------------------------------------------------------------------------
  13.  
  14. #include "Main.h"
  15. #pragma hdrstop
  16. #include "App.h"
  17. #include "MsgLoop.h"
  18. #include "Game.h"
  19. #include <stdio.h>
  20.  
  21.  
  22. //---------------------------------------------------------------------------
  23. // DEBUG info
  24. //---------------------------------------------------------------------------
  25. SZTHISFILE
  26.  
  27.  
  28. //---------------------------------------------------------------------------
  29. // Prototypes
  30. //---------------------------------------------------------------------------
  31. BOOL CALLBACK AppDlgProc(  HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
  32. BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
  33. LONG CALLBACK PSWndProc(   HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
  34.  
  35.  
  36. //---------------------------------------------------------------------------
  37. // Global Variables
  38. //---------------------------------------------------------------------------
  39. HINSTANCE g_hinst             = NULL;
  40. ITypeLib *g_ptlMain           = NULL;   // Cache of TypeLib
  41. CApp     *g_papp              = NULL;
  42. IUnknown *g_punkApplicationNA = NULL;   // Not AddRef()'d
  43. char     *g_pszCodeFile       = NULL;
  44. char     *g_pszRecFile        = NULL;
  45. FILE     *g_pfileRec          = NULL;
  46. int       g_mode              = MODE_NORMAL;
  47. CMGRRINFO App_crinfo =
  48.   {
  49.   sizeof(CMGRRINFO),      // size of CMGRRINFO structure in bytes.
  50.   0,                      // Don't need idle time
  51.   cmgrrfPreTranslateAll,  // Need pretranslate
  52.   cmgradvfModal           // Need modal notifications
  53.   };
  54. HRESULT CApp::s_hr = E_FAIL;
  55.  
  56.  
  57. //---------------------------------------------------------------------------
  58. // Helpers for little vs. bit endian
  59. //---------------------------------------------------------------------------
  60.  
  61. #undef BIGENDIAN // change for big-endian systems
  62.  
  63. typedef union
  64.   {
  65.   DWORD i4;
  66.   struct
  67.     {
  68.     char b1;
  69.     char b2;
  70.     char b3;
  71.     char b4;
  72.     };
  73.   } I4_SW;
  74.  
  75. #ifndef BIGENDIAN
  76.   #define NORMALIZE_I4(i4)  (i4)
  77. #else
  78.   #define NORMALIZE_I4(i4) \
  79.     {                      \
  80.     I4_SW l=i4;            \
  81.     (i4).b1 = l.b4;        \
  82.     (i4).b2 = l.b3;        \
  83.     (i4).b3 = l.b2;        \
  84.     (i4).b4 = l.b1;        \
  85.     }
  86. #endif
  87.  
  88. typedef struct
  89.   {
  90.   char   win;
  91.   char   msg;
  92.   I4_SW  wp;
  93.   I4_SW  lp;
  94.   } REC;
  95.  
  96.  
  97. //---------------------------------------------------------------------------
  98. // Write out one message.
  99. //---------------------------------------------------------------------------
  100. #define RECORD(win, msg, wp, lp)    {if (g_mode == MODE_RECORD) Record(win,msg,wp,lp);}
  101. #define WIN_DLG   ((char)0xdd)  // Dlg
  102. #define WIN_PS    ((char)0xee)  // playsurfacE
  103. #define WIN_ABOUT ((char)0xaa)  // About
  104.   
  105. void Record
  106. (
  107.   char   win,
  108.   UINT   msg,
  109.   WPARAM wp,
  110.   LPARAM lp
  111. )
  112. {
  113.   REC rec;
  114.  
  115.   if (!g_pfileRec)
  116.     {
  117.     g_pfileRec = fopen(g_pszRecFile, "wb");
  118.     if (!g_pfileRec)
  119.       {
  120.       MessageBox(NULL, "Could not open record file", "Spruuids", MB_OK | MB_ICONEXCLAMATION);
  121.       exit(1);
  122.       }
  123.     }
  124.  
  125.   switch (msg)
  126.     {
  127.     default:
  128.       return;
  129.  
  130.     case WM_COMMAND:
  131.       msg = 1;
  132.       break;
  133.     case WM_SYSCOMMAND:
  134.       msg = 2;
  135.       break;
  136.     case WM_TIMER:
  137.       msg = 3;
  138.       break;
  139.     case WM_CHAR:
  140.       msg = 4;
  141.       break;
  142.     case WM_KEYDOWN:
  143.       msg = 5;
  144.       break;
  145.     case WM_KEYUP:
  146.       msg = 6;
  147.       break;
  148.     case WM_MOUSEMOVE:
  149.       msg = 7;
  150.       break;
  151.     case WM_LBUTTONUP:
  152.       msg = 8;
  153.       break;
  154.     case WM_RBUTTONUP:
  155.       msg = 9;
  156.       break;
  157.     case WM_MBUTTONUP:
  158.       msg = 10;
  159.       break;
  160.     case WM_LBUTTONDOWN:
  161.       msg = 11;
  162.       break;
  163.     case WM_RBUTTONDOWN:
  164.       msg = 12;
  165.       break;
  166.     case WM_MBUTTONDOWN:
  167.       msg = 13;
  168.       break;
  169.     }
  170.  
  171.   rec.win = win;
  172.   rec.msg = (char)msg;
  173.   rec.wp.i4 = wp;
  174.   NORMALIZE_I4(rec.wp);    // Handle byte-swapping for little vs. big endian.
  175.   rec.lp.i4 = lp;
  176.   NORMALIZE_I4(rec.lp);    // Handle byte-swapping for little vs. big endian.
  177.   fwrite(&rec, sizeof(rec), 1, g_pfileRec);
  178. }
  179.  
  180.  
  181. //---------------------------------------------------------------------------
  182. //
  183. //---------------------------------------------------------------------------
  184. HRESULT CApp::Playback
  185. (
  186.   void
  187. )
  188. {
  189.   REC    rec;
  190.   HWND   hwnd;
  191.   UINT   msg;
  192.  
  193.   if (!g_pfileRec)
  194.     {
  195.     g_pfileRec = fopen(g_pszRecFile, "rb");
  196.     if (!g_pfileRec)
  197.       {
  198.       MessageBox(NULL, "Could not open playback file", "Spruuids", MB_OK | MB_ICONEXCLAMATION);
  199.       return E_FAIL;
  200.       }
  201.     }
  202.  
  203.   while (TRUE)
  204.     {
  205.     size_t cch = fread(&rec, sizeof(rec), 1, g_pfileRec);
  206.     if (cch != 1)
  207.       {
  208.       if (feof(g_pfileRec))
  209.         {
  210.         fclose(g_pfileRec);
  211.         g_pfileRec = NULL;
  212.         g_mode = MODE_NORMAL;
  213.         m_fQuit = TRUE;
  214.         return S_OK;
  215.         }
  216.       MessageBox(NULL, "Unexpected read error in playback file", "Spruuids", MB_OK | MB_ICONEXCLAMATION);
  217.       return E_FAIL;
  218.       }
  219.  
  220.     switch (rec.win)
  221.       {
  222.       case WIN_DLG:
  223.         hwnd = m_hwndDlg;
  224.         break;
  225.  
  226.       case WIN_PS:
  227.         hwnd = m_hwndPS;
  228.         break;
  229.  
  230.       case WIN_ABOUT:
  231.         hwnd = m_hwndAbout;
  232.         break;
  233.       }
  234.  
  235.     UINT mpimsg[] = {0, WM_COMMAND, WM_SYSCOMMAND, WM_TIMER, WM_CHAR, WM_KEYDOWN, WM_KEYUP,
  236.                         WM_MOUSEMOVE, WM_LBUTTONUP, WM_RBUTTONUP, WM_MBUTTONUP, WM_LBUTTONDOWN,
  237.                         WM_RBUTTONDOWN, WM_MBUTTONDOWN};
  238.     if (rec.msg <= 0 || rec.msg >= sizeof(mpimsg)/sizeof(mpimsg[0]))
  239.       {
  240.       MessageBox(NULL, "Bad msg # in playback file", "Spruuids", MB_OK | MB_ICONEXCLAMATION);
  241.       return E_FAIL;
  242.       }
  243.     msg = mpimsg[rec.msg];
  244.     NORMALIZE_I4(rec.wp);    // Handle byte-swapping for little vs. big endian.
  245.     NORMALIZE_I4(rec.lp);    // Handle byte-swapping for little vs. big endian.
  246.  
  247.     SendMessage(hwnd, msg, (WPARAM)rec.wp.i4, (LPARAM)rec.lp.i4);
  248.     if (!m_pmsgloop->FPushMessageLoop(g_papp->m_idcomp, cmgrloopDoEvents, NULL))
  249.       return E_FAIL;
  250.     }
  251.  
  252.   return S_OK;
  253. }
  254.  
  255.  
  256. //---------------------------------------------------------------------------
  257. // Helper to parse command-line parameters
  258. //---------------------------------------------------------------------------
  259. HRESULT ParseCmdLine
  260. (
  261.   char *pszCmdLine
  262. )
  263. {
  264.   if (!pszCmdLine)
  265.     goto DoError;
  266.  
  267.   if (pszCmdLine[0] == '/')
  268.     {
  269.     if (pszCmdLine[1] == 'P')
  270.       {
  271.       g_mode = MODE_PLAYBACK;
  272.       goto GetFile;
  273.       }
  274.     else if (pszCmdLine[1] == 'R')
  275.       {
  276.       g_mode = MODE_RECORD;
  277. GetFile:
  278.       if (pszCmdLine[2] <= ' ')
  279.         goto DoError;
  280.       pszCmdLine += 2;
  281.       g_pszRecFile = pszCmdLine;
  282.       while (*pszCmdLine > ' ')   // Skip non-white space
  283.         pszCmdLine++;
  284.       if (!*pszCmdLine)   // End Of String
  285.         goto DoError;     // Needed <fileCode>
  286.       *pszCmdLine = 0;
  287.       pszCmdLine++;
  288.       srand(1);           // Seed random # generator
  289.       }
  290.     else
  291.       goto DoError;
  292.     }
  293.  
  294.   // Skip white space
  295.   while (*pszCmdLine && *pszCmdLine <= ' ')
  296.     pszCmdLine++;
  297.   if (!*pszCmdLine)
  298.     {
  299. DoError:
  300.     MessageBox(NULL, "Usage: Spruuids [/P<filePlay> | /R<fileRec>] <fileCode>, where <fileCode> is a VB Script", "Spruuids", MB_OK | MB_ICONEXCLAMATION);
  301.     return E_FAIL;
  302.     }
  303.  
  304.   // Rest of Cmd Line should be source file
  305.   g_pszCodeFile = pszCmdLine;
  306.   return S_OK;
  307. }
  308.  
  309.  
  310. //---------------------------------------------------------------------------
  311. // Main program
  312. //---------------------------------------------------------------------------
  313. int WINAPI WinMain
  314. (
  315.   HINSTANCE hinst,        // Instance handle of current instance
  316.   HINSTANCE hinstPrev,    // Instance handle of previous instance
  317.   LPSTR     lpszCmdLine,  // Null-terminated command line
  318.   int        iCmdShow      // How window should be initially displayed
  319. )
  320. {
  321.   int     ret   = 1;      // Assume non-normal exit
  322.   BOOL    fInit = FALSE;
  323.   HRESULT hr;
  324.  
  325.   // Stuff hinst in global for all to see
  326.   g_hinst      = hinst;
  327.   hr = ParseCmdLine(lpszCmdLine);
  328.   if (hr)
  329.     goto CleanUp;
  330.  
  331.   // Initialize OLE
  332.   hr = CoInitialize(NULL);
  333.   if (hr)
  334.     goto CleanUp;
  335.   fInit = TRUE;
  336.  
  337.   // Create the CApp object, since it runs the show, note it inits g_papp
  338.   hr = CApp::CreateApp(hinst);
  339.   if (hr)
  340.     goto CleanUp;
  341.   ASSERT(g_papp, "!hr but g_papp==NULL");
  342.  
  343.   // Start a new game
  344.   g_papp->CausePause(0);
  345.   AppEvt_NewGame();
  346.  
  347.   // Either Playback or push the main msg loop
  348.   if (g_mode == MODE_PLAYBACK)
  349.     hr = g_papp->Playback();
  350.   else
  351.     hr = g_papp->MainMsgLoop();
  352.   if (hr)
  353.     goto CleanUp;
  354.  
  355.   // Normal exit
  356.   ret = 0;
  357.  
  358.   // Cleanup, if we haven't already done so
  359. CleanUp:
  360.   if (g_pfileRec)
  361.     {
  362.     fclose(g_pfileRec);
  363.     g_pfileRec = NULL;
  364.     }
  365.   if (g_papp)
  366.     delete g_papp;
  367.   if (fInit)
  368.     CoUninitialize();
  369.   return ret;
  370. }
  371.  
  372.  
  373. //***************************************************************************
  374. // Constructor and Destructor support for CApp
  375. //***************************************************************************
  376.  
  377. //---------------------------------------------------------------------------
  378. // Creates an instance of CApp.  Use this instead of "new", as this returns
  379. // errors, etc.
  380. //---------------------------------------------------------------------------
  381. HRESULT CApp::CreateApp
  382. (
  383.   HINSTANCE hinst
  384. )
  385. {
  386.   if (g_papp)
  387.     return E_UNEXPECTED;
  388.  
  389.   CApp *papp = new CApp(hinst);
  390.   if (!papp)
  391.     return E_OUTOFMEMORY;
  392.   if (papp->s_hr)
  393.     return papp->s_hr;
  394.  
  395.   return S_OK;
  396. }
  397.  
  398.  
  399. //---------------------------------------------------------------------------
  400. // Constructor
  401. //---------------------------------------------------------------------------
  402. CApp::CApp
  403. (
  404.   HINSTANCE hinst
  405. )
  406. {
  407.   WNDCLASS cls;
  408.   RECT     rect;
  409.   int      cx, cy;
  410.  
  411.   INIT_SIGNATURE(SIG_App);
  412.  
  413.   // Init globals
  414.   g_papp              = this;
  415.   g_punkApplicationNA = this->GetUnknown(); // GetUnknown() doesn't AddRef, but we don't want to anyway.
  416.   s_hr                = E_FAIL;             // Assume failure
  417.  
  418.   // Init members
  419.   m_pmsgloop        = NULL;
  420.   m_pgame           = NULL;
  421.   m_hwndDlg         = NULL;
  422.   m_hwndPS          = NULL;
  423.   m_hwndStat        = NULL;
  424.   m_hwndAbout       = NULL;
  425.   m_hinst           = hinst;
  426.   m_idcomp          = 0xffffffff;
  427.   m_fRegisteredComp = FALSE;
  428.   m_cmodal          = 0;
  429.   m_fQuit           = FALSE;
  430.   m_cref            = 1;
  431.   m_ptinfoCls       = NULL;
  432.   m_ptinfoInt       = NULL;
  433.   m_pdispBaseObject = NULL;
  434.  
  435.   // Add new class for dialog which is our application:
  436.   cls.style         = 0;
  437.   cls.lpfnWndProc   = DefDlgProc;
  438.   cls.cbClsExtra    = 0;
  439.   cls.cbWndExtra    = 0;
  440.   cls.hInstance     = hinst;
  441.   cls.hIcon         = LoadIcon(hinst, MAKEINTRESOURCE(ID_ICO_APP));
  442.   cls.hCursor       = NULL;
  443.   cls.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
  444.   cls.lpszMenuName  = NULL;
  445.   cls.lpszClassName = "DlgClass";
  446.   if (!RegisterClass(&cls))
  447.     return;
  448.  
  449.   // Add new class for play surface:
  450.   cls.style         = CS_OWNDC;
  451.   cls.lpfnWndProc   = PSWndProc;
  452.   cls.cbClsExtra    = 0;
  453.   cls.cbWndExtra    = 0;
  454.   cls.hInstance     = hinst;
  455.   cls.hIcon         = NULL;
  456.   cls.hCursor       = LoadCursor(hinst, MAKEINTRESOURCE(ID_CUR_PLAYSURF));
  457.   cls.hbrBackground = NULL;
  458.   cls.lpszMenuName  = NULL;
  459.   cls.lpszClassName = "PlaySurface";
  460.   if (!RegisterClass(&cls))
  461.     return;
  462.  
  463.   // Now that we've registerd the window classes, create the main window
  464.   m_hwndDlg = CreateDialog(hinst, MAKEINTRESOURCE(ID_DLG_APP), NULL, AppDlgProc);
  465.   if (!m_hwndDlg)
  466.     {
  467.     s_hr = E_OUTOFMEMORY;
  468.     return;
  469.     }
  470.  
  471.   // Center Dialog:
  472.   GetWindowRect(m_hwndDlg, &rect);
  473.   rect.right  -= rect.left;
  474.   rect.bottom -= rect.top;
  475.   cx = GetSystemMetrics(SM_CXSCREEN);
  476.   cy = GetSystemMetrics(SM_CYSCREEN);
  477.   MoveWindow(m_hwndDlg, (cx - rect.right) >> 1, (cy - rect.bottom) >> 1, rect.right, rect.bottom, TRUE);
  478.  
  479.   // Create the Component Manager
  480.   m_pmsgloop = new CMsgLoop(m_hwndDlg);
  481.   if (!m_pmsgloop)
  482.     {
  483.     s_hr = E_OUTOFMEMORY;
  484.     return;
  485.     }
  486.  
  487.   m_fRegisteredComp = m_pmsgloop->FRegisterComponent(this, &App_crinfo, &m_idcomp);
  488.   if (!m_fRegisteredComp)
  489.     return;
  490.  
  491.   HRESULT hr = this->LoadGame();
  492.   if (hr)
  493.     {
  494.     s_hr = hr;
  495.     return;
  496.     }
  497.  
  498.   // Success
  499.   s_hr = S_OK;
  500.   ShowWindow(m_hwndDlg, SW_NORMAL);
  501.   return;
  502. }
  503.  
  504.  
  505. //---------------------------------------------------------------------------
  506. // Destructor
  507. //---------------------------------------------------------------------------
  508. CApp::~CApp
  509. (
  510.   void
  511. )
  512. {
  513.   CHECK_SIGNATURE(SIG_App);
  514.  
  515.   g_papp = NULL;
  516.   g_punkApplicationNA = NULL;   // Wasn't AddRef()'d, so don't Release().
  517.  
  518.   if (m_hwndDlg)
  519.     {
  520.     ShowWindow(m_hwndDlg, SW_HIDE);
  521.     ReleaseCapture();
  522.     DestroyWindow(m_hwndDlg);
  523.     m_hwndDlg = NULL;
  524.     }
  525.  
  526.   if (m_pgame)
  527.     {
  528.     delete m_pgame;
  529.     m_pgame = NULL;
  530.     }
  531.  
  532.   if (m_fRegisteredComp)
  533.     {
  534.     ASSERT(m_pmsgloop, "m_idcomp, but !m_pmsgloop");
  535.     BOOL f = m_pmsgloop->FRevokeComponent(m_idcomp);
  536.     ASSERT(!f, "!f");
  537.     m_fRegisteredComp = FALSE;
  538.     }
  539.  
  540.   if (m_pmsgloop)
  541.     {
  542.     m_pmsgloop->Release();
  543.     m_pmsgloop = NULL;
  544.     }
  545.  
  546.   // Free dynamically created TypeInfo / TypeLib stuff
  547.   if (g_ptinfoClsGame)
  548.     g_ptinfoClsGame->Release();
  549.   if (g_ptinfoIntGame)
  550.     g_ptinfoIntGame->Release();
  551.  
  552.   if (g_ptlGameSubObj)
  553.     g_ptlGameSubObj->Release();
  554.  
  555.   // Free TypeInfo / TypeLib loaded from our resources
  556.   if (g_ptinfoClsGameOA)
  557.     g_ptinfoClsGameOA->Release();
  558.   if (g_ptinfoIntGameOA)
  559.     g_ptinfoIntGameOA->Release();
  560.  
  561.   if (g_ptinfoClsSpriteClass)
  562.     g_ptinfoClsSpriteClass->Release();
  563.   if (g_ptinfoIntSpriteClass)
  564.     g_ptinfoIntSpriteClass->Release();
  565.  
  566.   if (g_ptinfoClsSprite)
  567.     g_ptinfoClsSprite->Release();
  568.   if (g_ptinfoIntSprite)
  569.     g_ptinfoIntSprite->Release();
  570.  
  571.   if (m_ptinfoCls)
  572.     m_ptinfoCls->Release();
  573.   if (m_ptinfoInt)
  574.     m_ptinfoInt->Release();
  575.  
  576.   if (g_ptlMain)
  577.     g_ptlMain->Release();
  578.  
  579.   DESTROY_SIGNATURE(SIG_App);
  580. }
  581.  
  582.  
  583. //***************************************************************************
  584. // General methods
  585. //***************************************************************************
  586.  
  587. //---------------------------------------------------------------------------
  588. // Enter main message loop for application
  589. //---------------------------------------------------------------------------
  590. HRESULT CApp::MainMsgLoop
  591. (
  592.   void
  593. )
  594. {
  595.   if (!m_pmsgloop->FPushMessageLoop(g_papp->m_idcomp, cmgrloopDoEvents, NULL))
  596.     return E_FAIL;
  597.  
  598.   return S_OK;
  599. }
  600.  
  601.  
  602. //---------------------------------------------------------------------------
  603. // Load a game from the given file.
  604. //---------------------------------------------------------------------------
  605. HRESULT CApp::LoadGame
  606. (
  607.   void
  608. )
  609. {
  610.   if (m_pgame)
  611.     return E_UNEXPECTED;
  612.  
  613.   return CGame::CreateGame(g_hinst, m_hwndDlg, m_hwndPS, m_hwndStat, m_pmsgloop, &m_pgame);
  614. }
  615.  
  616.   
  617. //---------------------------------------------------------------------------
  618. // Get rid of an existing game, if present.
  619. //---------------------------------------------------------------------------
  620. void CApp::CloseGame
  621. (
  622.   void
  623. )
  624. {
  625.   if (m_pgame)
  626.     {
  627.     m_pgame->Close();
  628.     m_pgame->Release();
  629.     m_pgame = NULL;
  630.     }
  631. }
  632.  
  633.   
  634. //---------------------------------------------------------------------------
  635. // Called when pausing or unpausing
  636. //---------------------------------------------------------------------------
  637. void CApp::CausePause
  638. (
  639.   int p   // -1=Toggle, 0=UnPause, 1=Pause
  640. )
  641. {
  642.   // Invoke game.cpp's Pause event.  Returns whether or not app is paused
  643.   p = AppEvt_Pause(p);
  644. }
  645.  
  646.  
  647. //***************************************************************************
  648. // DlgProcs, WndProcs
  649. //***************************************************************************
  650.  
  651. //---------------------------------------------------------------------------
  652. //
  653. //---------------------------------------------------------------------------
  654. BOOL CALLBACK AppDlgProc
  655. (
  656.   HWND   hwnd,
  657.   UINT   msg,
  658.   WPARAM wp,
  659.   LPARAM lp
  660. )
  661. {
  662.   switch (msg)
  663.     {
  664.     case WM_INITDIALOG:
  665.       {
  666.       g_papp->m_hwndDlg  = hwnd;
  667.       g_papp->m_hwndPS   = GetDlgItem(hwnd, ID_CTL_PLAYSURF);
  668.       g_papp->m_hwndStat = GetDlgItem(hwnd, ID_CTL_STATUS);
  669.       break;
  670.       }
  671.  
  672.     case WM_ACTIVATE:
  673.       if (LOWORD(wp) != WA_INACTIVE)
  674.         {
  675.         g_papp->m_pmsgloop->OnComponentActivate(g_papp->m_idcomp);
  676.         SetFocus(g_papp->m_hwndPS);
  677.         return TRUE;
  678.         }
  679.       break;
  680.  
  681.     case WM_SETFOCUS:
  682.       SetFocus(g_papp->m_hwndPS);
  683.       return TRUE;
  684.  
  685.     case WM_QUERYDRAGICON:
  686.       return (BOOL)LoadIcon(g_papp->m_hinst, MAKEINTRESOURCE(ID_ICO_APP));
  687.  
  688.     case WM_PAINT:
  689.       {
  690.       HDC hdc;
  691.       PAINTSTRUCT ps;
  692.  
  693.       if (!IsIconic(hwnd))
  694.         return FALSE;
  695.       hdc = wp ? (HDC)wp : BeginPaint(hwnd, &ps);
  696.       DrawIcon(hdc, 0, 0, LoadIcon(g_papp->m_hinst, MAKEINTRESOURCE(ID_ICO_APP)));
  697.       if (!wp)
  698.         EndPaint(hwnd, &ps);
  699.       return TRUE;
  700.       }
  701.  
  702.     case WM_ERASEBKGND:
  703.       {
  704.       if (IsIconic(hwnd))
  705.         {
  706.         DefWindowProc(hwnd, msg, wp, lp);
  707.         return TRUE;
  708.         }
  709.  
  710.       // Draw fancy boarders
  711.       RECT rect;
  712.  
  713.       GetClientRect(hwnd, &rect);
  714.       DrawEdge((HDC)wp, &rect, 0, BF_RECT | BF_MIDDLE);
  715.  
  716.       GetWindowRect(g_papp->m_hwndPS, &rect);
  717.       ScreenToClient(hwnd, (LPPOINT)&rect);
  718.       ScreenToClient(hwnd, (LPPOINT)&rect.right);
  719.       InflateRect(&rect, 2, 2);
  720.       DrawEdge((HDC)wp, &rect, EDGE_SUNKEN, BF_RECT);
  721.  
  722.       GetWindowRect(g_papp->m_hwndStat, &rect);
  723.       InflateRect(&rect, 2, 2);
  724.       ScreenToClient(hwnd, (LPPOINT)&rect);
  725.       ScreenToClient(hwnd, (LPPOINT)&rect.right);
  726.       DrawEdge((HDC)wp, &rect, BDR_SUNKENOUTER, BF_RECT);
  727.       break;
  728.       }
  729.  
  730.     case WM_SYSCOMMAND:
  731.       RECORD(WIN_DLG, msg, wp, lp);
  732.       switch (wp & 0xfff0)
  733.         {
  734.         case SC_CLOSE:
  735.           if (g_papp->FQueryTerminate(TRUE))
  736.             g_papp->m_fQuit = TRUE;
  737.           break;
  738.         }
  739.       return FALSE;
  740.  
  741.     case WM_SIZE:
  742.       if (IsIconic(hwnd))
  743.         g_papp->CausePause(TRUE);
  744.       break;
  745.  
  746.     case WM_COMMAND:
  747.       RECORD(WIN_DLG, msg, wp, lp);
  748.       if (!LOWORD(lp) || HIWORD(lp) == 1)
  749.         switch (wp)
  750.           {
  751.           case ID_MENU_NEWGAME:
  752.             g_papp->CausePause(1);
  753.             if (!g_papp->m_pgame->m_fGameOver && g_mode != MODE_PLAYBACK)
  754.               {
  755.               int ret;
  756.               g_papp->m_pmsgloop->OnComponentEnterState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL, NULL);
  757.               ret = MessageBox(g_papp->m_hwndDlg, "Do you really want to start a new game?", "Spruuids", MB_YESNO | MB_ICONQUESTION);
  758.               g_papp->m_pmsgloop->FOnComponentExitState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL);
  759.               SetFocus(g_papp->m_hwndPS);
  760.               if (ret == IDYES)
  761.                 goto NewGame;
  762.               }
  763.             else
  764.               {
  765. NewGame:      g_papp->CausePause(0);
  766.               AppEvt_NewGame();
  767.               }
  768.             return TRUE;
  769.  
  770.           case ID_MENU_EDIT:
  771.             {
  772.             char sz[255];
  773.             // Shell notepad to edit file we loaded.
  774.             g_papp->CausePause(1);
  775.             wsprintf(sz, "Notepad.exe %s", g_pszCodeFile);
  776.             WinExec(sz, SW_SHOWNORMAL);
  777.             return TRUE;
  778.             }
  779.  
  780.           case ID_MENU_RELOAD:
  781.             g_papp->CausePause(1);
  782.             if (g_papp->m_pgame && !g_papp->m_pgame->m_fGameOver)
  783.               {
  784.               int ret;
  785.               g_papp->m_pmsgloop->OnComponentEnterState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL, NULL);
  786.               ret = MessageBox(g_papp->m_hwndDlg, "Do you really want to start a new game?", "Spruuids", MB_YESNO | MB_ICONQUESTION);
  787.               g_papp->m_pmsgloop->FOnComponentExitState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL);
  788.               SetFocus(g_papp->m_hwndPS);
  789.               if (ret == IDYES)
  790.                 goto OpenGame;
  791.               }
  792.             else
  793.               {
  794. OpenGame:     g_papp->CloseGame();
  795.               g_papp->LoadGame();
  796.               g_papp->CausePause(0);
  797.               AppEvt_NewGame();    // Start a new game
  798.               }
  799.             return TRUE;
  800.  
  801.           case ID_MENU_EXIT:
  802.             if (g_papp->FQueryTerminate(TRUE))
  803.               g_papp->m_fQuit = TRUE;
  804.             return TRUE;
  805.  
  806.           case ID_MENU_PAUSE:
  807.             g_papp->CausePause(-1);
  808.             break;
  809.  
  810.           case ID_MENU_ABOUT:
  811.             g_papp->CausePause(1);
  812.             g_papp->m_pmsgloop->OnComponentEnterState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL, NULL);
  813.             DialogBox(g_papp->m_hinst, MAKEINTRESOURCE(ID_DLG_ABOUT), g_papp->m_hwndDlg, AboutDlgProc);
  814.             g_papp->m_pmsgloop->FOnComponentExitState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL);
  815.             SetFocus(g_papp->m_hwndPS);
  816.             return TRUE;
  817.  
  818.           case ID_MENU_HIGHSCORES:
  819.           case ID_MENU_HELPINDEX:
  820.           case ID_MENU_HELPPLAY:
  821.           case ID_MENU_HELPCOMMANDS:
  822.           case ID_MENU_HELPHELP:
  823.             return TRUE;
  824.           }
  825.       break;
  826.     }
  827.  
  828.   return AppEvt_DlgProc(hwnd, msg, wp, lp);
  829. }
  830.  
  831.  
  832. //---------------------------------------------------------------------------
  833. //
  834. //---------------------------------------------------------------------------
  835. BOOL CALLBACK AboutDlgProc
  836. (
  837.   HWND   hwnd,
  838.   UINT   msg,
  839.   WPARAM wp,
  840.   LPARAM lp
  841. )
  842. {
  843.   switch (msg)
  844.     {
  845.     case WM_INITDIALOG:
  846.       {
  847.       RECT rect;
  848.       RECT rect2;
  849.  
  850.       g_papp->m_hwndAbout = hwnd;
  851.       GetWindowRect(g_papp->m_hwndDlg, &rect);
  852.       GetWindowRect(hwnd, &rect2);
  853.       MoveWindow(hwnd, (rect.right+rect.left)/2-(rect2.right-rect2.left)/2,
  854.                        (rect.bottom+rect.top)/2-(rect2.bottom-rect2.top)/2,
  855.                        rect2.right-rect2.left,
  856.                        rect2.bottom-rect2.top,
  857.                        TRUE);
  858.       return TRUE;
  859.       }
  860.  
  861.     case WM_COMMAND:
  862.       RECORD(WIN_ABOUT, msg, wp, lp);
  863.       g_papp->m_hwndAbout = NULL;
  864.       EndDialog(hwnd, TRUE);
  865.       return TRUE;
  866.     }
  867.   return FALSE;
  868. }
  869.  
  870.  
  871. //---------------------------------------------------------------------------
  872. //
  873. //---------------------------------------------------------------------------
  874. LRESULT CALLBACK PSWndProc
  875. (
  876.   HWND   hwnd,
  877.   UINT   msg,
  878.   WPARAM wp,
  879.   LPARAM lp
  880. )
  881. {
  882.   switch (msg)
  883.     {
  884.     case WM_TIMER:
  885.     case WM_CHAR:
  886.     case WM_KEYUP:
  887.     case WM_MOUSEMOVE:
  888.     case WM_LBUTTONUP:
  889.     case WM_RBUTTONUP:
  890.     case WM_MBUTTONUP:
  891.       RECORD(WIN_PS, msg, wp, lp);
  892.       break;
  893.  
  894.  
  895.     case WM_LBUTTONDOWN:
  896.     case WM_RBUTTONDOWN:
  897.     case WM_MBUTTONDOWN:
  898.       RECORD(WIN_PS, msg, wp, lp);
  899.       SetFocus(hwnd);
  900.       break;
  901.  
  902.     case WM_GETDLGCODE:
  903.       return DLGC_WANTALLKEYS | DLGC_WANTARROWS | DLGC_WANTCHARS | DLGC_WANTMESSAGE | DLGC_WANTTAB;
  904.  
  905.     case WM_KEYDOWN:
  906.       RECORD(WIN_PS, msg, wp, lp);
  907.       switch (wp)
  908.         {
  909.         case VK_ESCAPE:
  910.           ShowWindow(g_papp->m_hwndDlg, SW_MINIMIZE);
  911.           break;
  912.  
  913.         case VK_F1:
  914.           SendMessage(g_papp->m_hwndDlg, WM_COMMAND, ID_MENU_HELPINDEX, 0L);
  915.           break;
  916.  
  917.         case VK_F2:
  918.           SendMessage(g_papp->m_hwndDlg, WM_COMMAND, ID_MENU_NEWGAME, 0L);
  919.           break;
  920.  
  921.         case VK_PAUSE:
  922.         case VK_F3:
  923.           SendMessage(g_papp->m_hwndDlg, WM_COMMAND, ID_MENU_PAUSE, 0L);
  924.           break;
  925.  
  926.         case VK_F5:
  927.           SendMessage(g_papp->m_hwndDlg, WM_COMMAND, ID_MENU_RELOAD, 0L);
  928.           break;
  929.  
  930.         case VK_F9:
  931.           SendMessage(g_papp->m_hwndDlg, WM_COMMAND, ID_MENU_EDIT, 0L);
  932.           break;
  933.         }
  934.       break;
  935.     }
  936.  
  937.   return AppEvt_PSWndProc(hwnd, msg, wp, lp);
  938. }
  939.  
  940.  
  941. //***************************************************************************
  942. // IUnknown Interface
  943. //***************************************************************************
  944.  
  945. //---------------------------------------------------------------------------
  946. //
  947. //---------------------------------------------------------------------------
  948. STDMETHODIMP CApp::QueryInterface
  949. (
  950.   REFIID iid,
  951.   void **ppvObjOut
  952. )
  953. {
  954.   if (!ppvObjOut)
  955.     return E_INVALIDARG;
  956.  
  957.   *ppvObjOut = NULL;
  958.  
  959.   if (iid == IID_IUnknown)
  960.     *ppvObjOut = this->GetUnknown();
  961.   else if (iid == IID_IDispatch)
  962.     *ppvObjOut = this->GetDispatch();
  963.   else if (iid == IID_ISpruuidsApp)
  964.     *ppvObjOut = (ISpruuidsApp *)this;
  965.   else if (iid == IID_IOleComponent)
  966.     *ppvObjOut = (IOleComponent *)this;
  967.  
  968.   if (*ppvObjOut)
  969.     {
  970.     this->AddRef();
  971.     return S_OK;
  972.     }
  973.  
  974.   return E_NOINTERFACE;
  975. }
  976.  
  977.  
  978. //---------------------------------------------------------------------------
  979. //
  980. //---------------------------------------------------------------------------
  981. STDMETHODIMP_(ULONG) CApp::AddRef
  982. (
  983.   void
  984. )
  985. {
  986.   ASSERT(m_cref, "bad m_cref");
  987.   return ++m_cref;
  988. }
  989.  
  990.  
  991. //---------------------------------------------------------------------------
  992. //
  993. //---------------------------------------------------------------------------
  994. STDMETHODIMP_(ULONG) CApp::Release
  995. (
  996.   void
  997. )
  998. {
  999.   ASSERT(m_cref, "bad m_cref");
  1000.   m_cref--;
  1001.   if (!m_cref)
  1002.     {
  1003.     delete this;
  1004.     return 0;
  1005.     }
  1006.   return m_cref;
  1007. }
  1008.  
  1009.  
  1010. //***************************************************************************
  1011. // IOleComponent Interface
  1012. //***************************************************************************
  1013.  
  1014. //---------------------------------------------------------------------------
  1015. //
  1016. //---------------------------------------------------------------------------
  1017. STDMETHODIMP_(BOOL) CApp::FPreTranslateMessage
  1018. (
  1019.   MSG *pmsg
  1020. )
  1021. {
  1022.   return IsDialogMessage(m_hwndDlg, pmsg);
  1023. }
  1024.  
  1025.  
  1026. //---------------------------------------------------------------------------
  1027. //
  1028. //---------------------------------------------------------------------------
  1029. STDMETHODIMP_(void) CApp::OnEnterState
  1030. (
  1031.   ULONG state,
  1032.   BOOL  fEnter
  1033. )
  1034. {
  1035.   // TODO: We only care about Modal notifications.  You application will likely
  1036.   // TODO: need to support some of the others.
  1037.  
  1038.   if (state == cmgrstateModal)
  1039.     {
  1040.     if (fEnter)
  1041.       {
  1042.       if (!m_cmodal)
  1043.         {
  1044.         this->CausePause(1);              // Pause for the user, since we're modal
  1045.         EnableWindow(m_hwndDlg, FALSE);   // Entering modal state, so disable window
  1046.         }
  1047.       m_cmodal++;
  1048.       }
  1049.     else if (m_cmodal)    // Don't decrement if zero!
  1050.       {
  1051.       m_cmodal--;
  1052.       if (!m_cmodal)
  1053.         EnableWindow(m_hwndDlg, TRUE);   // Leaving modal state, so re-enable window
  1054.       }
  1055.     }
  1056. }
  1057.  
  1058.  
  1059. //---------------------------------------------------------------------------
  1060. //
  1061. //---------------------------------------------------------------------------
  1062. STDMETHODIMP_(void) CApp::OnAppActivate
  1063. (
  1064.   BOOL  fActive,
  1065.   DWORD dwOtherThreadID
  1066. )
  1067. {
  1068.   // TODO: If you have floating palettes, etc., show them here.
  1069.   SetFocus(m_hwndPS);
  1070. }
  1071.  
  1072.  
  1073. //---------------------------------------------------------------------------
  1074. //
  1075. //---------------------------------------------------------------------------
  1076. STDMETHODIMP_(void) CApp::OnLoseActivation
  1077. (
  1078.   void
  1079. )
  1080. {
  1081.   // TODO: If you have floating palettes, etc., hide them here.
  1082.   this->CausePause(1);
  1083. }
  1084.  
  1085.  
  1086. //---------------------------------------------------------------------------
  1087. //
  1088. //---------------------------------------------------------------------------
  1089. STDMETHODIMP_(BOOL) CApp::FDoIdle
  1090. (
  1091.   DWORD grfidlef
  1092. )
  1093. {
  1094.   // TODO: If you have need idle-time processing, do so here
  1095.   return FALSE;
  1096. }
  1097.  
  1098.  
  1099. //---------------------------------------------------------------------------
  1100. //
  1101. //---------------------------------------------------------------------------
  1102. STDMETHODIMP_(BOOL) CApp::FContinueMessageLoop
  1103. (
  1104.   ULONG uReason,
  1105.   void *pvLoopData
  1106. )
  1107. {
  1108.   MSG msg;
  1109.  
  1110.   // If we're playing back a recording, return from msg loop once there are
  1111.   // no more msgs.
  1112.   if (g_mode == MODE_PLAYBACK && !PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
  1113.     return FALSE;
  1114.  
  1115.   // Since the only time we push a message loop is for the Main message loop,
  1116.   // we don't want that one popped until we decide to exit the application.
  1117.   return !m_fQuit;
  1118. }
  1119.  
  1120.  
  1121. //---------------------------------------------------------------------------
  1122. //
  1123. //---------------------------------------------------------------------------
  1124. STDMETHODIMP_(BOOL) CApp::FQueryTerminate
  1125. (
  1126.   BOOL fPromptUser
  1127. )
  1128. {
  1129.   // Disallow termination if modal dlg is up
  1130.   if (m_cmodal)
  1131.     {
  1132.     if (fPromptUser)
  1133.       MessageBox(NULL, "Please terminate Dlg before exiting", "Spruuids",
  1134.                  MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OK);
  1135.     return FALSE;
  1136.     }
  1137.  
  1138.   return AppEvt_FQueryTerminate(fPromptUser);
  1139. }
  1140.  
  1141.  
  1142. //---------------------------------------------------------------------------
  1143. //
  1144. //---------------------------------------------------------------------------
  1145. STDMETHODIMP_(void) CApp::Terminate
  1146. (
  1147.   void
  1148. )
  1149. {
  1150.   // Unregister component & release all refs on Component Manager
  1151.   if (m_fRegisteredComp)
  1152.     {
  1153.     ASSERT(m_pmsgloop, "m_idcomp, but !m_pmsgloop");
  1154.     BOOL f = m_pmsgloop->FRevokeComponent(m_idcomp);
  1155.     ASSERT(!f, "!f");
  1156.     m_fRegisteredComp = FALSE;
  1157.     }
  1158.  
  1159.   if (m_pmsgloop)
  1160.     {
  1161.     m_pmsgloop->Release();
  1162.     m_pmsgloop = NULL;
  1163.     }
  1164.  
  1165.   m_fQuit = TRUE;
  1166. }
  1167.  
  1168.  
  1169. //***************************************************************************
  1170. // IDispatch Interface
  1171. //***************************************************************************
  1172.  
  1173. //---------------------------------------------------------------------------
  1174. // Method needed by COleAuto, so it can implement IDispatch for us.
  1175. //---------------------------------------------------------------------------
  1176. HRESULT CApp::GetTypeLibInfo
  1177. (
  1178.   HINSTANCE    *phinstOut,
  1179.   const GUID  **pplibidOut, 
  1180.   SHORT        *pwMajLib, 
  1181.   SHORT        *pwMinLib,
  1182.   const CLSID **ppclsidOut, 
  1183.   const IID   **ppiidOut, 
  1184.   ITypeLib   ***ppptlOut
  1185. )
  1186. {
  1187.   *phinstOut  = g_hinst;
  1188.   *pplibidOut = &LIBID_SPRUUIDS;
  1189.   *pwMajLib   = 1;
  1190.   *pwMinLib   = 0;
  1191.   *ppclsidOut = &CLSID_SpruuidsApp;
  1192.   *ppiidOut   = &IID_ISpruuidsApp;
  1193.   *ppptlOut   = &g_ptlMain;
  1194.   return S_OK;
  1195. }
  1196.  
  1197.  
  1198. //***************************************************************************
  1199. // SpruuidsApp Interface
  1200. //***************************************************************************
  1201.  
  1202. //---------------------------------------------------------------------------
  1203. // 
  1204. //---------------------------------------------------------------------------
  1205. STDMETHODIMP CApp::get_Application
  1206. (
  1207.   ISpruuidsApp** lppaReturn
  1208. )
  1209. {
  1210.   return this->QueryInterface(IID_ISpruuidsApp, (void **)lppaReturn);
  1211. }
  1212.  
  1213.  
  1214. //---------------------------------------------------------------------------
  1215. // 
  1216. //---------------------------------------------------------------------------
  1217. STDMETHODIMP CApp::get_Parent
  1218. (
  1219.   ISpruuidsApp** lppaReturn
  1220. )
  1221. {
  1222.   return this->QueryInterface(IID_ISpruuidsApp, (void **)lppaReturn);
  1223. }
  1224.  
  1225.  
  1226. //---------------------------------------------------------------------------
  1227. // 
  1228. //---------------------------------------------------------------------------
  1229. STDMETHODIMP CApp::Quit
  1230. (
  1231.   void 
  1232. )
  1233. {
  1234.   m_fQuit = TRUE;
  1235.  
  1236.   return S_OK;
  1237. }
  1238.  
  1239.  
  1240. //---------------------------------------------------------------------------
  1241. // 
  1242. //---------------------------------------------------------------------------
  1243. STDMETHODIMP CApp::get_Game
  1244. (
  1245.   IGame** lppaReturn
  1246. )
  1247. {
  1248.   return m_pgame->QueryInterface(IID_IGame, (void **)lppaReturn);
  1249. }
  1250.  
  1251.   
  1252. //--- EOF -------------------------------------------------------------------
  1253.