home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / mts4.cab / TServer_Human.cpp < prev    next >
C/C++ Source or Header  |  1997-11-14  |  21KB  |  851 lines

  1. // Filename: Human.cpp
  2. //
  3. // Description:  Implementation of CHuman
  4. // This file contains the code that handles the interaction between two
  5. // human players.
  6. //
  7. // This file is provided as part of the Microsoft Transaction Server Samples
  8. //
  9. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT 
  10. // WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, 
  11. // INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
  12. // OF MERCHANTABILITY AND/OR FITNESS FOR A  PARTICULAR 
  13. // PURPOSE.
  14. //
  15. // Copyright (C) 1997 Microsoft Corporation, All rights reserved
  16.  
  17. #include "stdafx.h"
  18. #include "tServer.h"
  19. #include "Human.h"
  20.  
  21. #include <mtx.h>
  22. #include <mtxspm.h>
  23.  
  24.  
  25. STDMETHODIMP CHuman::InterfaceSupportsErrorInfo(REFIID riid)
  26. {
  27.     static const IID* arr[] = 
  28.     {
  29.         &IID_IHuman,
  30.     };
  31.  
  32.     for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  33.     {
  34.         if (InlineIsEqualGUID(*arr[i],riid))
  35.             return S_OK;
  36.     }
  37.     return S_FALSE;
  38. }
  39.  
  40.  
  41. STDMETHODIMP CHuman::EnterNewGame (IN BSTR bstrLocalName, OUT VARIANT* pvGameID, OUT VARIANT* pvName,
  42.                                    OUT VARIANT* pvOrder) {
  43.     
  44.     HRESULT hr = S_OK;
  45.     
  46.     IObjectContext* pObjectContext = NULL;
  47.     
  48.     ISharedPropertyGroupManager* spmMgr = NULL;
  49.     ISharedPropertyGroup* spmGroup = NULL;
  50.     
  51.     ISharedProperty* spmPropCounter = NULL;
  52.     ISharedProperty* spmPropFirstName = NULL;
  53.     ISharedProperty* spmPropSecondName = NULL;
  54.     ISharedProperty* spmPropState = NULL;
  55.  
  56.     pvGameID->vt = VT_I4;
  57.     pvName->vt = VT_BSTR;
  58.     pvOrder->vt = VT_I4;
  59.  
  60.     long lGameID = 0;
  61.     long lOrder = 0;
  62.  
  63.     try {
  64.         
  65.         // Get the object context
  66.         THROW_ERR ( hr = GetObjectContext (&pObjectContext) );
  67.         if (pObjectContext == NULL) {
  68.             THROW_ERR ( E_FAIL );
  69.         }
  70.         
  71.         // Create the SharedPropertyGroupManager
  72.         THROW_ERR ( pObjectContext->CreateInstance (CLSID_SharedPropertyGroupManager, IID_ISharedPropertyGroupManager, (void**)&spmMgr) );
  73.         
  74.         // Create the SharedPropertyGroup
  75.         LONG lIsolationMode = LockMethod;
  76.         LONG lReleaseMode = Process;
  77.         VARIANT_BOOL bExists = VARIANT_FALSE;
  78.         THROW_ERR ( spmMgr->CreatePropertyGroup (L"TicTacToe", &lIsolationMode, &lReleaseMode, &bExists, &spmGroup) );
  79.  
  80.         // Create SharedProperties
  81.         CComVariant vCounter;
  82.  
  83.         THROW_ERR ( spmGroup->CreateProperty (L"Counter", &bExists, &spmPropCounter) );
  84.         THROW_ERR ( spmPropCounter->get_Value (&vCounter) );
  85.  
  86.         CComVariant vSecondName;
  87.         CComVariant vState;
  88.  
  89.         TCHAR szBuf [512];
  90.         BSTR bstrSecondName;
  91.         BSTR bstrFirstName;
  92.         BSTR bstrState;
  93.  
  94.         // Find first open two-human game
  95.         if (vCounter.lVal == 0) {
  96.             vCounter.lVal = 1;
  97.         } else {
  98.             long lScan = 1;
  99.             bool bFlag = false;
  100.             while (lScan < vCounter.lVal && !bFlag) {
  101.                 
  102.                 wsprintf (szBuf, _T("%dState"), lScan);
  103.                 bstrState = TCHAR2BSTR (szBuf);
  104.                 THROW_ERR ( spmGroup->CreateProperty (bstrState, &bExists, &spmPropState) );
  105.                 ::SysFreeString (bstrState);
  106.  
  107.                 THROW_ERR ( spmPropState->get_Value (&vState) );
  108.  
  109.                 if (vState.lVal < 2) {
  110.  
  111.                     // Found a game
  112.                     bFlag = true;
  113.                 } else
  114.                     lScan ++;
  115.  
  116.                 THROW_ERR ( spmPropState->Release() );
  117.             }
  118.  
  119.             vCounter.lVal = lGameID = lScan;
  120.         }
  121.  
  122.         wsprintf (szBuf, _T("%dSecondName"), vCounter.lVal);
  123.         bstrSecondName = TCHAR2BSTR (szBuf);
  124.         wsprintf (szBuf, _T("%dState"), vCounter.lVal);
  125.         bstrState = TCHAR2BSTR (szBuf);
  126.         wsprintf (szBuf, _T("%dFirstName"), vCounter.lVal);
  127.         bstrFirstName = TCHAR2BSTR (szBuf);
  128.  
  129.         THROW_ERR ( spmGroup->CreateProperty (bstrFirstName, &bExists, &spmPropFirstName) );
  130.         THROW_ERR ( spmGroup->CreateProperty (bstrSecondName, &bExists, &spmPropSecondName) );
  131.         THROW_ERR ( spmGroup->CreateProperty (bstrState, &bExists, &spmPropState) );
  132.  
  133.         ::SysFreeString (bstrFirstName);
  134.         ::SysFreeString (bstrSecondName);
  135.         ::SysFreeString (bstrState);
  136.  
  137.         // Get current state
  138.         THROW_ERR ( spmPropState->get_Value (&vState) );
  139.  
  140.         // State table
  141.         // ===========
  142.         // 0 - No one in game
  143.         // 1 - One player lurking
  144.         // 2 - Second player joined
  145.         // 3 - First player's turn
  146.         // 4 - Second player's turn
  147.         
  148.         // Is this the first time this property has been accessed?
  149.         if (!bExists)
  150.             vState.lVal = 0;
  151.         
  152.         // Is there someone lurking already?
  153.         if (vState.lVal == 1) {
  154.             
  155.             CComVariant vFirstName;
  156.  
  157.             // Get opponent's name
  158.             THROW_ERR ( spmPropFirstName->get_Value (&vFirstName) );
  159.  
  160.             // Submit own name
  161.             CComVariant vSecondName2;
  162.             vSecondName2.vt = VT_BSTR;
  163.  
  164.             vSecondName2.bstrVal = ::SysAllocString (bstrLocalName);
  165.             THROW_ERR ( spmPropSecondName->put_Value (vSecondName2) );
  166.             ::SysFreeString (vSecondName2.bstrVal);
  167.  
  168.             // Update state
  169.             vState.lVal = 2;
  170.             THROW_ERR ( spmPropState->put_Value (vState) );
  171.  
  172.             // Assign gameID
  173.             lGameID = vCounter.lVal;
  174.  
  175.             // Initialize the game screen array
  176.             InitArray();
  177.             THROW_ERR ( SaveArray(lGameID) );
  178.  
  179.             // Prepare return values
  180.             pvName->bstrVal = ::SysAllocString (vFirstName.bstrVal);
  181.             pvOrder->lVal = 2;
  182.             pvGameID->lVal = lGameID;
  183.         
  184.         } else {
  185.             
  186.             CComVariant vFirstName;
  187.             vFirstName.vt = VT_BSTR;
  188.  
  189.             // Update first name
  190.             vFirstName.bstrVal = ::SysAllocString (bstrLocalName);
  191.             THROW_ERR ( spmPropFirstName->put_Value (vFirstName) );
  192.             ::SysFreeString (vFirstName.bstrVal);
  193.  
  194.             // Update counter for next game
  195.             vCounter.lVal = vCounter.lVal + 1;
  196.             THROW_ERR ( spmPropCounter->put_Value (vCounter) );
  197.  
  198.             // Update state
  199.             vState.lVal = 1;
  200.             THROW_ERR ( spmPropState->put_Value (vState) );
  201.  
  202.             // Assign gameID
  203.             lGameID = vCounter.lVal - 1;
  204.     
  205.             // Prepare return values
  206.             pvName->bstrVal = ::SysAllocString (L"No one");
  207.             pvOrder->lVal = 1;
  208.             pvGameID->lVal = lGameID;
  209.         }
  210.  
  211.         // We're finished and happy
  212.         pObjectContext->SetComplete();
  213.     
  214.     } catch (HRESULT hr) {
  215.         
  216.         // Create an ErrorInfo object
  217.         ICreateErrorInfo* pCreateErrInfo = NULL;
  218.         IErrorInfo* pErrInfo = NULL;
  219.         
  220.         CreateErrorInfo (&pCreateErrInfo);
  221.         pCreateErrInfo->QueryInterface (IID_IErrorInfo, (LPVOID FAR*) &pErrInfo);
  222.         
  223.         // Fill in error information
  224.         TCHAR szErr [512];
  225.         wsprintf (szErr, _T("Error %d occurred in Human::EnterNewGame()"), hr);
  226.         BSTR bstrDesc = TCHAR2BSTR (szErr);
  227.  
  228.         pCreateErrInfo->SetGUID (IID_IComputer);
  229.         pCreateErrInfo->SetSource (L"Computer");
  230.         pCreateErrInfo->SetDescription (bstrDesc);
  231.         ::SysFreeString (bstrDesc);
  232.         
  233.         // Confirm error information
  234.         SetErrorInfo (0, pErrInfo);
  235.         
  236.         // Clean up the error objects
  237.         if (pCreateErrInfo)
  238.             pCreateErrInfo->Release();
  239.         
  240.         if (pErrInfo)
  241.             pErrInfo->Release();
  242.         
  243.         // Indicate our unhappiness
  244.         if (pObjectContext)
  245.             pObjectContext->SetAbort();
  246.         
  247.         hr = E_FAIL;
  248.     }
  249.  
  250.     if (pObjectContext)
  251.         pObjectContext->Release();
  252.     
  253.     if (spmMgr)
  254.         spmMgr->Release();
  255.     
  256.     if (spmGroup)
  257.         spmGroup->Release();
  258.     
  259.     if (spmPropCounter)
  260.         spmPropCounter->Release();
  261.  
  262.     if (spmPropFirstName)
  263.         spmPropFirstName->Release();
  264.  
  265.     if (spmPropSecondName)
  266.         spmPropSecondName->Release();
  267.  
  268.     if (spmPropState)
  269.         spmPropState->Release();
  270.     
  271.     return hr;
  272. }
  273.  
  274.  
  275. STDMETHODIMP CHuman::NewMove (IN long lGameID, IN long lOrder, IN long lX, IN long lY, OUT VARIANT* pvWin) {
  276.  
  277.     // Win protocol
  278.     // ============
  279.     // 0  -> move did not end game
  280.     // 1  -> player won
  281.     // -1 -> remote player won (won't occur in this function)
  282.     // 2  -> player's move tied the game
  283.     // -2 -> remote player's move tied the game (won't occur in this function)
  284.  
  285.     HRESULT hr = S_OK;
  286.  
  287.     IObjectContext* pObjectContext = NULL;
  288.  
  289.     ISharedPropertyGroupManager* spmMgr = NULL;
  290.     ISharedPropertyGroup* spmGroup = NULL;
  291.     
  292.     ISharedProperty* spmPropState = NULL;
  293.     ISharedProperty* spmPropX = NULL;
  294.     ISharedProperty* spmPropY = NULL;
  295.     ISharedProperty* spmPropWin = NULL;
  296.  
  297.     pvWin->vt = VT_I4;
  298.  
  299.     long lWin = 0;
  300.  
  301.  
  302.     try {
  303.         
  304.         // Get the object context
  305.         THROW_ERR ( hr = GetObjectContext(&pObjectContext) );
  306.         if (pObjectContext == NULL) {
  307.             THROW_ERR ( E_FAIL );
  308.         }
  309.         
  310.         // Create the SharedPropertyGroupManager
  311.         THROW_ERR ( pObjectContext->CreateInstance (CLSID_SharedPropertyGroupManager, 
  312.             IID_ISharedPropertyGroupManager, (void**)&spmMgr) );
  313.         
  314.         // Create the SharedPropertyGroup
  315.         LONG lIsolationMode = LockMethod;
  316.         LONG lReleaseMode = Process;
  317.         VARIANT_BOOL bExists = VARIANT_FALSE;
  318.         THROW_ERR ( spmMgr->CreatePropertyGroup (L"TicTacToe", &lIsolationMode, &lReleaseMode,
  319.             &bExists, &spmGroup) );
  320.  
  321.         // Create SharedProperties
  322.         BSTR bstrState;
  323.         BSTR bstrX;
  324.         BSTR bstrY;
  325.         BSTR bstrWin;
  326.         TCHAR szBuf[512];
  327.         wsprintf (szBuf, _T("%dState"), lGameID);
  328.         bstrState = TCHAR2BSTR (szBuf);    
  329.         wsprintf (szBuf, _T("%dX"), lGameID);
  330.         bstrX = TCHAR2BSTR (szBuf);
  331.         wsprintf (szBuf, _T("%dY"), lGameID);
  332.         bstrY = TCHAR2BSTR (szBuf);
  333.         wsprintf (szBuf, _T("%dWin"), lGameID);
  334.         bstrWin = TCHAR2BSTR (szBuf);
  335.  
  336.         THROW_ERR ( spmGroup->CreateProperty (bstrState, &bExists, &spmPropState) );
  337.         THROW_ERR ( spmGroup->CreateProperty (bstrX, &bExists, &spmPropX) );
  338.         THROW_ERR ( spmGroup->CreateProperty (bstrY, &bExists, &spmPropY) );
  339.         THROW_ERR ( spmGroup->CreateProperty (bstrWin, &bExists, &spmPropWin) );
  340.  
  341.         ::SysFreeString (bstrState);
  342.         ::SysFreeString (bstrX);
  343.         ::SysFreeString (bstrY);
  344.         ::SysFreeString (bstrWin);
  345.  
  346.         CComVariant vState;
  347.         CComVariant vX;
  348.         CComVariant vY;
  349.         CComVariant vWin;
  350.         vState.vt = VT_I4;
  351.         vX.vt = VT_I4;
  352.         vY.vt = VT_I4;
  353.         vWin.vt = VT_I4;
  354.  
  355.         // Load screen data
  356.         THROW_ERR ( LoadArray(lGameID) );
  357.         
  358.         // Save player's move to local storage and to Spam
  359.         plField[lX][lY] = lOrder;
  360.         
  361.         vX.lVal = lX;
  362.         vY.lVal = lY;
  363.         THROW_ERR ( spmPropX->put_Value (vX) );
  364.         THROW_ERR ( spmPropY->put_Value (vY) );
  365.  
  366.         // Submit new state
  367.         if (lOrder == 1)
  368.             vState.lVal = 4;
  369.         else
  370.             vState.lVal = 3;
  371.  
  372.         THROW_ERR ( spmPropState->put_Value (vState) );
  373.  
  374.         // Commit move to global storage
  375.         THROW_ERR ( SaveArray (lGameID) );
  376.  
  377.         // Check for win
  378.         if (IsWin (lOrder)) {
  379.  
  380.             // Player wins
  381.             lWin = 1;
  382.  
  383.             // Other player loses
  384.             vWin.lVal = - 1;
  385.             THROW_ERR ( spmPropWin->put_Value (vWin) );
  386.         }
  387.  
  388.         else if (HowManyTurns() == 9) {
  389.             
  390.             // Player ties on his move
  391.             lWin = 2;
  392.  
  393.             // Other player ties on opponent's move
  394.             vWin.lVal = - 2;
  395.             THROW_ERR ( spmPropWin->put_Value (vWin) );
  396.         }
  397.  
  398.         // Prepare return values
  399.         pvWin->lVal = lWin;
  400.  
  401.         // We're happy and finished
  402.         pObjectContext->SetComplete();
  403.  
  404.     } catch (HRESULT hr) {
  405.         
  406.         // Create an ErrorInfo object
  407.         ICreateErrorInfo* pCreateErrInfo = NULL;
  408.         IErrorInfo* pErrInfo = NULL;
  409.         
  410.         CreateErrorInfo (&pCreateErrInfo);
  411.         pCreateErrInfo->QueryInterface (IID_IErrorInfo, (LPVOID FAR*) &pErrInfo);
  412.         
  413.         // Fill in error information
  414.         TCHAR szErr [512];
  415.         wsprintf (szErr, _T("Error %d occurred in Human::NewMove()"), hr);        
  416.         BSTR bstrDesc = TCHAR2BSTR (szErr);
  417.         pCreateErrInfo->SetGUID (IID_IComputer);
  418.         pCreateErrInfo->SetSource (L"Computer");
  419.         pCreateErrInfo->SetDescription (bstrDesc);
  420.         ::SysFreeString (bstrDesc);
  421.         
  422.         // Confirm error information
  423.         SetErrorInfo (0, pErrInfo);
  424.         
  425.         // Clean up the error objects
  426.         if (pCreateErrInfo)
  427.             pCreateErrInfo->Release();
  428.         
  429.         if (pErrInfo)
  430.             pErrInfo->Release();
  431.         
  432.         // Indicate our unhappiness
  433.         if (pObjectContext)
  434.             pObjectContext->SetAbort();
  435.         
  436.         hr = E_FAIL;
  437.     }
  438.     
  439.     if (pObjectContext)
  440.         pObjectContext->Release();
  441.     
  442.     if (spmMgr)
  443.         spmMgr->Release();
  444.     
  445.     if (spmGroup)
  446.         spmGroup->Release();
  447.  
  448.     if (spmPropState)
  449.         spmPropState->Release();
  450.  
  451.     if (spmPropX)
  452.         spmPropX->Release();
  453.  
  454.     if (spmPropY)
  455.         spmPropY->Release();
  456.  
  457.     if (spmPropWin)
  458.         spmPropWin->Release();
  459.  
  460.     return hr;
  461.  
  462. }
  463.  
  464.  
  465. STDMETHODIMP CHuman::GetNewMove (IN long lGameID, IN long lOrder, OUT VARIANT* pvName,
  466.                                  OUT VARIANT* pvFoeX, OUT VARIANT* pvFoeY, OUT VARIANT* pvWin,
  467.                                  OUT VARIANT* pvUpdate) {
  468.  
  469.     // Win protocol
  470.     // ============
  471.     // 0  -> move did not end game
  472.     // 1  -> player won (won't occur in this function)
  473.     // -1 -> remote player won 
  474.     // 2  -> player's move tied the game (won't occur in this function)
  475.     // -2 -> remote player's move tied the game 
  476.  
  477.     HRESULT hr = S_OK;
  478.  
  479.     IObjectContext* pObjectContext = NULL;
  480.  
  481.     ISharedPropertyGroupManager* spmMgr = NULL;
  482.     ISharedPropertyGroup* spmGroup = NULL;
  483.     ISharedProperty* spmPropState = NULL;
  484.     ISharedProperty* spmPropX = NULL;
  485.     ISharedProperty* spmPropY = NULL;
  486.     ISharedProperty* spmPropWin = NULL;
  487.     ISharedProperty* spmPropSecondName = NULL;
  488.  
  489.     pvName->vt = VT_BSTR;
  490.     pvFoeX->vt = VT_I4;
  491.     pvFoeY->vt = VT_I4;
  492.     pvWin->vt = VT_I4;
  493.     pvUpdate->vt = VT_I4;
  494.  
  495.     long lWin = 0;
  496.     long lUpdate = 0;
  497.     long lX = 0;
  498.     long lY = 0;
  499.  
  500.  
  501.     try {
  502.  
  503.         // Get the object context
  504.         THROW_ERR ( hr = GetObjectContext(&pObjectContext) );
  505.         if (pObjectContext == NULL) {
  506.             THROW_ERR ( E_FAIL );
  507.         }
  508.         
  509.         // Create the SharedPropertyGroupManager
  510.         THROW_ERR ( pObjectContext->CreateInstance (CLSID_SharedPropertyGroupManager,
  511.             IID_ISharedPropertyGroupManager, (void**)&spmMgr) );
  512.         
  513.         // Create the SharedPropertyGroup
  514.         LONG lIsolationMode = LockMethod;
  515.         LONG lReleaseMode = Process;
  516.         VARIANT_BOOL bExists = VARIANT_FALSE;
  517.         THROW_ERR ( spmMgr->CreatePropertyGroup (L"TicTacToe", &lIsolationMode, &lReleaseMode,
  518.             &bExists, &spmGroup) );
  519.  
  520.         // Create SharedProperties
  521.         BSTR bstrState;
  522.         BSTR bstrX;
  523.         BSTR bstrY;
  524.         BSTR bstrWin;
  525.         BSTR bstrSecondName;
  526.         TCHAR szBuf[512];
  527.         wsprintf (szBuf, _T("%dState"), lGameID);
  528.         bstrState = TCHAR2BSTR (szBuf);    
  529.         wsprintf (szBuf, _T("%dX"), lGameID);
  530.         bstrX = TCHAR2BSTR (szBuf);
  531.         wsprintf (szBuf, _T("%dY"), lGameID);
  532.         bstrY = TCHAR2BSTR (szBuf);
  533.         wsprintf (szBuf, _T("%dWin"), lGameID);
  534.         bstrWin = TCHAR2BSTR (szBuf);
  535.         wsprintf (szBuf, _T("%dSecondName"), lGameID);
  536.         bstrSecondName = TCHAR2BSTR (szBuf);
  537.  
  538.         THROW_ERR ( spmGroup->CreateProperty (bstrState, &bExists, &spmPropState) );
  539.         THROW_ERR ( spmGroup->CreateProperty (bstrX, &bExists, &spmPropX) );
  540.         THROW_ERR ( spmGroup->CreateProperty (bstrY, &bExists, &spmPropY) );
  541.         THROW_ERR ( spmGroup->CreateProperty (bstrWin, &bExists, &spmPropWin) );
  542.         THROW_ERR ( spmGroup->CreateProperty (bstrSecondName, &bExists, &spmPropSecondName) );
  543.  
  544.         ::SysFreeString (bstrState);
  545.         ::SysFreeString (bstrX);
  546.         ::SysFreeString (bstrY);
  547.         ::SysFreeString (bstrWin);
  548.         ::SysFreeString (bstrSecondName);
  549.  
  550.         // Get state and move parameters
  551.         CComVariant vState;
  552.         CComVariant vX;
  553.         CComVariant vY;
  554.         CComVariant vWin;
  555.         CComVariant vSecondName;
  556.         THROW_ERR ( spmPropState->get_Value (&vState) );
  557.         THROW_ERR ( spmPropX->get_Value (&vX) );
  558.         THROW_ERR ( spmPropY->get_Value (&vY) );
  559.         THROW_ERR ( spmPropWin->get_Value (&vWin) );
  560.         THROW_ERR ( spmPropSecondName->get_Value (&vSecondName) );
  561.  
  562.         switch (vState.lVal) {
  563.  
  564.         case (0):
  565.         
  566.             // Shouldn't happen
  567.             THROW_ERR ( E_FAIL);
  568.             break;
  569.  
  570.         case (1):
  571.  
  572.             // Still waiting for next player to join
  573.             lUpdate = 0;
  574.             break;
  575.  
  576.         case (2):
  577.  
  578.             // Other player just joined
  579.             if (lOrder == 1) {
  580.                 lUpdate = 2;
  581.                 pvName->bstrVal = ::SysAllocString (vSecondName.bstrVal);
  582.  
  583.                 // It's now the first player's turn
  584.                 vState.lVal = 3;
  585.                 THROW_ERR ( spmPropState->put_Value (vState) );
  586.             }
  587.             
  588.             break;
  589.  
  590.         case (3):
  591.         case (4):
  592.  
  593.             long lTemp;
  594.             if (vState.lVal == 3)
  595.                 lTemp = 1;
  596.             else
  597.                 lTemp = 2;
  598.  
  599.             // Has other player moved?
  600.             if (lOrder == lTemp) {
  601.  
  602.                 // Other player has moved
  603.                 lX = vX.lVal;
  604.                 lY = vY.lVal;
  605.                 lWin = vWin.lVal;
  606.                 lUpdate = 1;
  607.  
  608.             } else {
  609.  
  610.                 // Waiting for other player to move
  611.                 lUpdate = 0;
  612.             }
  613.  
  614.             break;
  615.  
  616.         default:
  617.         
  618.             // Shouldn't happen
  619.             THROW_ERR ( E_FAIL );
  620.             break;
  621.         }
  622.  
  623.         // Prepare return values
  624.         pvFoeX->lVal = lX;
  625.         pvFoeY->lVal = lY;
  626.         pvWin->lVal = lWin;
  627.         pvUpdate->lVal = lUpdate;
  628.         
  629.         // We are finished and happy
  630.         pObjectContext->SetComplete();
  631.  
  632.     } catch (HRESULT hr) {
  633.  
  634.         // Create an ErrorInfo object
  635.         ICreateErrorInfo* pCreateErrInfo = NULL;
  636.         IErrorInfo* pErrInfo = NULL;
  637.         
  638.         CreateErrorInfo (&pCreateErrInfo);
  639.         pCreateErrInfo->QueryInterface (IID_IErrorInfo, (LPVOID FAR*) &pErrInfo);
  640.         
  641.         // Fill in error information
  642.         TCHAR szErr [512];
  643.         wsprintf (szErr, _T("Error %d occurred in Human::GetNewMove()"), hr);
  644.         BSTR bstrDesc = TCHAR2BSTR (szErr);
  645.         pCreateErrInfo->SetGUID (IID_IComputer);
  646.         pCreateErrInfo->SetSource (L"Computer");
  647.         pCreateErrInfo->SetDescription (bstrDesc);
  648.         ::SysFreeString (bstrDesc);
  649.  
  650.         // Confirm error information
  651.         SetErrorInfo (0, pErrInfo);
  652.         
  653.         // Clean up the error objects
  654.         if (pCreateErrInfo)
  655.             pCreateErrInfo->Release();
  656.         
  657.         if (pErrInfo)
  658.             pErrInfo->Release();
  659.         
  660.         // Indicate our unhappiness
  661.         if (pObjectContext)
  662.             pObjectContext->SetAbort();
  663.         
  664.         hr = E_FAIL;
  665.     }
  666.  
  667.     if (pObjectContext)
  668.         pObjectContext->Release();
  669.     
  670.     if (spmMgr)
  671.         spmMgr->Release();
  672.     
  673.     if (spmGroup)
  674.         spmGroup->Release();
  675.  
  676.     if (spmPropState)
  677.         spmPropState->Release();
  678.  
  679.     if (spmPropX)
  680.         spmPropX->Release();
  681.  
  682.     if (spmPropY)
  683.         spmPropY->Release();
  684.  
  685.     if (spmPropWin)
  686.         spmPropWin->Release();
  687.  
  688.     if (spmPropSecondName)
  689.         spmPropSecondName->Release();
  690.  
  691.     return hr;
  692. }
  693.  
  694.  
  695. bool CHuman::IsWin (long lPlayer) {
  696.     
  697.     bool bWin = false;
  698.  
  699.     for (int i = 0; i < 3; i ++) {
  700.         if (plField [i][0] == plField [i][1] && plField [i][1] == plField [i][2] && plField [i][0] == lPlayer)
  701.             bWin = true;
  702.         if (plField [0][i] == plField [1][i] && plField [1][i] == plField [2][i] && plField [0][i] == lPlayer)
  703.             bWin = true;
  704.     }
  705.     
  706.     if (plField [0][0] == plField [1][1] && plField [1][1] == plField [2][2] && plField [1][1] == lPlayer)
  707.         bWin = true;
  708.     if (plField [2][0] == plField [1][1] && plField [1][1] == plField [0][2] && plField [1][1] == lPlayer)
  709.         bWin = true;
  710.  
  711.     return bWin;
  712. }
  713.  
  714.  
  715. long CHuman::HowManyTurns () {
  716.  
  717.     long lTurns = 0;
  718.     
  719.     for (int i = 0; i < 3; i ++) {
  720.         for (int j = 0; j < 3; j ++) {
  721.             if (plField[i][j] > 0) {
  722.                 lTurns ++;
  723.             }
  724.         }
  725.     }
  726.  
  727.     return lTurns;
  728. }
  729.  
  730.  
  731. HRESULT CHuman::LoadArray (long lGameID) {
  732.     
  733.     HRESULT hr = S_OK;
  734.  
  735.     IObjectContext* pObjectContext = NULL;
  736.  
  737.     ISharedPropertyGroupManager* spmMgr = NULL;
  738.     ISharedPropertyGroup* spmGroup = NULL;
  739.     ISharedProperty* spmPropField[3][3];
  740.  
  741.     // Get context
  742.     hr = GetObjectContext(&pObjectContext);
  743.  
  744.     // Create the SharedPropertyGroupManager
  745.     hr = pObjectContext->CreateInstance (CLSID_SharedPropertyGroupManager, IID_ISharedPropertyGroupManager, (void**)&spmMgr);
  746.     
  747.     // Create the SharedPropertyGroup
  748.     LONG lIsolationMode = LockMethod;
  749.     LONG lReleaseMode = Process;
  750.     VARIANT_BOOL bExists = VARIANT_FALSE;
  751.     hr = spmMgr->CreatePropertyGroup (L"TicTacToe", &lIsolationMode, &lReleaseMode, &bExists, &spmGroup);
  752.     
  753.     // Load the field SharedProperties
  754.     TCHAR szBuf [512];
  755.     BSTR bstrField;
  756.     CComVariant vField;
  757.  
  758.     for (long i = 0; i < 3; i ++ ) {
  759.         for (long j = 0; j < 3; j ++) {
  760.     
  761.             wsprintf (szBuf, _T("%dField%d%d"), lGameID, i, j);
  762.             bstrField = TCHAR2BSTR (szBuf);
  763.             hr = spmGroup->CreateProperty (bstrField, &bExists, &spmPropField[i][j]);
  764.             ::SysFreeString (bstrField);
  765.  
  766.             hr = spmPropField[i][j]->get_Value (&vField);
  767.             plField[i][j] = vField.lVal;
  768.         }
  769.     }
  770.  
  771.     if (pObjectContext)
  772.         pObjectContext->Release();
  773.     
  774.     if (spmMgr)
  775.         spmMgr->Release();
  776.     
  777.     if (spmGroup)
  778.         spmGroup->Release();
  779.     
  780.     for (i = 0; i < 3; i ++) {
  781.         for (long j = 0; j < 3; j ++) {
  782.             if (spmPropField[i][j]) {
  783.                 spmPropField[i][j]->Release();
  784.             }
  785.         }
  786.     }
  787.  
  788.     return hr;
  789. }
  790.  
  791.  
  792. HRESULT CHuman::SaveArray (long lGameID) {
  793.  
  794.     HRESULT hr = S_OK;
  795.  
  796.     IObjectContext* pObjectContext = NULL;
  797.         
  798.     ISharedPropertyGroupManager* spmMgr = NULL;
  799.     ISharedPropertyGroup* spmGroup = NULL;
  800.     ISharedProperty* spmPropField[3][3];
  801.  
  802.     // Get context
  803.     hr = GetObjectContext(&pObjectContext);
  804.  
  805.     // Create the SharedPropertyGroupManager
  806.     hr = pObjectContext->CreateInstance (CLSID_SharedPropertyGroupManager, IID_ISharedPropertyGroupManager, (void**)&spmMgr);
  807.     
  808.     // Create the SharedPropertyGroup
  809.     LONG lIsolationMode = LockMethod;
  810.     LONG lReleaseMode = Process;
  811.     VARIANT_BOOL bExists = VARIANT_FALSE;
  812.     hr = spmMgr->CreatePropertyGroup (L"TicTacToe", &lIsolationMode, &lReleaseMode, &bExists, &spmGroup);
  813.     
  814.     // Save the field shared properties
  815.     TCHAR szBuf [512];
  816.     BSTR bstrField;
  817.     CComVariant vField;
  818.     vField.vt = VT_I4;
  819.  
  820.     for (long i = 0; i < 3; i ++ ) {
  821.         for (long j = 0; j < 3; j ++) {
  822.     
  823.             wsprintf (szBuf, _T("%dField%d%d"), lGameID, i, j);
  824.             bstrField = TCHAR2BSTR (szBuf);
  825.             hr = spmGroup->CreateProperty (bstrField, &bExists, &spmPropField[i][j]);
  826.             ::SysFreeString (bstrField);
  827.  
  828.             vField.lVal = plField[i][j];
  829.             hr = spmPropField[i][j]->put_Value (vField);
  830.         }
  831.     }
  832.  
  833.     if (pObjectContext)
  834.         pObjectContext->Release();
  835.     
  836.     if (spmMgr)
  837.         spmMgr->Release();
  838.     
  839.     if (spmGroup)
  840.         spmGroup->Release();
  841.     
  842.     for (i = 0; i < 3; i ++) {
  843.         for (long j = 0; j < 3; j ++) {
  844.             if (spmPropField[i][j]) {
  845.                 spmPropField[i][j]->Release();
  846.             }
  847.         }
  848.     }
  849.  
  850.     return hr;
  851. }