home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / vjplusb / activex / inetsdk / samples / axscript / spruuids / src / app.cpp next >
Encoding:
C/C++ Source or Header  |  1996-07-15  |  32.1 KB  |  1,250 lines

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