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

  1. //---------------------------------------------------------------------------
  2. // Game.cpp
  3. //---------------------------------------------------------------------------
  4. // 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 "Game.h"
  16. #include "App.h"
  17. #include "Spr.h"
  18. #include "Score.h"
  19. #include "SpruuidP.h"
  20. #include <math.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <stdio.h>
  24.  
  25.  
  26. //---------------------------------------------------------------------------
  27. // DEBUG info
  28. //---------------------------------------------------------------------------
  29. SZTHISFILE
  30.  
  31.  
  32. //---------------------------------------------------------------------------
  33. // Forward Declares
  34. //---------------------------------------------------------------------------
  35. int DisplayScriptError(HINSTANCE hinst, HWND hwndParent, LPCSTR pszError, int ichError);
  36.  
  37.  
  38. //---------------------------------------------------------------------------
  39. // Image data
  40. //---------------------------------------------------------------------------
  41. #define ADDPIX(    id,idNext,x,y,cx,cy) {iimg##idNext, x, y, cx, cy},
  42. #define ADDPIXLAST(id,idNext,x,y,cx,cy) {iimg##idNext, x, y, cx, cy}
  43. #define ADDPIXIMG
  44. IMG Game_img[] = {
  45. #include "SpruuidP.pix"
  46. };
  47. #undef ADDPIX
  48. #undef ADDPIXLAST
  49. #undef ADDPIXIMG
  50.  
  51.  
  52. //---------------------------------------------------------------------------
  53. // Various Globals
  54. //---------------------------------------------------------------------------
  55. CGame     *g_pgame            = NULL;
  56. ITypeLib  *g_ptlGameSubObj    = NULL;
  57. ITypeInfo *g_ptinfoClsGame    = NULL;
  58. ITypeInfo *g_ptinfoIntGame    = NULL;
  59. char      *CGame::s_pszError  = NULL;
  60. ULONG      g_clineOffset;
  61.  
  62.  
  63. //---------------------------------------------------------------------------
  64. // Cover for contstructor.  Use instead of new CGame!
  65. //---------------------------------------------------------------------------
  66. HRESULT CGame::s_hr = E_FAIL;
  67.  
  68. HRESULT CGame::CreateGame
  69. (
  70.   HINSTANCE hinst,
  71.   HWND      hwndDlg,
  72.   HWND      hwndPS,
  73.   HWND      hwndStat,
  74.   IOleComponentManager *pcm,
  75.   CGame   **ppgameOut
  76. )
  77. {
  78.   CGame  *pgame;
  79.   HRESULT hr;
  80.  
  81.   *ppgameOut = NULL;
  82.   pgame = new CGame(hinst, hwndDlg, hwndPS, hwndStat, pcm);
  83.   if (!pgame)
  84.     return E_OUTOFMEMORY;
  85.   else if (pgame->s_hr)
  86.     {
  87.     delete pgame;
  88.     return s_hr;
  89.     }
  90.  
  91. // ##### BEGIN ACTIVEX SCRIPTING SUPPORT #####
  92. // Add the Game as a Named Item & load its code
  93.   g_clineOffset = 0;
  94.   hr = pgame->ParseFile(g_pszCodeFile, L"Game");
  95.   if (hr)
  96.     {
  97.     MessageBox(g_papp->m_hwndDlg, s_pszError ? s_pszError : "Unspecified Error", "Spruuids", MB_OK | MB_ICONEXCLAMATION);
  98.     return hr;
  99.     }
  100. // #####  END  ACTIVEX SCRIPTING SUPPORT #####
  101.  
  102.   // Create sprite classes based upon $OBJECT lines in file
  103.   for (int i=0; i<pgame->m_csubobj; i++)
  104.     {
  105.     CHECK(CSpriteClass::Create(pgame->m_pdisp, &pgame->m_rgpsc[i]));
  106.     pgame->m_rgpdispSubObjs[i] = pgame->m_rgpsc[i]->GetDispatch();
  107.     pgame->m_rgpdispSubObjs[i]->AddRef();
  108.     }
  109.  
  110.   if (hr)
  111.     {
  112. CleanUp:
  113.     delete pgame;
  114.     return hr;
  115.     }
  116.  
  117. // ##### BEGIN ACTIVEX SCRIPTING SUPPORT #####
  118.   // Start the script running...
  119.   hr = pgame->m_ps->SetScriptState(SCRIPTSTATE_CONNECTED);
  120.   if (hr)
  121.     {
  122.     delete pgame;
  123.     return hr;
  124.     }
  125. // #####  END  ACTIVEX SCRIPTING SUPPORT #####
  126.  
  127.   // Success
  128.   *ppgameOut = pgame;
  129.   return S_OK;
  130. }
  131.  
  132.  
  133. //---------------------------------------------------------------------------
  134. // Constructor
  135. //---------------------------------------------------------------------------
  136. CGame::CGame
  137. (
  138.   HINSTANCE hinst,
  139.   HWND      hwndDlg,
  140.   HWND      hwndPS,
  141.   HWND      hwndStat,
  142.   IOleComponentManager *pcm
  143. )
  144. {
  145.   INIT_SIGNATURE(SIG_Game);
  146.  
  147.   // Setup globals
  148.   g_pgame       = this;
  149.   s_hr          = S_OK;
  150.  
  151.   // Init members
  152.   m_hinst        = hinst;
  153.   m_hwndDlg      = hwndDlg;
  154.   m_hwndPS       = hwndPS;
  155.   m_hwndStat     = hwndStat;
  156.   m_cref         = 1;
  157.   m_fPaused      = FALSE;
  158.   m_fShipDead    = FALSE;
  159.   m_fShipRestart = FALSE;
  160.   m_fGameOver    = TRUE;
  161.   m_pcm          = pcm;
  162.   m_ps           = NULL;
  163.   m_psp          = NULL;
  164.   VariantInit(&m_varTag);
  165.   m_pscore       = NULL;
  166.   m_pdisp        = NULL;
  167.   m_pdispBaseObject = NULL;
  168.   m_pgameoa      = NULL;
  169.   m_csubobj      = 0;
  170.  
  171.   CoCreateGuid(&m_libidSubObj);
  172.   CoCreateGuid(&m_clsidSubObj);
  173.   CoCreateGuid(&m_iidSubObj);
  174.  
  175.   m_pgameoa = new CGameOA(this);
  176.   if (!m_pgameoa)
  177.     {
  178.     s_hr = E_OUTOFMEMORY;
  179.     return;
  180.     }
  181.   this->SetBaseObject(m_pgameoa->GetDispatch());
  182.  
  183.   m_pdisp = new CDisplay(hinst, hwndPS, GetDC(hwndPS),
  184.                          this->GetUnknown(), CGameOA::FireCollide,
  185.                          sizeof(Game_img)/sizeof(IMG), Game_img, ID_BMP_SPRITES);
  186.   if (!m_pdisp)
  187.     {
  188.     s_hr = E_OUTOFMEMORY;
  189.     return;
  190.     }
  191.  
  192.   s_hr = CScore::CreateScore(
  193.                       m_hinst,       // hinst to load resources from
  194.                       m_hwndDlg,     // hwnd on which to draw score
  195.                       m_hwndPS,      // hwnd of PlaySurface
  196.                       m_hwndStat,    // hwnd of Status bar
  197.                       2500,          // scoreFirst1Up
  198.                       5000,          // scoreSecond1Up
  199.                       2500,          // dscoreNext1Up
  200.                       3,             // cshipStart;
  201.                       ID_BMP_SHIP,   // idbmpShip;
  202.                       ID_BMP_PLUS,   // idbmpPlus;
  203.                       &m_pscore);
  204.   if (s_hr)
  205.     return;
  206.   ASSERT(m_pscore, "Good hr, but m_pscore==NULL");
  207.  
  208.   // Default to VBScript
  209.   extern const CLSID CLSID_VBScript;
  210.   m_clsidEngine = CLSID_VBScript;
  211.  
  212.   // Success
  213.   s_hr = S_OK;
  214. }
  215.  
  216.  
  217. //---------------------------------------------------------------------------
  218. // Clean up allocated resources
  219. //---------------------------------------------------------------------------
  220. CGame::~CGame
  221. (
  222.   void
  223. )
  224. {
  225.   CHECK_SIGNATURE(SIG_Game);
  226.   this->Close();
  227.   if (m_pgameoa)
  228.     delete m_pgameoa;
  229.   DESTROY_SIGNATURE(SIG_Game);
  230. }
  231.  
  232.  
  233. //---------------------------------------------------------------------------
  234. // Clean up allocated resources
  235. //---------------------------------------------------------------------------
  236. void CGame::Close
  237. (
  238.   void
  239. )
  240. {
  241.   CHECK_SIGNATURE(SIG_Game);
  242.  
  243.   if (g_mode != MODE_PLAYBACK)
  244.     KillTimer(m_hwndPS, 0);
  245.  
  246.   g_pgame = NULL;
  247.  
  248.   // Clear this, since it may be an object
  249.   VariantClear(&m_varTag);
  250.  
  251. // ##### BEGIN ACTIVEX SCRIPTING SUPPORT #####
  252.   // Release the language engine, since it may hold on to us
  253.   if (m_psp)
  254.     m_psp->Release();
  255.   if (m_ps)
  256.     {
  257.     m_ps->Close();
  258.     m_ps->Release();
  259.     }
  260. // #####  END  ACTIVEX SCRIPTING SUPPORT #####
  261.  
  262.   // Drop all sink's that have Advise()'d us, since they might keep us alive
  263.   m_pgameoa->m_cp.Close();
  264.  
  265.   // Release all existing sprites
  266.   if (m_pdisp)
  267.     m_pdisp->DestroyAll();
  268.  
  269.   // Close & Release the SpriteClass Sub Objects
  270.   for (int i=0; i<m_csubobj; i++)
  271.     {
  272.     delete [] m_rgpwszSubObjs[i];
  273.     if (m_rgpdispSubObjs[i])
  274.       {
  275.       m_rgpdispSubObjs[i]->Release();
  276.       m_rgpdispSubObjs[i] = NULL;
  277.       }
  278.     if (m_rgpsc[i])
  279.       {
  280.       m_rgpsc[i]->Close();
  281.       m_rgpsc[i]->Release();
  282.       m_rgpsc[i] = NULL;
  283.       }
  284.     }
  285.  
  286.   // Now destroy the Score & Display objects
  287.   if (m_pscore)
  288.     {
  289.     delete m_pscore;
  290.     m_pscore = NULL;
  291.     }
  292.   if (m_pdisp)
  293.     {
  294.     delete m_pdisp;
  295.     m_pdisp = NULL;
  296.     }
  297. }
  298.  
  299.  
  300. //***************************************************************************
  301. // IUnknown Interface
  302. //***************************************************************************
  303.  
  304. //---------------------------------------------------------------------------
  305. // 
  306. //---------------------------------------------------------------------------
  307. STDMETHODIMP CGame::QueryInterface
  308. (
  309.   REFIID  iid,
  310.   LPVOID* ppvObjOut
  311. )
  312. {
  313.   if (!ppvObjOut)
  314.     return E_INVALIDARG;
  315.  
  316.   *ppvObjOut = NULL;
  317.  
  318.   if (iid == IID_IUnknown)
  319.     *ppvObjOut = this->GetUnknown();
  320.   else if (iid == IID_IDispatch)
  321.     *ppvObjOut = this->GetDispatch();
  322.   else if (iid == IID_IGameSubObjects)
  323.     *ppvObjOut = this->GetDispatch();
  324.   else if (iid == IID_IActiveScriptSite)
  325.     *ppvObjOut = (IActiveScriptSite *)this;
  326.   else if (iid == IID_IProvideClassInfo)
  327.     *ppvObjOut = (IProvideClassInfo *)this;
  328.   else if (iid == IID_IProvideMultipleClassInfo)
  329.     *ppvObjOut = (IProvideMultipleClassInfo *)this;
  330.   else if (iid == IID_IGame)
  331.     *ppvObjOut = (IGame *)(this->m_pgameoa);
  332.   else if (iid == IID_IConnectionPointContainer)
  333.     *ppvObjOut = (IConnectionPointContainer *)(this->m_pgameoa);
  334.  
  335.   if (*ppvObjOut)
  336.     {
  337.     this->AddRef();
  338.     return S_OK;
  339.     }
  340.  
  341.   return E_NOINTERFACE;
  342. }
  343.  
  344.  
  345. //---------------------------------------------------------------------------
  346. // 
  347. //---------------------------------------------------------------------------
  348. STDMETHODIMP_(ULONG) CGame::AddRef
  349. (
  350.   void 
  351. )
  352. {
  353.   return ++m_cref;
  354. }
  355.  
  356.  
  357. //---------------------------------------------------------------------------
  358. // 
  359. //---------------------------------------------------------------------------
  360. STDMETHODIMP_(ULONG) CGame::Release
  361. (
  362.   void 
  363. )
  364. {
  365.   ASSERT(m_cref, "bad m_cref");
  366.   m_cref--;
  367.   if (!m_cref)
  368.     {
  369.     m_pgameoa->m_cp.Close();     // Make sure nobody's holding on to us because we're holding their sink
  370.     if (!m_cref && !m_pgameoa->m_cp.m_cref)
  371.       {
  372.       delete this;
  373.       return 0;
  374.       }
  375.     }
  376.   return m_cref;
  377. }
  378.  
  379.  
  380. //***************************************************************************
  381. // IDispatch Interface
  382. //***************************************************************************
  383.  
  384. //---------------------------------------------------------------------------
  385. // Re-implement COleAuto's GetIDsOfNames(), so we can implement the dynamic
  386. // properties we added for the $OBJECT=SpriteClassName lines.
  387. //---------------------------------------------------------------------------
  388. STDMETHODIMP CGame::GetIDsOfNames
  389. (
  390.   REFIID    iid,
  391.   OLECHAR** rgszNames,
  392.   UINT      cNames,
  393.   LCID      lcid,
  394.   DISPID*   prgdispid
  395. )
  396. {
  397.   // Validate Args
  398.   if (iid != IID_NULL)
  399.       return E_INVALIDARG;
  400.  
  401.   // See if a sub-object matches the name passed in.
  402.   for (int i=0; i<m_csubobj; i++)
  403.     if (!wcscmp(*rgszNames, m_rgpwszSubObjs[i]))
  404.       {
  405.       if (cNames != 1)
  406.         return DISP_E_NONAMEDARGS;
  407.       *prgdispid = 0x80010000 | i;
  408.       return S_OK;
  409.       }
  410.  
  411.   return COleAuto::GetIDsOfNames(iid, rgszNames, cNames, lcid, prgdispid);
  412. }
  413.  
  414.  
  415. //---------------------------------------------------------------------------
  416. // Re-implement COleAuto's Invoke(), so we can implement the dynamic
  417. // properties we added for the $OBJECT=SpriteClassName lines.
  418. //---------------------------------------------------------------------------
  419. STDMETHODIMP CGame::Invoke
  420. (
  421.   DISPID      dispid,
  422.   REFIID      riid,
  423.   LCID        lcid,
  424.   WORD        wFlags,
  425.   DISPPARAMS* pdispparams,
  426.   VARIANT*    pvarResult,
  427.   EXCEPINFO*  pexcepinfo, 
  428.   UINT*       puArgErr)
  429. {
  430.   IDispatch *pdisp = NULL;
  431.  
  432.   // Validate Args
  433.   if (pvarResult)
  434.     VariantInit(pvarResult);
  435.   if (puArgErr)
  436.     *puArgErr = 0;
  437.   SetErrorInfo(0L, NULL);
  438.  
  439.   // If dispid isn't a dynamic property, call COleAuto's dispatch,
  440.   // and it will forward the request on to m_pdispBaseObject.
  441.   if ((dispid & 0x80010000) != 0x80010000)
  442.     return COleAuto::Invoke(dispid, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  443.   // It's for one of our property objects...
  444.  
  445.   // Make sure we have either a PropGet or a Method
  446.   if (!(wFlags & (DISPATCH_METHOD | DISPATCH_PROPERTYGET)))
  447.     return DISP_E_MEMBERNOTFOUND;
  448.  
  449.   dispid &= 0xffff;
  450.   if (dispid >= m_csubobj)
  451.     return DISP_E_MEMBERNOTFOUND;
  452.  
  453.   if (pdispparams->cArgs)
  454.     return DISP_E_BADPARAMCOUNT;
  455.  
  456.   if (pdispparams->cNamedArgs)
  457.     return DISP_E_NONAMEDARGS;
  458.  
  459.   // Get an addref'd IDispatch to the property object
  460.   pdisp = m_rgpdispSubObjs[dispid];
  461.   ASSERT(pdisp, "NULL m_rgpdispSubObjs[]");
  462.  
  463.   if (pvarResult)    
  464.     {
  465.     pvarResult->vt = VT_DISPATCH;
  466.     pvarResult->pdispVal = pdisp;
  467.     pdisp->AddRef();        // We're returning this disp ptr
  468.     }
  469.  
  470.   return S_OK;
  471. }
  472.  
  473.  
  474. //---------------------------------------------------------------------------
  475. // Method needed by COleAuto, so it can implement IDispatch for us.
  476. //---------------------------------------------------------------------------
  477. HRESULT CGame::GetTypeLibInfo
  478. (
  479.   HINSTANCE    *phinstOut,
  480.   const GUID  **pplibidOut, 
  481.   SHORT        *pwMajLib, 
  482.   SHORT        *pwMinLib,
  483.   const CLSID **ppclsidOut, 
  484.   const IID   **ppiidOut, 
  485.   ITypeLib   ***ppptlOut
  486. )
  487. {
  488.   HRESULT hr = this->BuildTypeInfo();
  489.   if (hr)
  490.     return hr;
  491.   *phinstOut  = NULL;
  492.   *pplibidOut = &m_libidSubObj;
  493.   *pwMajLib   = 1;
  494.   *pwMinLib   = 0;
  495.   *ppclsidOut = &m_clsidSubObj;
  496.   *ppiidOut   = &m_iidSubObj;
  497.   *ppptlOut   = &g_ptlGameSubObj;
  498.   return S_OK;
  499. }
  500.  
  501.  
  502. //***************************************************************************
  503. // IProvideClassInfo Interfaces
  504. //***************************************************************************
  505.  
  506. //---------------------------------------------------------------------------
  507. // 
  508. //---------------------------------------------------------------------------
  509. STDMETHODIMP CGame::GetClassInfo
  510. (
  511.   ITypeInfo** pptinfoOut
  512. )
  513. {
  514.   HRESULT hr = ((COleAuto *)this)->CheckTypeInfo(0, 0x0409);
  515.   if (hr)
  516.     return hr;
  517.   *pptinfoOut = g_ptinfoClsGame;
  518.   (*pptinfoOut)->AddRef();
  519.   return S_OK;
  520. }
  521.  
  522.  
  523. //---------------------------------------------------------------------------
  524. // 
  525. //---------------------------------------------------------------------------
  526. STDMETHODIMP CGame::GetGUID
  527. (
  528.   DWORD dwGuidKind,
  529.   GUID* pGUID
  530. )
  531. {
  532.   if (pGUID)
  533.     return E_INVALIDARG;
  534.  
  535.   if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
  536.     return E_INVALIDARG;
  537.  
  538.   *pGUID = DIID_IGameEvents;
  539.   return S_OK;
  540. }
  541.  
  542.  
  543. //---------------------------------------------------------------------------
  544. // 
  545. //---------------------------------------------------------------------------
  546. STDMETHODIMP CGame::GetMultiTypeInfoCount
  547. (
  548.   ULONG *pcti
  549. )
  550. {
  551.   if (!pcti)
  552.     return E_INVALIDARG;
  553.  
  554.   *pcti = 2;
  555.   return S_OK;
  556. }
  557.  
  558.  
  559. //---------------------------------------------------------------------------
  560. // 
  561. //---------------------------------------------------------------------------
  562. STDMETHODIMP CGame::GetInfoOfIndex
  563. (
  564.   ULONG       iti,
  565.   DWORD       dwFlags,
  566.   ITypeInfo** pptiCoClass,
  567.   DWORD*      pdwTIFlags,
  568.   ULONG*      pcdispidReserved,
  569.   IID*        piidPrimary,
  570.   IID*        piidSource
  571. )
  572. {
  573.   HRESULT    hr        = S_OK;
  574.   ITypeInfo *ptinfoOut = NULL;
  575.  
  576.   if (iti > 1)
  577.     hr = E_FAIL;
  578.  
  579. //  if (dwFlags & ~MULTICLASSINFO_ALL)
  580. //    hr = E_INVALIDARG;
  581.  
  582.   if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
  583.     {
  584.     if (!pptiCoClass || !pdwTIFlags)
  585.       hr = E_INVALIDARG;
  586.     else
  587.       {
  588.       *pdwTIFlags  = 0L;
  589.       *pptiCoClass = NULL;
  590.       if (iti == 0)
  591.         {
  592.         hr = ((COleAuto *)this)->CheckTypeInfo(0, 0x0409);
  593.         if (hr)
  594.           return hr;
  595.         ptinfoOut = g_ptinfoClsGame;
  596.         }
  597.       else
  598.         {
  599.         hr = ((COleAuto *)m_pgameoa)->CheckTypeInfo(0, 0x0409);
  600.         if (hr)
  601.           return hr;
  602.         ptinfoOut = g_ptinfoClsGameOA;
  603.         }
  604.       }
  605.     }
  606.  
  607.   if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
  608.     {
  609.     if (!pcdispidReserved)
  610.       hr = E_INVALIDARG;
  611.     else
  612.       *pcdispidReserved = 256;
  613.     }
  614.  
  615.   if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY)
  616.     {
  617.     if (!piidPrimary)
  618.       hr = E_INVALIDARG;
  619.     else if (iti == 0)
  620.       *piidPrimary = IID_IGameSubObjects;
  621.     else
  622.       *piidPrimary = IID_IGame;
  623.     }
  624.  
  625.   if (dwFlags & MULTICLASSINFO_GETIIDSOURCE)
  626.     {
  627.     if (!piidSource)
  628.       hr = E_INVALIDARG;
  629.     else if (iti == 0)
  630.       *piidSource = IID_NULL;
  631.     else
  632.       *piidSource = DIID_IGameEvents;
  633.     }
  634.  
  635.   // Fill in ptinfo out param
  636.   if (hr)
  637.     {
  638.     if (pptiCoClass)
  639.       *pptiCoClass = NULL;
  640.     }
  641.   else if (pptiCoClass)
  642.     {
  643.     *pptiCoClass = ptinfoOut;
  644.     (*pptiCoClass)->AddRef();
  645.     }
  646.  
  647.   return hr;
  648. }
  649.  
  650.  
  651.  
  652. // ##### BEGIN ACTIVEX SCRIPTING SUPPORT #####
  653. //***************************************************************************
  654. // IActiveScriptSite Interface
  655. //***************************************************************************
  656.  
  657. //---------------------------------------------------------------------------
  658. // 
  659. //---------------------------------------------------------------------------
  660. STDMETHODIMP CGame::GetLCID
  661. (
  662.   LCID *plcid
  663. )
  664. {
  665.   return E_NOTIMPL;     // Use system settings
  666. }
  667.  
  668.  
  669. //---------------------------------------------------------------------------
  670. // 
  671. //---------------------------------------------------------------------------
  672. STDMETHODIMP CGame::GetItemInfo
  673. (
  674.   LPCOLESTR   pstrName,
  675.   DWORD       dwReturnMask,
  676.   IUnknown**  ppunkItemOut,
  677.   ITypeInfo** pptinfoOut
  678. )
  679. {
  680.   HRESULT hr;
  681.  
  682.   if (dwReturnMask & SCRIPTINFO_ITYPEINFO)
  683.     {
  684.     if (!pptinfoOut)
  685.       return E_INVALIDARG;
  686.     *pptinfoOut = NULL;
  687.     }
  688.  
  689.   if (dwReturnMask & SCRIPTINFO_IUNKNOWN)
  690.     {
  691.     if (!ppunkItemOut)
  692.       return E_INVALIDARG;
  693.     *ppunkItemOut = NULL;
  694.     }
  695.  
  696.   if (!_wcsicmp(L"game", pstrName))
  697.     {
  698.     if (dwReturnMask & SCRIPTINFO_ITYPEINFO)
  699.       {
  700.       hr = ((COleAuto *)this)->CheckTypeInfo(0, 0x0409);
  701.       if (hr)
  702.         return hr;
  703.       *pptinfoOut = g_ptinfoClsGame;
  704.       (*pptinfoOut)->AddRef();      // because returning
  705.       }
  706.     if (dwReturnMask & SCRIPTINFO_IUNKNOWN)
  707.       {
  708.       *ppunkItemOut = this->GetUnknown();
  709.       (*ppunkItemOut)->AddRef();    // because returning
  710.       }
  711.     return S_OK;
  712.     }
  713.  
  714.   return TYPE_E_ELEMENTNOTFOUND;
  715. }
  716.  
  717.  
  718. //---------------------------------------------------------------------------
  719. // 
  720. //---------------------------------------------------------------------------
  721. STDMETHODIMP CGame::GetDocVersionString
  722. (
  723.   BSTR *pbstrVersion
  724. )
  725. {
  726.   return E_NOTIMPL;   // UNDONE: Implement this method
  727. }
  728.  
  729.  
  730. //---------------------------------------------------------------------------
  731. // 
  732. //---------------------------------------------------------------------------
  733. STDMETHODIMP CGame::RequestItems
  734. (
  735.   void 
  736. )
  737. {
  738.   return m_ps->AddNamedItem(L"Game", SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE);
  739. }
  740.  
  741.  
  742. //---------------------------------------------------------------------------
  743. // 
  744. //---------------------------------------------------------------------------
  745. STDMETHODIMP CGame::RequestTypeLibs
  746. (
  747.   void 
  748. )
  749. {
  750.   return m_ps->AddTypeLib(LIBID_SPRUUIDS, 1, 0, 0);
  751. }
  752.  
  753.  
  754. //---------------------------------------------------------------------------
  755. // 
  756. //---------------------------------------------------------------------------
  757. STDMETHODIMP CGame::OnScriptTerminate
  758. (
  759.   const VARIANT   *pvarResult,
  760.   const EXCEPINFO *pexcepinfo
  761. )
  762. {
  763.   // UNDONE: Put up error dlg here
  764.   return S_OK;
  765. }
  766.  
  767.  
  768. //---------------------------------------------------------------------------
  769. // 
  770. //---------------------------------------------------------------------------
  771. STDMETHODIMP CGame::OnStateChange
  772. (
  773.   SCRIPTSTATE ssScriptState
  774. )
  775. {
  776.   // Don't care about notification
  777.   return S_OK;
  778. }
  779.  
  780.  
  781. //---------------------------------------------------------------------------
  782. // Display the error
  783. //---------------------------------------------------------------------------
  784. STDMETHODIMP CGame::OnScriptError
  785. (
  786.   IActiveScriptError *pse
  787. )
  788. {
  789.   char      szError[1024];
  790.   char     *pszArrow = NULL;
  791.   BOOL      fAlloc = FALSE;
  792.   EXCEPINFO ei;
  793.   DWORD     dwSrcContext;
  794.   ULONG     ulLine;
  795.   LONG      ichError;
  796.   BSTR      bstrLine = NULL;
  797.   HRESULT   hr;
  798.  
  799.   CHECK(pse->GetExceptionInfo(&ei));
  800.   CHECK(pse->GetSourcePosition(&dwSrcContext, &ulLine, &ichError));
  801.   ulLine += g_clineOffset;    // Adjust for $ENGINE/$OBJECT/etc. lines
  802.   hr = pse->GetSourceLineText(&bstrLine);
  803.   if (hr)
  804.     hr = S_OK;  // Ignore this error, there may not be source available
  805.   
  806.   if (!hr)
  807.     {
  808.     MAKE_ANSIPTR_FROMWIDE(pszSrc,  ei.bstrSource);
  809.     MAKE_ANSIPTR_FROMWIDE(pszDesc, ei.bstrDescription);
  810.     MAKE_ANSIPTR_FROMWIDE(pszLine, bstrLine);
  811.     if (ichError > 0 && ichError < 255)
  812.       {
  813.       pszArrow = new char[ichError+1];
  814.       memset(pszArrow, '-', ichError);
  815.       pszArrow[ichError-1] = 'v';
  816.       pszArrow[ichError]   = 0;
  817.       fAlloc = TRUE;
  818.       }
  819.     else
  820.       pszArrow = "";
  821.  
  822.     wsprintf(szError, "Source:'%s'\nFile:'%s'  Line:%d  Char:%d\nError:%d  '%s'\n%s\n%s",
  823.                       pszSrc, g_pszCodeFile, ulLine, ichError,
  824.                       (int)ei.wCode, pszDesc, pszArrow, pszLine);
  825.     DisplayScriptError(g_hinst, m_hwndDlg, szError, ichError);
  826.     }
  827.  
  828. CleanUp:
  829.   if (fAlloc)
  830.     delete [] pszArrow;
  831.   if (bstrLine)
  832.     SysFreeString(bstrLine);
  833.  
  834.   return hr;
  835. }
  836.  
  837.  
  838. //---------------------------------------------------------------------------
  839. // 
  840. //---------------------------------------------------------------------------
  841. STDMETHODIMP CGame::OnEnterScript
  842. (
  843.   void 
  844. )
  845. {
  846.   // No need to do anything
  847.   return S_OK;
  848. }
  849.  
  850.  
  851. //---------------------------------------------------------------------------
  852. // 
  853. //---------------------------------------------------------------------------
  854. STDMETHODIMP CGame::OnLeaveScript
  855. (
  856.   void 
  857. )
  858. {
  859.   // No need to do anything
  860.   return S_OK;
  861. }
  862.  
  863.  
  864.  
  865. //***************************************************************************
  866. // IActiveScriptSiteWindow Interface
  867. //***************************************************************************
  868.  
  869. //---------------------------------------------------------------------------
  870. // 
  871. //---------------------------------------------------------------------------
  872. STDMETHODIMP CGame::GetWindow
  873. (
  874.   HWND *phwndOut
  875. )
  876. {
  877.   if (!phwndOut)
  878.     return E_INVALIDARG;
  879.   *phwndOut = m_hwndDlg;
  880.   return S_OK;
  881. }
  882.  
  883.  
  884. //---------------------------------------------------------------------------
  885. // 
  886. //---------------------------------------------------------------------------
  887. STDMETHODIMP CGame::EnableModeless
  888. (
  889.   BOOL fEnable
  890. )
  891. {
  892.   if (fEnable)
  893.     m_pcm->FOnComponentExitState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL);
  894.   else
  895.     m_pcm->OnComponentEnterState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL, NULL);
  896.   return S_OK;
  897. }
  898. // #####  END  ACTIVEX SCRIPTING SUPPORT #####
  899.  
  900.  
  901. //***************************************************************************
  902. // Misc WndProc-related Methods
  903. //***************************************************************************
  904.  
  905. //---------------------------------------------------------------------------
  906. //
  907. //---------------------------------------------------------------------------
  908. BOOL AppEvt_DlgProc
  909. (
  910.   HWND   hwnd,
  911.   UINT   msg,
  912.   WPARAM wp,
  913.   LPARAM lp
  914. )
  915. {
  916.   if (!g_pgame)
  917.     return FALSE;
  918.  
  919.   return g_pgame->DlgProc(hwnd, msg, wp, lp);
  920. }
  921.  
  922.  
  923. //---------------------------------------------------------------------------
  924. //
  925. //---------------------------------------------------------------------------
  926. BOOL CGame::DlgProc
  927. (
  928.   HWND   hwnd,
  929.   UINT   msg,
  930.   WPARAM wp,
  931.   LPARAM lp
  932. )
  933. {
  934.   switch (msg)
  935.     {
  936.     case WM_ERASEBKGND:
  937.       if (m_pscore)
  938.         {
  939.         m_pscore->Paint((HDC)wp);
  940.         return TRUE;
  941.         }
  942.       break;
  943.     }
  944.   return FALSE;
  945. }
  946.  
  947.  
  948. //---------------------------------------------------------------------------
  949. //
  950. //---------------------------------------------------------------------------
  951. LRESULT AppEvt_PSWndProc
  952. (
  953.   HWND   hwnd,
  954.   UINT   msg,
  955.   WPARAM wp,
  956.   LPARAM lp
  957. )
  958. {
  959.   if (!g_pgame)
  960.     return DefWindowProc(hwnd, msg, wp, lp);
  961.  
  962.   return g_pgame->PSWndProc(hwnd, msg, wp, lp);
  963. }
  964.  
  965.  
  966. //---------------------------------------------------------------------------
  967. //
  968. //---------------------------------------------------------------------------
  969. LRESULT CGame::PSWndProc
  970. (
  971.   HWND   hwnd,
  972.   UINT   msg,
  973.   WPARAM wp,
  974.   LPARAM lp
  975. )
  976. {
  977.   switch (msg)
  978.     {
  979.     case WM_PAINT:
  980.       if (m_pdisp)
  981.         {
  982.         if (wp)
  983.           m_pdisp->Paint((HDC)wp);
  984.         else
  985.           {
  986.           PAINTSTRUCT ps;
  987.  
  988.           BeginPaint(hwnd, &ps);
  989.           m_pdisp->Paint(ps.hdc);
  990.           EndPaint(hwnd, &ps);
  991.           }
  992.         return 1L;
  993.         }
  994.       break;
  995.  
  996.     case WM_ERASEBKGND:
  997.       SelectObject((HDC)wp, (HGDIOBJ)(m_pdisp->m_hbrushBack ? (HBRUSH)(m_pdisp->m_hbrushBack) : (HBRUSH)g_hbrushStock));
  998.       PatBlt((HDC)wp, 0, 0, 32000, 32000, PATCOPY);
  999.       SelectObject((HDC)wp, g_hbrushStock);
  1000.       return TRUE;
  1001.  
  1002.     case WM_SIZE:
  1003.       {
  1004.       RECT rect;
  1005.  
  1006.       GetClientRect(hwnd, &rect);
  1007.       m_pdisp->m_cx = rect.right;
  1008.       m_pdisp->m_cy = rect.bottom;
  1009.       break;
  1010.       }
  1011.  
  1012.     case WM_TIMER:
  1013.       {
  1014.       if (m_fGameOver)
  1015.         break;
  1016.  
  1017.       m_pdisp->Timer();
  1018.  
  1019.       if (m_fPaused)
  1020.         break;
  1021.  
  1022.       if (m_fShipRestart)
  1023.         {
  1024.         m_pdisp->Refresh();
  1025.         break;
  1026.         }
  1027.  
  1028.       if (!m_fShipDead)
  1029.         {
  1030.         static cRefresh = 0;
  1031.  
  1032.         m_pgameoa->FireTick();
  1033.         if (++cRefresh > 5)          // What's a reasonable number?
  1034.           {
  1035.           m_pdisp->Refresh();
  1036.           cRefresh = 0;
  1037.           }
  1038.         }
  1039.       else
  1040.         {
  1041.         m_pscore->ShipKilled();
  1042.         InvalidateRect(m_hwndDlg, NULL, TRUE);
  1043.         if (m_pscore->GetCShip() <= 0)
  1044.           {
  1045.           this->GameOver();
  1046.           break;
  1047.           }
  1048.  
  1049.         m_fShipDead = FALSE;
  1050.         m_fShipRestart = TRUE;
  1051.         InvalidateRect(hwnd, NULL, TRUE);
  1052.         }
  1053.       break;
  1054.       }
  1055.  
  1056.     case WM_KEYDOWN:
  1057.       m_pgameoa->FireKeyDown(wp);
  1058.       break;
  1059.  
  1060.     case WM_CHAR:
  1061.       m_pgameoa->FireKeyPress(wp);
  1062.       break;
  1063.  
  1064.     case WM_KEYUP:
  1065.       m_pgameoa->FireKeyUp(wp);
  1066.       break;
  1067.  
  1068.     case WM_MOUSEMOVE:
  1069.       m_pgameoa->FireMouseMove(LOWORD(lp), HIWORD(lp), wp);
  1070.       break;
  1071.  
  1072.     case WM_LBUTTONDOWN:
  1073.       m_pgameoa->FireMouseDown(LOWORD(lp), HIWORD(lp), wp, MK_LBUTTON);
  1074.       break;
  1075.  
  1076.     case WM_RBUTTONDOWN:
  1077.       m_pgameoa->FireMouseDown(LOWORD(lp), HIWORD(lp), wp, MK_RBUTTON);
  1078.       break;
  1079.  
  1080.     case WM_MBUTTONDOWN:
  1081.       m_pgameoa->FireMouseDown(LOWORD(lp), HIWORD(lp), wp, MK_MBUTTON);
  1082.       break;
  1083.  
  1084.     case WM_LBUTTONUP:
  1085.       m_pgameoa->FireMouseUp(LOWORD(lp), HIWORD(lp), wp, MK_LBUTTON);
  1086.       break;
  1087.  
  1088.     case WM_RBUTTONUP:
  1089.       m_pgameoa->FireMouseUp(LOWORD(lp), HIWORD(lp), wp, MK_RBUTTON);
  1090.       break;
  1091.  
  1092.     case WM_MBUTTONUP:
  1093.       m_pgameoa->FireMouseUp(LOWORD(lp), HIWORD(lp), wp, MK_MBUTTON);
  1094.       break;
  1095.     }
  1096.  
  1097.   return DefWindowProc(hwnd, msg, wp, lp);
  1098. }
  1099.  
  1100.  
  1101. //---------------------------------------------------------------------------
  1102. //
  1103. //---------------------------------------------------------------------------
  1104. LRESULT CALLBACK ScriptErrorDialog
  1105. (
  1106.   HWND   hwnd,
  1107.   UINT   msg,
  1108.   WPARAM wp,
  1109.   LPARAM lp
  1110. )
  1111. {
  1112.   LPCSTR pszError;
  1113.  
  1114.   switch (msg) 
  1115.     {
  1116.     case WM_INITDIALOG:
  1117.       pszError = (LPCSTR)lp;
  1118.       ShowWindow(hwnd, SW_HIDE);
  1119.       SendDlgItemMessage(hwnd, ID_CTL_ERROR, WM_SETFONT,
  1120.                          (WPARAM)GetStockObject(ANSI_FIXED_FONT), MAKELPARAM(FALSE,0));
  1121.       SendDlgItemMessage(hwnd, ID_CTL_ERROR, WM_SETTEXT, 0, (LPARAM)pszError);
  1122.       ShowWindow(hwnd, SW_SHOW);
  1123.       return (TRUE);
  1124.  
  1125.      case WM_COMMAND:
  1126.        switch(LOWORD(wp))
  1127.          {
  1128.          case IDOK:
  1129.          case IDCANCEL:
  1130.            goto Destroy;
  1131.          }
  1132.        break;
  1133.     }
  1134.   return FALSE;
  1135.  
  1136. Destroy:
  1137.   EndDialog(hwnd, 0);
  1138.   return TRUE;
  1139. }
  1140.  
  1141.  
  1142. //---------------------------------------------------------------------------
  1143. //
  1144. //---------------------------------------------------------------------------
  1145. int DisplayScriptError
  1146. (
  1147.   HINSTANCE hinst,
  1148.   HWND      hwndParent,
  1149.   LPCSTR    pszError,
  1150.   int       ichError
  1151. )
  1152. {
  1153.   int   result;
  1154.   UINT  len = lstrlen(pszError);
  1155.   UINT  newlen;
  1156.   UINT  newindex;
  1157.   UINT  i;
  1158.   LPSTR pszNewError;
  1159.  
  1160.   // Figure out how long the real string will be
  1161.   newlen = 0;
  1162.   for (i=0; i<len; i++)
  1163.     {
  1164.     CHAR c = pszError[i];
  1165.  
  1166.     if (c == '\n')
  1167.       newlen +=1;               // Convert \n to \r\n
  1168.     else if (c == '\r')
  1169.       {
  1170.       if (pszError[i+1] == '\n')
  1171.         {
  1172.         newlen++;               // Leave \r\n alone
  1173.         i++;
  1174.         }
  1175.       else
  1176.         newlen++;               // Convert \r to \r\n
  1177.       }
  1178.     newlen++;
  1179.     }
  1180.  
  1181.   // Create the real string:
  1182.   pszNewError = new char[newlen+1];
  1183.   if (!pszNewError)
  1184.     return -1;
  1185.  
  1186.   newindex = 0;
  1187.   for (i=0; i<len; i++)
  1188.     {
  1189.     CHAR c = pszError[i];
  1190.  
  1191.     if (c == '\n')
  1192.       pszNewError[newindex++] = '\r';             // Convert \n to \r\n
  1193.     else if (c == '\r')
  1194.       {
  1195.       if (pszError[i+1] == '\n')
  1196.         {
  1197.         pszNewError[newindex++] = pszError[i++];  // Leave \r\n alone
  1198.         i++;
  1199.         }
  1200.       else
  1201.         {
  1202.         pszNewError[newindex++] = c;              // Convert \r to \r\n
  1203.         c = '\n';
  1204.         }
  1205.       }
  1206.     pszNewError[newindex++] = c;
  1207.     }
  1208.   pszNewError[newindex] = '\0';
  1209.  
  1210.   // Create the dialog box
  1211.   g_pgame->m_pcm->OnComponentEnterState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL, NULL);
  1212.   g_pgame->Pause(1);
  1213.   result = DialogBoxParam(
  1214.       hinst,                         // Handle to application instance
  1215.       MAKEINTRESOURCE(ID_DLG_ERROR), // Identifies dialog box template name  
  1216.       hwndParent,                    // Handle to owner window
  1217.       (DLGPROC)ScriptErrorDialog,    // Pointer to dialog box procedure
  1218.       (DWORD)pszNewError);           // Context
  1219.   g_pgame->m_pcm->FOnComponentExitState(g_papp->m_idcomp, cmgrstateModal, cmgrcontextAll, 0, NULL);
  1220.   SetFocus(g_pgame->m_hwndPS);
  1221.  
  1222.   delete[] pszNewError;
  1223.  
  1224.   return result;
  1225. }
  1226.  
  1227.  
  1228. //***************************************************************************
  1229. // Misc General Methods
  1230. //***************************************************************************
  1231.  
  1232. //---------------------------------------------------------------------------
  1233. // New level
  1234. //---------------------------------------------------------------------------
  1235. void CGame::NewLevel
  1236. (
  1237.   void
  1238. )
  1239. {
  1240.   g_pgame->m_pdisp->DestroyAll();
  1241.   m_pscore->NextLevel();
  1242.   m_fShipRestart = TRUE;
  1243.   InvalidateRect(m_hwndPS,  NULL, TRUE);
  1244.   InvalidateRect(m_hwndDlg, NULL, TRUE);
  1245.   m_pgameoa->FireNewLevel();
  1246. }
  1247.  
  1248.  
  1249. //---------------------------------------------------------------------------
  1250. //
  1251. //---------------------------------------------------------------------------
  1252. void AppEvt_NewGame
  1253. (
  1254.   void
  1255. )
  1256. {
  1257.   g_pgame->NewGame();
  1258. }
  1259.  
  1260.  
  1261. //---------------------------------------------------------------------------
  1262. //
  1263. //---------------------------------------------------------------------------
  1264. void CGame::NewGame
  1265. (
  1266.   void
  1267. )
  1268. {
  1269.   m_pdisp->DestroyAll();
  1270.   m_pscore->NewGame();
  1271.   m_fGameOver    = FALSE;
  1272.   m_fShipRestart = TRUE;
  1273.   m_pgameoa->FireNewGame();
  1274. }
  1275.  
  1276.  
  1277. //---------------------------------------------------------------------------
  1278. //
  1279. //---------------------------------------------------------------------------
  1280. BOOL AppEvt_Pause
  1281. (
  1282.   int pause
  1283. )
  1284. {
  1285.   return g_pgame->Pause(pause);
  1286. }
  1287.  
  1288.  
  1289. //---------------------------------------------------------------------------
  1290. //
  1291. //---------------------------------------------------------------------------
  1292. BOOL CGame::Pause
  1293. (
  1294.   int pause
  1295. )
  1296. {
  1297.   if (pause == -1)            // Toggle
  1298.     pause = !m_fPaused;
  1299.  
  1300.   switch (pause)
  1301.     {
  1302.     case 1:                   // Pause
  1303.       if (m_fGameOver)
  1304.         goto UnPause;
  1305.       if (g_mode != MODE_PLAYBACK)
  1306.         KillTimer(m_hwndPS, 0);
  1307.       m_fPaused = TRUE;
  1308.       break;
  1309.  
  1310.     case 0:                   // UnPause
  1311. UnPause:
  1312.       if (g_mode != MODE_PLAYBACK)
  1313.         SetTimer(m_hwndPS, 0, 40, NULL);
  1314.       m_fPaused = FALSE;
  1315.       break;
  1316.     }
  1317.  
  1318.   if (m_fPaused)
  1319.     m_pscore->SetStatusText("Game Paused.  Press F3 to Continue.");
  1320.   else
  1321.     m_pscore->SetStatusText("");
  1322.  
  1323.   return m_fPaused;
  1324. }
  1325.  
  1326.  
  1327. //---------------------------------------------------------------------------
  1328. //
  1329. //---------------------------------------------------------------------------
  1330. BOOL AppEvt_FQueryTerminate
  1331. (
  1332.   BOOL fPromptUser
  1333. )
  1334. {
  1335.   return g_pgame->FQueryTerminate(fPromptUser);
  1336. }
  1337.  
  1338.  
  1339. //---------------------------------------------------------------------------
  1340. //
  1341. //---------------------------------------------------------------------------
  1342. BOOL CGame::FQueryTerminate
  1343. (
  1344.   BOOL fPromptUser
  1345. )
  1346. {
  1347.   // UNDONE
  1348.   return TRUE;
  1349. }
  1350.  
  1351.  
  1352. //---------------------------------------------------------------------------
  1353. //
  1354. //---------------------------------------------------------------------------
  1355. void CGame::GameOver
  1356. (
  1357.   void
  1358. )
  1359. {
  1360.   m_fGameOver = TRUE;
  1361.   InvalidateRect(m_hwndPS, NULL, TRUE);
  1362.   m_pscore->SetStatusText("Game Over.  Press F2 to Play a New Game.");
  1363. }
  1364.  
  1365.  
  1366. // ##### BEGIN ACTIVEX SCRIPTING SUPPORT #####
  1367. //---------------------------------------------------------------------------
  1368. //
  1369. //---------------------------------------------------------------------------
  1370. HRESULT CGame::CreateScriptEngine
  1371. (
  1372.   LPCOLESTR pstrItemName
  1373. )
  1374. {
  1375.   HRESULT hr;
  1376.  
  1377.   if (m_ps)
  1378.     return S_FALSE;   // Already created it
  1379.  
  1380.   // Create the ActiveX Scripting Engine
  1381.   hr = CoCreateInstance(m_clsidEngine, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void **)&m_ps);
  1382.   if (hr)
  1383.     {
  1384.     s_pszError = "Creating the ActiveX Scripting engine failed.  Scripting engine is probably not correctly registered or CLSID incorrect.";
  1385.     return E_FAIL;
  1386.     }
  1387.   // Script Engine must support IActiveScriptParse for us to use it
  1388.   hr = m_ps->QueryInterface(IID_IActiveScriptParse, (void **)&m_psp);
  1389.   if (hr)
  1390.     {
  1391.     s_pszError = "ActiveX Scripting engine does not support IActiveScriptParse";
  1392.     return hr;
  1393.     }
  1394.   hr = m_ps->SetScriptSite(this);
  1395.   if (hr)
  1396.     return hr;
  1397.   // InitNew the object:
  1398.   hr = m_psp->InitNew();
  1399.   if (hr)
  1400.     return hr;
  1401.   hr = m_ps->AddNamedItem(L"Game", SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE);
  1402.   return hr;
  1403. }
  1404. // #####  END  ACTIVEX SCRIPTING SUPPORT #####
  1405.  
  1406.  
  1407.  
  1408. //***************************************************************************
  1409. // Parsing support
  1410. //***************************************************************************
  1411.  
  1412. //---------------------------------------------------------------------------
  1413. // Skip white space, counting lines.  Treat \r & \n as white space only if
  1414. // fSkipNewLines is TRUE.
  1415. //---------------------------------------------------------------------------
  1416. void SkipWhite
  1417. (
  1418.   char **ppsz,
  1419.   BOOL   fSkipNewLines
  1420. )
  1421. {
  1422.   // Skip white space
  1423.   while (**ppsz && **ppsz<=' ')
  1424.     {
  1425.     if (**ppsz == '\r' || **ppsz == '\n')
  1426.       {
  1427.       if (!fSkipNewLines)
  1428.         return;
  1429.       if (**ppsz == '\r' && (*ppsz)[1] == '\n')
  1430.         ++*ppsz;
  1431.       g_clineOffset++;
  1432.       }
  1433.     ++*ppsz;
  1434.     }
  1435. }
  1436.  
  1437.  
  1438. //---------------------------------------------------------------------------
  1439. // Finds $OBJECT, $ENGINE, $INCLUDE, etc, parses past '=' to argument.  NULL
  1440. // terminates the argument, then returns a ptr to begining of arg & to beg
  1441. // of next line.
  1442. //---------------------------------------------------------------------------
  1443. struct
  1444.   {
  1445.   int   cch;
  1446.   char *psz;
  1447.   } g_rgtoken[] = 
  1448.     {
  1449.       {7, "$ENGINE"},
  1450.       {7, "$OBJECT"},
  1451.       {8, "$INCLUDE"},
  1452.       {0, ""},
  1453.     };
  1454.  
  1455. int FindToken
  1456. (
  1457.   char    *pszCur,
  1458.   char   **ppszBeginArg,
  1459.   char   **ppszNextLine,
  1460.   HRESULT *phr,
  1461.   char   **ppszError
  1462. )
  1463. {
  1464.   char chQuote = 0;
  1465.   char ch;
  1466.  
  1467.   *phr = S_OK;
  1468.   SkipWhite(&pszCur, TRUE);
  1469.   if (*pszCur != '$')
  1470.     {
  1471.     *ppszNextLine = pszCur;
  1472.     return 0;   // No token found
  1473.     }
  1474.  
  1475.   for (int i=0; g_rgtoken[i].cch; i++)
  1476.     {
  1477.     if (!strncmp(pszCur, g_rgtoken[i].psz, g_rgtoken[i].cch))
  1478.       {
  1479.       pszCur += g_rgtoken[i].cch;
  1480.       SkipWhite(&pszCur, FALSE);
  1481.       if (*pszCur != '=')
  1482.         {
  1483.         *ppszError = "Missing '=' on $ENGINE, $OBJECT, or $INCLUDE line";
  1484.         *phr = E_FAIL;
  1485.         return 0;
  1486.         }
  1487.       pszCur++;
  1488.       SkipWhite(&pszCur, FALSE);
  1489.       if (*pszCur <= ' ')
  1490.         {
  1491.         *ppszError = "Missing argument on $ENGINE, $OBJECT, or $INCLUDE line";
  1492.         *phr = E_FAIL;
  1493.         return 0;
  1494.         }
  1495.       if (*pszCur=='"' || *pszCur=='\'' || *pszCur=='<')
  1496.         {
  1497.         chQuote = *pszCur;
  1498.         if (chQuote == '<')
  1499.           chQuote = '>';
  1500.         pszCur++;
  1501.         }
  1502.       *ppszBeginArg = pszCur;
  1503.       if (chQuote)
  1504.         {
  1505.         // Look for End of String, EOL, or End of Quote
  1506.         while (*pszCur && *pszCur!='\n' && *pszCur!='\r' && *pszCur!=chQuote)
  1507.           pszCur++;
  1508.         }
  1509.       else
  1510.         {
  1511.         // Skip non-white space
  1512.         while (*pszCur > ' ')
  1513.           pszCur++;
  1514.         }
  1515.       ch = *pszCur;
  1516.       *pszCur = 0;
  1517. NextChar:
  1518.       switch (ch)
  1519.         {
  1520.         default:
  1521.           // Look for EOL
  1522.           pszCur++;
  1523.           ch = *pszCur;
  1524.           goto NextChar;
  1525.  
  1526.         case '\r':
  1527.           // Skip the cr we're at
  1528.           g_clineOffset++;
  1529.           pszCur++;
  1530.           if (*pszCur == '\n')
  1531.             pszCur++;
  1532.           break;
  1533.  
  1534.         case '\n':
  1535.           // Skip the newline we're at
  1536.           g_clineOffset++;
  1537.           pszCur++;
  1538.           break;
  1539.  
  1540.         case 0:
  1541.            break;
  1542.         }
  1543.  
  1544.       *ppszNextLine = pszCur;
  1545.       return i+1;
  1546.       }
  1547.     }
  1548.  
  1549.   *ppszError = "unrecognized token; must be $ENGINE, $OBJECT, or $INCLUDE";
  1550.   *phr = E_FAIL;
  1551.   return 0;
  1552. }
  1553.  
  1554.  
  1555. //---------------------------------------------------------------------------
  1556. //
  1557. //---------------------------------------------------------------------------
  1558. HRESULT CGame::ParseFile
  1559. (
  1560.   char     *pszFileName,
  1561.   LPCOLESTR pstrItemName
  1562. )
  1563. {
  1564.   struct _stat stat;
  1565.   size_t       cch;
  1566.   EXCEPINFO    ei;
  1567.   char        *pszT;
  1568.   char        *pszAlloc;
  1569.   FILE        *pfile;
  1570.   HRESULT      hr = S_OK;
  1571.   int          tk = 0;
  1572.   char        *pszArg;
  1573.  
  1574.   // Find the length of the file
  1575.   if (_stat(pszFileName, &stat))
  1576.     return E_FAIL;
  1577.   cch = stat.st_size;
  1578.  
  1579.   // Allocate a buffer to read the file
  1580.   pszAlloc = new char[cch+1];
  1581.   if (!pszAlloc)
  1582.     return E_OUTOFMEMORY;
  1583.   memset(pszAlloc, 0, cch);   // HACK: Since cch may be too large, zero-fill string
  1584.  
  1585.   // Open & read the file
  1586.   pfile = fopen(pszFileName, "rb");
  1587.   if (!pfile)
  1588.     {
  1589.     s_pszError = "Bad file name";
  1590.     hr = E_FAIL;
  1591.     goto Error;
  1592.     }
  1593.   fread(pszAlloc, cch, 1, pfile);
  1594.   fclose(pfile);
  1595.  
  1596.   // Parse lines begining w/$
  1597.   pszAlloc[cch] = 0;
  1598.   pszT = pszAlloc;
  1599.   while (tk=FindToken(pszT, &pszArg, &pszT, &hr, &s_pszError))
  1600.     {
  1601.     switch (tk)
  1602.       {
  1603.       case 1:   // $ENGINE
  1604.         {
  1605.         MAKE_WIDEPTR_FROMANSI(pwszCLSID, pszArg);
  1606.         hr = CLSIDFromString(pwszCLSID, &m_clsidEngine);
  1607.         if (hr)
  1608.           {
  1609.           s_pszError = "Bad $ENGINE={xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} syntax";
  1610.           goto Error;
  1611.           }
  1612.         hr = this->CreateScriptEngine(pstrItemName);
  1613.         if (hr == S_FALSE)
  1614.           {
  1615.           s_pszError = "$ENGINE must be first line; Script Engine already created.";
  1616.           goto Error;
  1617.           }
  1618.         else if (hr)
  1619.           goto Error;
  1620.         break;
  1621.         }
  1622.  
  1623.       case 2:  // $OBJECT
  1624.         if (m_csubobj >= csubobjMAX)
  1625.           {
  1626.           s_pszError = "Too many $OBJECT lines";
  1627.           goto Error;
  1628.           }
  1629.  
  1630.         m_rgpwszSubObjs[m_csubobj] = new WCHAR [strlen(pszArg)+1];
  1631.         if (!m_rgpwszSubObjs[m_csubobj])
  1632.           {
  1633.           s_pszError = "Out Of Memory";
  1634.           goto Error;
  1635.           }
  1636.         UNICODE_FROM_ANSI(m_rgpwszSubObjs[m_csubobj], pszArg, 2*strlen(pszArg));
  1637.         m_rgpdispSubObjs[m_csubobj] = NULL;
  1638.         m_rgpsc[m_csubobj] = NULL;
  1639.         m_csubobj++;
  1640.         break;
  1641.  
  1642.       case 3:   // $INCLUDE
  1643.         hr = this->ParseFile(pszArg, pstrItemName);
  1644.         if (hr)
  1645.           goto Error;
  1646.         break;
  1647.       }
  1648.     }
  1649.  
  1650.   // If there's anything left, assume it's code
  1651.   if (*pszT)
  1652.     {
  1653. // ##### BEGIN ACTIVEX SCRIPTING SUPPORT #####
  1654.     // Make sure we've created the scripting engine
  1655.     if (!m_ps)
  1656.       {
  1657.       hr = this->CreateScriptEngine(pstrItemName);
  1658.       if (hr)
  1659.         goto Error;
  1660.       }
  1661.  
  1662.     // Hand it the code
  1663.     MAKE_WIDEPTR_FROMANSI(pwszCode, pszT);
  1664.     hr = m_psp->ParseScriptText(pwszCode, pstrItemName, NULL, NULL, 0, 0, 0L, NULL, &ei);
  1665.     hr = S_OK;    // Ignore parse errors, so user can press F9 to view source...
  1666. // #####  END  ACTIVEX SCRIPTING SUPPORT #####
  1667.     }
  1668.  
  1669. Error:
  1670.   delete pszAlloc;
  1671.   return hr;
  1672. }
  1673.  
  1674.  
  1675.  
  1676. //***************************************************************************
  1677. // Dynamic object model support
  1678. //***************************************************************************
  1679.  
  1680. //---------------------------------------------------------------------------
  1681. // Builds the typeinfo for the container object from the list of property 
  1682. // objects.
  1683. //---------------------------------------------------------------------------
  1684. HRESULT CGame::BuildTypeInfo
  1685. (
  1686.   void
  1687. )
  1688. {
  1689.   static GUID guidStdOle = {0x00020430,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46};
  1690.   ITypeLib*        ptlStdOle   = NULL;
  1691.   ITypeInfo*       ptinfoIDisp = NULL;
  1692.   ICreateTypeLib * pcreatetl   = NULL;
  1693.   ICreateTypeInfo* pctiCoClass = NULL;        // For creating the CoClass
  1694.   ICreateTypeInfo* pctiProps   = NULL;        // For creating the Primary (Property) Dispinterface
  1695.   FUNCDESC         funcdesc    = {0};
  1696.   TYPEDESC         tdescUser   = {0};
  1697.   ELEMDESC         edArg       = {0};
  1698.   HREFTYPE         hreftype;
  1699.   int              index;
  1700.   int              i;
  1701.   HRESULT          hr;
  1702.  
  1703.   if (g_ptinfoIntGame && g_ptinfoClsGame)
  1704.     return S_OK;
  1705.  
  1706.   // Create TypeLib
  1707.   CHECKSZ(CreateTypeLib(SYS_WIN32, L"c:\\SprdSubO.tlb" /* szFile */, &pcreatetl), "CreateTypeLib FAILED");
  1708.  
  1709.   // Misc. global props of the TypeLib
  1710.   CHECKSZ(pcreatetl->SetGuid(m_libidSubObj), "TL SetGuid FAILED");
  1711.   CHECKSZ(pcreatetl->SetVersion(1, 0), "TL SetVersion FAILED");
  1712.   CHECKSZ(pcreatetl->SetName(L"Sprds"), "TL SetName FAILED");
  1713.   CHECKSZ(pcreatetl->SetLcid(LOCALE_SYSTEM_DEFAULT), "TL SetLcid FAILED");
  1714.  
  1715.   // Get Information on IDispatch
  1716.   CHECKSZ(LoadRegTypeLib(guidStdOle, STDOLE_MAJORVERNUM, STDOLE_MINORVERNUM, STDOLE_LCID, &ptlStdOle), "LoadRegTypeLib FAILED");
  1717.   CHECKSZ(ptlStdOle->GetTypeInfoOfGuid(IID_IDispatch, &ptinfoIDisp), "GetTypeInfoOfGuid (IID_IDispatch) FAILED");
  1718.  
  1719.   // Create TypeInfo
  1720.   CHECKSZ(pcreatetl->CreateTypeInfo(L"GameSubObjs", TKIND_DISPATCH, &pctiProps), "Create TI FAILED");
  1721.   CHECKSZ(pctiProps->SetGuid(m_iidSubObj), "cti SetGuid FAILED");
  1722.   CHECKSZ(pctiProps->SetVersion(1, 0), "cti SetVersion FAILED");
  1723.   CHECKSZ(pctiProps->AddRefTypeInfo(ptinfoIDisp, &hreftype), "cti AddRefTypeInfoo FAILED");     // Reference StdOLE
  1724.   CHECKSZ(pctiProps->AddImplType(0, hreftype), "cti AddImplType FAILED");
  1725.  
  1726.   funcdesc.funckind = FUNC_DISPATCH;
  1727.   funcdesc.invkind  = INVOKE_PROPERTYGET;
  1728.   funcdesc.callconv = CC_STDCALL;
  1729.   funcdesc.cScodes  = -1;
  1730.   funcdesc.elemdescFunc.tdesc.vt = VT_PTR;
  1731.   funcdesc.elemdescFunc.tdesc.lptdesc = &tdescUser;
  1732.   tdescUser.vt = VT_USERDEFINED;
  1733.  
  1734.   // Loop through all of the SpriteClasses ($OBJECTs) in this game, adding a
  1735.   // property to pctiProps which corresponds to the control.
  1736.   index = 0;
  1737.   for (i=0; i<m_csubobj; i++)
  1738.     {
  1739.     // Need to make sure this starts out cleared
  1740.     if (!g_ptinfoClsSpriteClass)
  1741.       {
  1742.       CHECKCL(LoadTypeInfo(g_hinst, 0, 1, 0, 0x0409,
  1743.                            LIBID_SPRUUIDS, CLSID_SpriteClass, IID_ISpriteClass, FALSE,
  1744.                            &g_ptlMain, &g_ptinfoClsSpriteClass, &g_ptinfoIntSpriteClass));
  1745.       }
  1746.     CHECKCL(pctiProps->AddRefTypeInfo(g_ptinfoClsSpriteClass, &tdescUser.hreftype));
  1747.     funcdesc.memid = 0x80010000 | i;
  1748.     funcdesc.wFuncFlags = FUNCFLAG_FSOURCE;
  1749.  
  1750.     CHECKCL(pctiProps->AddFuncDesc(index, &funcdesc));
  1751.     CHECKCL(pctiProps->SetFuncAndParamNames(index, &m_rgpwszSubObjs[i], 1));
  1752.  
  1753.     index++;
  1754.     continue;
  1755.  
  1756. CheckLoop:
  1757.     // Do any clean up here
  1758.  
  1759.     CHECKSZ(hr,"BuildTypeInfo FAILED");
  1760.     break;
  1761.     }
  1762.  
  1763.   // Finish off the TI for the Props
  1764.   CHECKSZ(pctiProps->LayOut(), "BuildTypeInfo FAILED");
  1765.   CHECKSZ(pctiProps->QueryInterface(IID_ITypeInfo, (void **)&g_ptinfoIntGame), "BuildTypeInfo FAILED");
  1766.  
  1767.   // Now we have to create a coclass for the interface
  1768.   CHECKSZ(pcreatetl->CreateTypeInfo(L"Game", TKIND_COCLASS, &pctiCoClass), "BuildTypeInfo FAILED");
  1769.   CHECKSZ(pctiCoClass->SetGuid(m_clsidSubObj), "BuildTypeInfo FAILED");
  1770.   CHECKSZ(pctiCoClass->SetVersion(1, 0), "BuildTypeInfo FAILED");
  1771.  
  1772.   // Add the Page Property dispinterface to coclass
  1773.   CHECKSZ(pctiCoClass->AddRefTypeInfo(g_ptinfoIntGame, &hreftype), "BuildTypeInfo FAILED");
  1774.   CHECKSZ(pctiCoClass->AddImplType(0, hreftype), "BuildTypeInfo FAILED");
  1775.   CHECKSZ(pctiCoClass->SetImplTypeFlags(0, IMPLTYPEFLAG_FDEFAULT), "BuildTypeInfo FAILED");
  1776.  
  1777.   // Finish off the CoClass
  1778.   CHECKSZ(pctiCoClass->LayOut(), "BuildTypeInfo FAILED");
  1779.   CHECKSZ(pctiCoClass->QueryInterface(IID_ITypeInfo, (void **)&g_ptinfoClsGame), "BuildTypeInfo FAILED");
  1780.  
  1781.   // Finish off the Library
  1782.   CHECKSZ(pcreatetl->QueryInterface(IID_ITypeLib, (void **)&g_ptlGameSubObj), "BuildTypeLib FAILED");
  1783.  
  1784. CleanUp:
  1785.   // Code to release refs aquired during page build.
  1786.   if (pctiCoClass)
  1787.     pctiCoClass->Release();
  1788.   if (pctiProps)
  1789.     pctiProps->Release();
  1790.   if (ptinfoIDisp)
  1791.     ptinfoIDisp->Release();
  1792.   if (ptlStdOle)
  1793.     ptlStdOle->Release();
  1794.   if (pcreatetl)
  1795.     pcreatetl->Release();
  1796.  
  1797.   return hr;
  1798. };
  1799.  
  1800. //--- EOF -------------------------------------------------------------------
  1801.