home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / tutsamp / remclien / utcrucar.cpp < prev    next >
C/C++ Source or Header  |  1997-08-05  |  38KB  |  1,094 lines

  1. /*+==========================================================================
  2.   File:      UTCRUCAR.CPP
  3.  
  4.   Summary:   Implementation file for the aggregatable COUtilityCruiseCar
  5.              COM object class.
  6.  
  7.              UTCRUCAR showcases the construction of the COUtilityCruiseCar
  8.              COM object class with the IUnknown, ICar, ICruise, and
  9.              IUtility interfaces.  This is done through Containment reuse
  10.              of COCruiseCar's ICar and ICruise interface features.
  11.  
  12.              For a comprehensive tutorial code tour of this module's
  13.              contents and offerings see the tutorial REMCLIEN.HTM
  14.              file.  For more specific technical details on the internal
  15.              workings see the comments dispersed throughout the
  16.              module's source code.
  17.  
  18.   Classes:   COUtilityCruiseCar.
  19.  
  20.   Functions: CreateUtilityCruiseCar.
  21.  
  22.   Origin:    3-27-96: atrent - Editor inheritance from APTCLIEN source.
  23.  
  24. ----------------------------------------------------------------------------
  25.   This file is part of the Microsoft COM Tutorial Code Samples.
  26.  
  27.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  28.  
  29.   This source code is intended only as a supplement to Microsoft
  30.   Development Tools and/or on-line documentation.  See these other
  31.   materials for detailed information regarding Microsoft code samples.
  32.  
  33.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  34.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  35.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  36.   PARTICULAR PURPOSE.
  37. ==========================================================================+*/
  38.  
  39. /*---------------------------------------------------------------------------
  40.   We include WINDOWS.H for all Win32 applications.
  41.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  42.   We include APPUTIL.H because we will be building this application using
  43.     the convenient Virtual Window and Dialog classes and other
  44.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  45.   We include MICARS.H and CARGUIDS.H for the common car-related Interface
  46.     class, GUID, and CLSID specifications.
  47.   We include REMCLIEN.H because it has class and resource definitions
  48.     specific to this remCLIEN application.
  49.   We include UTCRUCAR.H because it has the COUtilityCruiseCar declarations.
  50. ---------------------------------------------------------------------------*/
  51. #include <windows.h>
  52. #include <ole2.h>
  53. #include <apputil.h>
  54. #include <micars.h>
  55. #include <carguids.h>
  56. #include "remclien.h"
  57. #include "utcrucar.h"
  58.  
  59.  
  60. /*---------------------------------------------------------------------------
  61.   COUtilityCruiseCar's implementation of its main COM object class including
  62.   Constructor, Destructor, QueryInterface, AddRef, and Release.
  63. ---------------------------------------------------------------------------*/
  64.  
  65. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  66.   Method:   COUtilityCruiseCar::COUtilityCruiseCar
  67.  
  68.   Summary:  COUtilityCruiseCar Constructor. Note the member initializer:
  69.             "m_ImpIUtility(this, pUnkOuter)" which is used to pass the 'this'
  70.             and pUnkOuter pointers of this constructor function to the
  71.             constructor in the instantiation of the implementation of
  72.             the CImpIUtility interface (which is nested inside this present
  73.             COUtilityCruiseCar Object Class).
  74.  
  75.   Args:     IUnknown* pUnkOuter)
  76.               Pointer to the the outer Unknown.  NULL means this COM Object
  77.               is not being Aggregated.  Non NULL means it is being created
  78.               on behalf of an outside COM object that is reusing it via
  79.               aggregation.
  80.  
  81.   Modifies: m_cRefs, m_pUnkOuter, m_pUnkCruiseCar.
  82.  
  83.   Returns:  void
  84. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  85. COUtilityCruiseCar::COUtilityCruiseCar(
  86.   IUnknown* pUnkOuter) :
  87.   m_ImpICar(this, pUnkOuter),
  88.   m_ImpICruise(this, pUnkOuter),
  89.   m_ImpIUtility(this, pUnkOuter)
  90. {
  91.   // Zero the COM object's reference count.
  92.   m_cRefs = 0;
  93.  
  94.   // No AddRef necessary if non-NULL, as this COM object's lifetime
  95.   // is totally coupled with the controlling Outer object's lifetime.
  96.   m_pUnkOuter = pUnkOuter;
  97.  
  98.   // Zero the pointer to the contained COCruiseCar object's ICar interface.
  99.   m_pICar = NULL;
  100.  
  101.   // Zero the pointer to the contained COCruiseCar object's ICruise
  102.   // interface.
  103.   m_pICruise = NULL;
  104.  
  105.   LOGF1("C: COUtilityCruiseCar Constructor. m_pUnkOuter=0x%X.", m_pUnkOuter);
  106.  
  107.   return;
  108. }
  109.  
  110.  
  111. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  112.   Method:   COUtilityCruiseCar::~COUtilityCruiseCar
  113.  
  114.   Summary:  COUtilityCruiseCar Destructor.
  115.  
  116.   Args:     void
  117.  
  118.   Modifies: .
  119.  
  120.   Returns:  void
  121. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  122. COUtilityCruiseCar::~COUtilityCruiseCar(void)
  123. {
  124.   LOG("C: COUtilityCruiseCar::Destructor.");
  125.  
  126.   // Release the contained CruiseCar interfaces.
  127.   RELEASE_INTERFACE(m_pICruise);
  128.   RELEASE_INTERFACE(m_pICar);
  129.  
  130.   return;
  131. }
  132.  
  133.  
  134. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  135.   Method:   COUtilityCruiseCar::Init
  136.  
  137.   Summary:  COUtilityCruiseCar Initialization method.
  138.  
  139.   Args:     void
  140.  
  141.   Modifies: m_pICar, m_pICruise, m_cRefs.
  142.  
  143.   Returns:  HRESULT
  144.               Standard result code. NOERROR for success.
  145. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  146. HRESULT COUtilityCruiseCar::Init(void)
  147. {
  148.   HRESULT hr;
  149.   IClassFactory* pICFCruiseCar;
  150.   HCURSOR hCurPrev;
  151.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  152.  
  153.   // Change cursor to the hour glass.  Things could take awhile working
  154.   // across the network.
  155.   hCurPrev = SetCursor(hCurWait);
  156.  
  157.   // Set up the right pIUnknown for delegation.  If we are being
  158.   // aggregated then we pass the pUnkOuter in turn to any COM objects
  159.   // that we are aggregating.  m_pUnkOuter was set in the Constructor.
  160.   IUnknown* pUnkOuter = (NULL == m_pUnkOuter) ? this : m_pUnkOuter;
  161.  
  162.   LOGF1("C: COUtilityCruiseCar::Init. pUnkOuter=0x%X",pUnkOuter);
  163.  
  164.   // Get a class factory for AptCruiseCar and issue IClassFactory's
  165.   // CreateInstance method to manufacture a COCruiseCar COM object.
  166.   LOG("C: COUtilityCruiseCar::Init. Obtain CruiseCar Class Factory.");
  167.   hr = CoGetClassObject(
  168.          CLSID_AptCruiseCar,
  169.          CLSCTX_REMOTE_SERVER,
  170.          &g_ServerInfo,
  171.          IID_IClassFactory,
  172.          (PPVOID)&pICFCruiseCar);
  173.   LOGERROR("C:CoGetClassObject.",hr);
  174.   if (SUCCEEDED(hr))
  175.   {
  176.     LOG("C: COUtilityCruiseCar::Init. CruiseCar Class Factory obtained.");
  177.     LOG("C: COUtilityCruiseCar::Init. Calling CFCruiseCar::CreateInstance.");
  178.     // A NULL pUnkOuter is passed indicating that we are creating a
  179.     // COCruiseCar component via the Containment reuse method.  We can
  180.     // currently pass nothing other than this NULL pUnkOuter because
  181.     // aggregation is not supported across process or machine boundaries.
  182.     // Since we are not requesting a COCruiseCar create for aggregation we
  183.     // can directly request for the ICruise interface on the new object.
  184.     hr = pICFCruiseCar->CreateInstance(
  185.                           NULL,
  186.                           IID_ICruise,
  187.                           (PPVOID)&m_pICruise);
  188.     LOG("C: COUtilityCruiseCar::Init. Releasing CruiseCar Class Factory.");
  189.     pICFCruiseCar->Release();
  190.     LOGERROR("C:CreateInstance.",hr);
  191.     if (SUCCEEDED(hr))
  192.     {
  193.       // Now that we have a valid interface pointer (m_pICruise) on the
  194.       // new object we can obtain and cache a pointer to that contained
  195.       // object's ICar interface as well.  We must QI using the obtained
  196.       // ICruise pointer on the object to ensure that the marshaling proxy
  197.       // is involved in the QueryInterface call to provide the pointer to
  198.       // the ICar interface proxy.
  199.       hr = m_pICruise->QueryInterface(IID_ICar, (PPVOID)&m_pICar);
  200.     }
  201.   }
  202.  
  203.   if (SUCCEEDED(hr))
  204.   {
  205.     LOG("C: COUtilityCruiseCar::Init (CruiseCar Containment) Succeeded.");
  206.   }
  207.   else
  208.   {
  209.     LOGF1("C: COUtilityCruiseCar::Init (CruiseCar Containment) Failed. hr=0x%X",hr);
  210.   }
  211.  
  212.   // Set Cursor back to what it was.
  213.   SetCursor(hCurPrev);
  214.  
  215.   return (hr);
  216. }
  217.  
  218.  
  219. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  220.   Method:   COUtilityCruiseCar::QueryInterface
  221.  
  222.   Summary:  QueryInterface of the COUtilityCruiseCar non-delegating
  223.             IUnknown implementation.
  224.  
  225.   Args:     REFIID riid,
  226.               [in] GUID of the Interface being requested.
  227.             PPVOID ppv)
  228.               [out] Address of the caller's pointer variable that will
  229.               receive the requested interface pointer.
  230.  
  231.   Modifies: .
  232.  
  233.   Returns:  HRESULT
  234. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  235. STDMETHODIMP COUtilityCruiseCar::QueryInterface(
  236.                REFIID riid,
  237.                PPVOID ppv)
  238. {
  239.   HRESULT hr = E_NOINTERFACE;
  240.   *ppv = NULL;
  241.  
  242.   if (IID_IUnknown == riid)
  243.   {
  244.     *ppv = this;
  245.     LOG("C: COUtilityCruiseCar::QueryInterface. 'this' pIUnknown returned.");
  246.   }
  247.   else if (IID_ICar == riid)
  248.   {
  249.     *ppv = &m_ImpICar;
  250.     LOG("C: COUtilityCruiseCar::QueryInterface. pICar returned");
  251.   }
  252.   else if (IID_ICruise == riid)
  253.   {
  254.     *ppv = &m_ImpICruise;
  255.     LOG("C: COUtilityCruiseCar::QueryInterface. pICruise returned");
  256.   }
  257.   else if (IID_IUtility == riid)
  258.   {
  259.     // This IUtility interface is implemented in this COUtilityCruiseCar
  260.     // object as a native interface of COUtilityCruiseCar.
  261.     *ppv = &m_ImpIUtility;
  262.     LOG("C: COUtilityCruiseCar::QueryInterface. pIUtility returned.");
  263.   }
  264.  
  265.   if (NULL != *ppv)
  266.   {
  267.     // We've handed out a pointer to an interface so obey the COM rules
  268.     // and AddRef its reference count.
  269.     ((LPUNKNOWN)*ppv)->AddRef();
  270.     hr = NOERROR;
  271.   }
  272.  
  273.   return (hr);
  274. }
  275.  
  276.  
  277. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  278.   Method:   COUtilityCruiseCar::AddRef
  279.  
  280.   Summary:  AddRef of the COUtilityCruiseCar non-delegating
  281.             IUnknown implementation.
  282.  
  283.   Args:     void
  284.  
  285.   Modifies: m_cRefs.
  286.  
  287.   Returns:  ULONG
  288.               New value of m_cRefs (COM object's reference count).
  289. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  290. STDMETHODIMP_(ULONG) COUtilityCruiseCar::AddRef(void)
  291. {
  292.   m_cRefs++;
  293.  
  294.   LOGF1("C: COUtilityCruiseCar::AddRef. New cRefs=%i.", m_cRefs);
  295.  
  296.   return m_cRefs;
  297. }
  298.  
  299.  
  300. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  301.   Method:   COUtilityCruiseCar::Release
  302.  
  303.   Summary:  Release of the COUtilityCruiseCar non-delegating IUnknown
  304.             implementation.
  305.  
  306.   Args:     void
  307.  
  308.   Modifies: m_cRefs.
  309.  
  310.   Returns:  ULONG
  311.               New value of m_cRefs (COM object's reference count).
  312. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  313. STDMETHODIMP_(ULONG) COUtilityCruiseCar::Release(void)
  314. {
  315.   ULONG ulCount = --m_cRefs;
  316.  
  317.   LOGF1("C: COUtilityCruiseCar::Release. New cRefs=%i.", m_cRefs);
  318.  
  319.   if (0 == m_cRefs)
  320.   {
  321.     // We artificially bump the main ref count.  This fulfills one of
  322.     // the rules of aggregated objects and ensures that an indirect
  323.     // recursive call to this release won't occur because of other
  324.     // delegating releases that might happen in our own destructor.
  325.     m_cRefs++;
  326.     delete this;
  327.   }
  328.  
  329.   return ulCount;
  330. }
  331.  
  332.  
  333. /*---------------------------------------------------------------------------
  334.   COUtilityCruiseCar's nested implementation of the ICar interface
  335.   including Constructor, Destructor, QueryInterface, AddRef, Release,
  336.   Shift, Clutch, Speed, and Steer.
  337. ---------------------------------------------------------------------------*/
  338.  
  339. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  340.   Method:   COUtilityCruiseCar::CImpICar::CImpICar
  341.  
  342.   Summary:  Constructor for the CImpICar interface instantiation.
  343.  
  344.   Args:     COUtilityCruiseCar* pBackObj,
  345.               Back pointer to the parent outer object.
  346.             IUnknown* pUnkOuter,
  347.               Pointer to the outer Unknown.  For delegation.
  348.  
  349.   Modifies: m_cRefI, m_pBackObj, m_pUnkOuter.
  350.  
  351.   Returns:  void
  352. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  353. COUtilityCruiseCar::CImpICar::CImpICar(
  354.   COUtilityCruiseCar* pBackObj,
  355.   IUnknown* pUnkOuter)
  356. {
  357.   // Init the Interface Ref Count (used for debugging only).
  358.   m_cRefI = 0;
  359.  
  360.   // Init the Back Object Pointer to point to the outer object.
  361.   m_pBackObj = pBackObj;
  362.  
  363.   // Init the CImpICar interface's delegating Unknown pointer.  We use
  364.   // the Back Object pointer for IUnknown delegation here if we are not
  365.   // being aggregated.  If we are being aggregated we use the supplied
  366.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  367.   // assignment requires no AddRef because the CImpICar lifetime is
  368.   // quaranteed by the lifetime of the parent object in which
  369.   // CImpICar is nested.
  370.   if (NULL == pUnkOuter)
  371.   {
  372.     m_pUnkOuter = pBackObj;
  373.     LOG("C: COUtilityCruiseCar::CImpICar Constructor. Non-Aggregating");
  374.   }
  375.   else
  376.   {
  377.     m_pUnkOuter = pUnkOuter;
  378.     LOG("C: COUtilityCruiseCar::CImpICar Constructor. Aggregating");
  379.   }
  380.  
  381.   return;
  382. }
  383.  
  384.  
  385. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  386.   Method:   COUtilityCruiseCar::CImpICar::~CImpICar
  387.  
  388.   Summary:  Destructor for the CImpICar interface instantiation.
  389.  
  390.   Args:     void
  391.  
  392.   Modifies: .
  393.  
  394.   Returns:  void
  395. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  396. COUtilityCruiseCar::CImpICar::~CImpICar(void)
  397. {
  398.   LOG("C: COUtilityCruiseCar::CImpICar Destructor.");
  399.  
  400.   return;
  401. }
  402.  
  403.  
  404. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  405.   Method:   COUtilityCruiseCar::CImpICar::QueryInterface
  406.  
  407.   Summary:  The QueryInterface IUnknown member of this ICar interface
  408.             implementation that delegates to m_pUnkOuter, whatever it is.
  409.  
  410.   Args:     REFIID riid,
  411.               [in] GUID of the Interface being requested.
  412.             PPVOID ppv)
  413.               [out] Address of the caller's pointer variable that will
  414.               receive the requested interface pointer.
  415.  
  416.   Modifies: .
  417.  
  418.   Returns:  HRESULT
  419.               Returned by the delegated outer QueryInterface call.
  420. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  421. STDMETHODIMP COUtilityCruiseCar::CImpICar::QueryInterface(
  422.                REFIID riid,
  423.                PPVOID ppv)
  424. {
  425.   LOG("C: COUtilityCruiseCar::CImpICar::QueryInterface. Delegating.");
  426.  
  427.   // Delegate this call to the outer object's QueryInterface.
  428.   return m_pUnkOuter->QueryInterface(riid, ppv);
  429. }
  430.  
  431.  
  432. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  433.   Method:   COUtilityCruiseCar::CImpICar::AddRef
  434.  
  435.   Summary:  The AddRef IUnknown member of this ICar interface
  436.             implementation that delegates to m_pUnkOuter, whatever it is.
  437.  
  438.   Args:     void
  439.  
  440.   Modifies: m_cRefI.
  441.  
  442.   Returns:  ULONG
  443.               Returned by the delegated outer AddRef call.
  444. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  445. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpICar::AddRef(void)
  446. {
  447.   // Increment the Interface Reference Count.
  448.   ++m_cRefI;
  449.  
  450.   LOGF1("C: COUtilityCruiseCar::CImpICar::Addref. Delegating. New cI=%i.", m_cRefI);
  451.  
  452.   // Delegate this call to the outer object's AddRef.
  453.   return m_pUnkOuter->AddRef();
  454. }
  455.  
  456.  
  457. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  458.   Method:   COUtilityCruiseCar::CImpICar::Release
  459.  
  460.   Summary:  The Release IUnknown member of this ICar interface
  461.             implementation that delegates to m_pUnkOuter, whatever it is.
  462.  
  463.   Args:     void
  464.  
  465.   Modifies: .
  466.  
  467.   Returns:  ULONG
  468.               Returned by the delegated outer Release call.
  469. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  470. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpICar::Release(void)
  471. {
  472.   // Decrement the Interface Reference Count.
  473.   --m_cRefI;
  474.  
  475.   LOGF1("C: COUtilityCruiseCar::CImpICar::Release. Delegating. New cI=%i.", m_cRefI);
  476.  
  477.   // Delegate this call to the outer object's Release.
  478.   return m_pUnkOuter->Release();
  479. }
  480.  
  481.  
  482. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  483.   Method:   COUtilityCruiseCar::CImpICar::Shift
  484.  
  485.   Summary:  The Shift member method of this ICar interface implementation.
  486.             A simple empty method on a COUtilityCruiseCar COM object for
  487.             tutorial purposes.  Presumably if this Car object were
  488.             modeling a real Car then the Shift method would shift to the
  489.             specified gear.
  490.  
  491.   Args:     short nGear
  492.               0 - Neutral; 1 - 5 First 5 forward gears; 6 - Reverse.
  493.  
  494.   Modifies: .
  495.  
  496.   Returns:  HRESULT
  497.               Delegated HRESULT.
  498. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  499. STDMETHODIMP COUtilityCruiseCar::CImpICar::Shift(
  500.                short nGear)
  501. {
  502.   LOGF1("C: COUtilityCruiseCar::CImpICar::Shift. Delegating. nGear=%i.",nGear);
  503.  
  504.   // Delegate this call to the contained COCruiseCar's ICar::Shift.
  505.   return m_pBackObj->m_pICar->Shift(nGear);
  506. }
  507.  
  508.  
  509. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  510.   Method:   COUtilityCruiseCar::CImpICar::Clutch
  511.  
  512.   Summary:  The Clutch member method of this ICar interface
  513.             implementation. A simple empty method on a COUtilityCruiseCar
  514.             COM object for tutorial purposes.  Presumably if this Car
  515.             object were modeling a real Car then the Clutch method would
  516.             engage the clutch the specified amount.
  517.  
  518.   Args:     short nEngaged)
  519.               Percent clutch is engaged (0 to 100%).
  520.  
  521.   Modifies: .
  522.  
  523.   Returns:  HRESULT
  524.               Delegated HRESULT.
  525. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  526. STDMETHODIMP COUtilityCruiseCar::CImpICar::Clutch(
  527.                short nEngaged)
  528. {
  529.   LOGF1("C: COUtilityCruiseCar::CImpICar::Clutch. Delegating. nEngaged=%i.", nEngaged);
  530.  
  531.   // Delegate this call to the contained COCruiseCar's ICar::Clutch.
  532.   return m_pBackObj->m_pICar->Clutch(nEngaged);
  533. }
  534.  
  535.  
  536. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  537.   Method:   COUtilityCruiseCar::CImpICar::Speed
  538.  
  539.   Summary:  The Propel member method of this ICar interface
  540.             implementation. A simple empty method on a COUtilityCruiseCar
  541.             COM object for tutorial purposes.  Presumably if this Car
  542.             object were modeling a real Car then this method would
  543.             accelerate/brake to bring the car to the specified speed.
  544.  
  545.   Args:     short nMph
  546.               New speed in miles per hour.
  547.  
  548.   Modifies: .
  549.  
  550.   Returns:  HRESULT
  551.               Delegated HRESULT.
  552. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  553. STDMETHODIMP COUtilityCruiseCar::CImpICar::Speed(
  554.                short nMph)
  555. {
  556.   LOGF1("C: COUtilityCruiseCar::CImpICar::Speed. Delegating. nMph=%i.",nMph);
  557.  
  558.   // Delegate this call to the contained COCruiseCar's ICar::Speed.
  559.   return m_pBackObj->m_pICar->Speed(nMph);
  560. }
  561.  
  562.  
  563. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  564.   Method:   COUtilityCruiseCar::CImpICar::Steer
  565.  
  566.   Summary:  The Steer member method of this ICar interface implementation.
  567.             A simple empty method on a COUtilityCruiseCar COM object for
  568.             tutorial purposes.  Presumably if this Car object were
  569.             modeling a real Car then the Steer method would set the
  570.             steering angle of the Car.
  571.  
  572.   Args:     short nAngle)
  573.               0 degrees straight ahead, -45 Full left, +45 Full right.
  574.  
  575.   Modifies: .
  576.  
  577.   Returns:  HRESULT
  578.               Delegated HRESULT.
  579. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  580. STDMETHODIMP COUtilityCruiseCar::CImpICar::Steer(
  581.                short nAngle)
  582. {
  583.   LOGF1("C: COUtilityCruiseCar::CImpICar::Steer. Delegating. nAngle=%i.",nAngle);
  584.  
  585.   // Delegate this call to the contained COCruiseCar's ICar::Steer.
  586.   return m_pBackObj->m_pICar->Steer(nAngle);
  587. }
  588.  
  589.  
  590. /*---------------------------------------------------------------------------
  591.   COUtilityCruiseCar's nested implementation of the ICruise interface
  592.   including Constructor, Destructor, QueryInterface, AddRef, Release,
  593.   Engage, and Adjust.
  594. ---------------------------------------------------------------------------*/
  595.  
  596. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  597.   Method:   COUtilityCruiseCar::CImpICruise::CImpICruise
  598.  
  599.   Summary:  Constructor for the CImpICruise interface instantiation.
  600.  
  601.   Args:     COUtilityCruiseCar* pBackObj,
  602.               Back pointer to the parent outer object.
  603.             IUnknown* pUnkOuter,
  604.               Pointer to the outer Unknown.  For delegation.
  605.  
  606.   Modifies: m_cRefI, m_pBackObj, m_pUnkOuter.
  607.  
  608.   Returns:  void
  609. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  610. COUtilityCruiseCar::CImpICruise::CImpICruise(
  611.   COUtilityCruiseCar* pBackObj,
  612.   IUnknown* pUnkOuter)
  613. {
  614.   // Init the Interface Ref Count (used for debugging only).
  615.   m_cRefI = 0;
  616.  
  617.   // Init the Back Object Pointer to point to the outer object.
  618.   m_pBackObj = pBackObj;
  619.  
  620.   // Init the CImpICruise interface's delegating Unknown pointer.  We use
  621.   // the Back Object pointer for IUnknown delegation here if we are not
  622.   // being aggregated.  If we are being aggregated we use the supplied
  623.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  624.   // assignment requires no AddRef because the CImpICruise lifetime is
  625.   // quaranteed by the lifetime of the parent object in which
  626.   // CImpICruise is nested.
  627.   if (NULL == pUnkOuter)
  628.   {
  629.     m_pUnkOuter = pBackObj;
  630.     LOG("C: COUtilityCruiseCar::CImpICruise Constructor. Non-Aggregating");
  631.   }
  632.   else
  633.   {
  634.     m_pUnkOuter = pUnkOuter;
  635.     LOG("C: COUtilityCruiseCar::CImpICruise Constructor. Aggregating");
  636.   }
  637.  
  638.   return;
  639. }
  640.  
  641.  
  642. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  643.   Method:   COUtilityCruiseCar::CImpICruise::~CImpICruise
  644.  
  645.   Summary:  Destructor for the CImpICruise interface instantiation.
  646.  
  647.   Args:     void
  648.  
  649.   Modifies: .
  650.  
  651.   Returns:  void
  652. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  653. COUtilityCruiseCar::CImpICruise::~CImpICruise(void)
  654. {
  655.   LOG("C: COUtilityCruiseCar::CImpICruise Destructor.");
  656.  
  657.   return;
  658. }
  659.  
  660.  
  661. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  662.   Method:   COUtilityCruiseCar::CImpICruise::QueryInterface
  663.  
  664.   Summary:  The QueryInterface IUnknown member of this ICruise interface
  665.             implementation that delegates to m_pUnkOuter, whatever it is.
  666.  
  667.   Args:     REFIID riid,
  668.               [in] GUID of the Interface being requested.
  669.             PPVOID ppv)
  670.               [out] Address of the caller's pointer variable that will
  671.               receive the requested interface pointer.
  672.  
  673.   Modifies: .
  674.  
  675.   Returns:  HRESULT
  676.               Returned by the delegated outer QueryInterface call.
  677. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  678. STDMETHODIMP COUtilityCruiseCar::CImpICruise::QueryInterface(
  679.                REFIID riid,
  680.                PPVOID ppv)
  681. {
  682.   LOG("C: COUtilityCruiseCar::CImpICruise::QueryInterface. Delegating.");
  683.  
  684.   // Delegate this call to the outer object's QueryInterface.
  685.   return m_pUnkOuter->QueryInterface(riid, ppv);
  686. }
  687.  
  688.  
  689. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  690.   Method:   COUtilityCruiseCar::CImpICruise::AddRef
  691.  
  692.   Summary:  The AddRef IUnknown member of this ICruise interface
  693.             implementation that delegates to m_pUnkOuter, whatever it is.
  694.  
  695.   Args:     void
  696.  
  697.   Modifies: m_cRefI.
  698.  
  699.   Returns:  ULONG
  700.               Returned by the delegated outer AddRef call.
  701. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  702. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpICruise::AddRef(void)
  703. {
  704.   // Increment the Interface Reference Count.
  705.   ++m_cRefI;
  706.  
  707.   LOGF1("C: COUtilityCruiseCar::CImpICruise::Addref. Delegating. New cI=%i.", m_cRefI);
  708.  
  709.   // Delegate this call to the outer object's AddRef.
  710.   return m_pUnkOuter->AddRef();
  711. }
  712.  
  713.  
  714. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  715.   Method:   COUtilityCruiseCar::CImpICruise::Release
  716.  
  717.   Summary:  The Release IUnknown member of this ICruise interface
  718.             implementation that delegates to m_pUnkOuter, whatever it is.
  719.  
  720.   Args:     void
  721.  
  722.   Modifies: .
  723.  
  724.   Returns:  ULONG
  725.               Returned by the delegated outer Release call.
  726. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  727. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpICruise::Release(void)
  728. {
  729.   // Decrement the Interface Reference Count.
  730.   --m_cRefI;
  731.  
  732.   LOGF1("C: COUtilityCruiseCar::CImpICruise::Release. Delegating. New cI=%i.", m_cRefI);
  733.  
  734.   // Delegate this call to the outer object's Release.
  735.   return m_pUnkOuter->Release();
  736. }
  737.  
  738.  
  739. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  740.   Method:   COUtilityCruiseCar::CImpICruise::Engage
  741.  
  742.   Summary:  The Engage member method of this ICruise interface
  743.             implementation.  A simple empty method on a COUtilityCruiseCar
  744.             COM object for tutorial purposes.  Presumably if this Car
  745.             object were modeling a real Car then the Engage method would
  746.             turn the Cruise control system on or off.
  747.  
  748.   Args:     BOOL bOnOff)
  749.               TRUE for On; FALSE for Off.
  750.  
  751.   Modifies: .
  752.  
  753.   Returns:  HRESULT
  754.               Delegated HRESULT.
  755. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  756. STDMETHODIMP COUtilityCruiseCar::CImpICruise::Engage(
  757.                BOOL bOnOff)
  758. {
  759.   LOGF1("C: COUtilityCruiseCar::CImpICruise::Engage. Delegating. bOnOff=%i.",bOnOff);
  760.  
  761.   // Delegate this call to the contained COCruiseCar's ICruise::Engage.
  762.   m_pBackObj->m_pICruise->Engage(bOnOff);
  763.  
  764.   return NOERROR;
  765. }
  766.  
  767.  
  768. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  769.   Method:   COUtilityCruiseCar::CImpICruise::Adjust
  770.  
  771.   Summary:  The Adjust member method of this ICruise interface
  772.             implementation.  A simple empty method on a COUtilityCruiseCar
  773.             COM object for tutorial purposes.  Presumably if this Car
  774.             object were modeling a real Car then the Adjust method would
  775.             allow notching the cruise set speed up or down by increments
  776.             of 3 mph.
  777.  
  778.   Args:     BOOL bUpDown)
  779.               TRUE for Up; FALSE for Down.
  780.  
  781.   Modifies: .
  782.  
  783.   Returns:  HRESULT
  784.               Delegated HRESULT.
  785. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  786. STDMETHODIMP COUtilityCruiseCar::CImpICruise::Adjust(
  787.                BOOL bUpDown)
  788. {
  789.   LOGF1("C: COUtilityCruiseCar::CImpICruise::Adjust. Delegating. bUpDown=%i.",bUpDown);
  790.  
  791.   // Delegate this call to the contained COCruiseCar's ICruise::Adjust.
  792.   m_pBackObj->m_pICruise->Adjust(bUpDown);
  793.  
  794.   return NOERROR;
  795. }
  796.  
  797.  
  798. /*---------------------------------------------------------------------------
  799.   COUtilityCruiseCar's nested implementation of the IUtility interface
  800.   including methods: Constructor, Destructor, QueryInterface, AddRef,
  801.   Release, Offroad, and Winch.
  802. ---------------------------------------------------------------------------*/
  803.  
  804. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  805.   Method:   COUtilityCruiseCar::CImpIUtility::CImpIUtility
  806.  
  807.   Summary:  Constructor for the CImpIUtility interface instantiation.
  808.  
  809.   Args:     COUtilityCruiseCar* pBackObj,
  810.               Back pointer to the parent outer object.
  811.             IUnknown* pUnkOuter)
  812.               Pointer to the outer Unknown.  For delegation.
  813.  
  814.   Modifies: m_cRefI, m_pBackObj, m_pUnkOuter.
  815.  
  816.   Returns:  void
  817. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  818. COUtilityCruiseCar::CImpIUtility::CImpIUtility(
  819.   COUtilityCruiseCar* pBackObj,
  820.   IUnknown* pUnkOuter)
  821. {
  822.   // Init the Interface Ref Count (used for debugging only).
  823.   m_cRefI = 0;
  824.  
  825.   // Init the Back Object Pointer to point to the outer object.
  826.   m_pBackObj = pBackObj;
  827.  
  828.   // Init the CImpIUtility interface's delegating IUnknown pointer.  We use
  829.   // the Back Object pointer for IUnknown delegation here if we are not
  830.   // being aggregated.  If we are being aggregated we use the supplied
  831.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  832.   // assignment requires no AddRef because the CImpIUtility lifetime is
  833.   // quaranteed by the lifetime of the parent object in which
  834.   // CImpIUtility is nested.
  835.   if (NULL == pUnkOuter)
  836.   {
  837.     m_pUnkOuter = pBackObj;
  838.     LOG("C: COUtilityCruiseCar::CImpIUtility Constructor. Non-Aggregating.");
  839.   }
  840.   else
  841.   {
  842.     m_pUnkOuter = pUnkOuter;
  843.     LOG("C: COUtilityCruiseCar::CImpIUtility Constructor. Aggregating.");
  844.   }
  845.  
  846.   return;
  847. }
  848.  
  849.  
  850. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  851.   Method:   COUtilityCruiseCar::CImpIUtility::~CImpIUtility
  852.  
  853.   Summary:  Destructor for the CImpIUtility interface instantiation.
  854.  
  855.   Args:     void
  856.  
  857.   Modifies: .
  858.  
  859.   Returns:  void
  860. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  861. COUtilityCruiseCar::CImpIUtility::~CImpIUtility(void)
  862. {
  863.   LOG("C: COUtilityCruiseCar::CImpIUtility Destructor.");
  864.  
  865.   return;
  866. }
  867.  
  868.  
  869. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  870.   Method:   COUtilityCruiseCar::CImpIUtility::QueryInterface
  871.  
  872.   Summary:  The QueryInterface IUnknown member of this IUtility interface
  873.             implementation that delegates to m_pUnkOuter, whatever it is.
  874.  
  875.   Args:     REFIID riid,
  876.               [in] GUID of the Interface being requested.
  877.             PPVOID ppv)
  878.               [out] Address of the caller's pointer variable that will
  879.               receive the requested interface pointer.
  880.  
  881.   Modifies: .
  882.  
  883.   Returns:  HRESULT
  884.               Returned by the delegated outer QueryInterface call.
  885. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  886. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::QueryInterface(
  887.                REFIID riid,
  888.                PPVOID ppv)
  889. {
  890.   LOG("C: COUtilityCruiseCar::CImpIUtility::QueryInterface. Delegating.");
  891.  
  892.   // Delegate this call to the outer object's QueryInterface.
  893.   return m_pUnkOuter->QueryInterface(riid, ppv);
  894. }
  895.  
  896.  
  897. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  898.   Method:   COUtilityCruiseCar::CImpIUtility::AddRef
  899.  
  900.   Summary:  The AddRef IUnknown member of this IUtility interface
  901.             implementation that delegates to m_pUnkOuter, whatever it is.
  902.  
  903.   Args:     void
  904.  
  905.   Modifies: m_cRefI.
  906.  
  907.   Returns:  ULONG
  908.               Returned by the delegated outer AddRef call.
  909. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  910. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpIUtility::AddRef(void)
  911. {
  912.   // Increment the Interface Reference Count.
  913.   ++m_cRefI;
  914.  
  915.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Addref. Delegating. New cI=%i.", m_cRefI);
  916.  
  917.   // Delegate this call to the outer object's AddRef.
  918.   return m_pUnkOuter->AddRef();
  919. }
  920.  
  921.  
  922. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  923.   Method:   COUtilityCruiseCar::CImpIUtility::Release
  924.  
  925.   Summary:  The Release IUnknown member of this IUtility interface
  926.             implementation that delegates to m_pUnkOuter, whatever it is.
  927.  
  928.   Args:     void
  929.  
  930.   Modifies: .
  931.  
  932.   Returns:  ULONG
  933.               Returned by the delegated outer Release call.
  934. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  935. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpIUtility::Release(void)
  936. {
  937.   // Decrement the Interface Reference Count.
  938.   --m_cRefI;
  939.  
  940.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Release. Delegating. New cI=%i.", m_cRefI);
  941.  
  942.   // Delegate this call to the outer object's Release.
  943.   return m_pUnkOuter->Release();
  944. }
  945.  
  946.  
  947. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  948.   Method:   COUtilityCruiseCar::CImpIUtility::Offroad
  949.  
  950.   Summary:  The Offroad member method of this IUtility interface
  951.             implementation.  A simple empty method on a COUtilityCruiseCar
  952.             COM object for tutorial purposes.  Presumably if this
  953.             UtilityCruise Car object were modeling a real Car then the
  954.             Offroad method would function the 4-wheel drive transfer case
  955.             and shift it to the specified 4-wheel drive mode.
  956.  
  957.   Args:     short nGear
  958.               0 = 2H or regular 2-wheel drive;
  959.               1 = 4H or 4-wheel drive high speed;
  960.               2 = neutral; and
  961.               3 = 4L or 4-wheel drive low speed).
  962.  
  963.   Modifies: .
  964.  
  965.   Returns:  HRESULT
  966.               NOERROR
  967. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  968. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::Offroad(
  969.                short nGear)
  970. {
  971.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Offroad. Called. nGear=%i.",nGear);
  972.  
  973.   // We don't delegate because this IUtility implementation is native to
  974.   // the composite COUtilityCruiseCar object.
  975.  
  976.   return NOERROR;
  977. }
  978.  
  979.  
  980. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  981.   Method:   COUtilityCruiseCar::CImpIUtility::Winch
  982.  
  983.   Summary:  The Winch member method of this IUtility interface
  984.             implementation.  A simple empty method on a COUtilityCruiseCar
  985.             COM object for tutorial purposes.  Presumably if this
  986.             UtilityCruiseCar object were modeling a real Car then the
  987.             Winch method would turn on/off the front-mounted Winch to the
  988.             specified RPMs.
  989.  
  990.   Args:     short nRpm
  991.               0 = off; 1 - 50 RPM.
  992.  
  993.   Modifies: .
  994.  
  995.   Returns:  HRESULT
  996.               NOERROR
  997. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  998. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::Winch(
  999.                short nRpm)
  1000. {
  1001.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Winch. Called. nRpm=%i.",nRpm);
  1002.  
  1003.   // We don't delegate because this IUtility implementation is native to
  1004.   // the composite COUtilityCruiseCar object.
  1005.  
  1006.   return NOERROR;
  1007. }
  1008.  
  1009.  
  1010. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  1011.   Function: CreateUtilityCruiseCar
  1012.  
  1013.   Summary:  Creates an instance of the COUtilityCruiseCar COM object class
  1014.             returning a requested interface pointer. COUtilityCruiseCar
  1015.             uses the Containment reuse technique to incorporate
  1016.             COCruiseCar features (ie, ICar and ICruise implementations)
  1017.             into its Interface offerings of IUnknown and IUtility. With
  1018.             this containment, the ICar and ICruise interfaces are
  1019.             implemented in COUtilityCruiseCar as delegating interfaces
  1020.             that delegate to their matching interface implementations in
  1021.             an instance of the contained COCruiseCar.  COCruiseCar is
  1022.             provided by the outside APTSERVE.EXE server.
  1023.  
  1024.   Args:     IUnknown* pUnkOuter,
  1025.               Pointer the outer Unknown interface.  Non NULL implies
  1026.               that the new COM object is being created via an
  1027.               aggregation with an Outer object.  NULL implies that the
  1028.               object is not being created via aggregation.
  1029.             REFIID riid,
  1030.               The GUID of the interface requested on the new COM Object.
  1031.             PPVOID ppv)
  1032.               Address of the caller's pointer variable that will
  1033.               receive the requested interface pointer.
  1034.  
  1035.   Returns:  HRESULT
  1036.               NOERROR if successful, CLASS_E_NOAGREGATION if IUnknown is
  1037.               not requested with non-NULL pUnkOuter, or other errors as
  1038.               appropriate.
  1039. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  1040. HRESULT CreateUtilityCruiseCar(
  1041.           IUnknown* pUnkOuter,
  1042.           REFIID riid,
  1043.           PPVOID ppv)
  1044. {
  1045.   HRESULT hr;
  1046.   COUtilityCruiseCar* pCob;
  1047.  
  1048.   LOGF1("C: CreateUtilityCruiseCar. pUnkOuter=0x%X.",pUnkOuter);
  1049.  
  1050.   // If the creation call is requesting aggregation (pUnkOuter != NULL),
  1051.   // the COM rules state the IUnknown interface MUST also be concomitantly
  1052.   // requested.  If it is not so requested ( riid != IID_IUnknown) then
  1053.   // an error must be returned indicating that no aggregate creation of
  1054.   // the COUtilityCruiseCar COM Object can be performed using anything
  1055.   // other than a controlling IUnknown interface.
  1056.   if (NULL != pUnkOuter && riid != IID_IUnknown)
  1057.     hr = CLASS_E_NOAGGREGATION;
  1058.   else
  1059.   {
  1060.     // Instantiate a COUtilityCruiseCar COM Object.
  1061.     pCob = new COUtilityCruiseCar(pUnkOuter);
  1062.     if (NULL != pCob)
  1063.     {
  1064.       // If we have succeeded in instantiating the COUtilityCruiseCar object
  1065.       // we initialize it (with any subordinate COM objects) to offer it's
  1066.       // interfaces.
  1067.       hr = pCob->Init();
  1068.       if (SUCCEEDED(hr))
  1069.       {
  1070.         // We QueryInterface this new COM Object not only to deposit the
  1071.         // main interface pointer to the caller's pointer variable, but to
  1072.         // also automatically bump the Reference Count on the new COM
  1073.         // Object after handing out this *ppv reference to it.
  1074.         hr = pCob->QueryInterface(riid, (PPVOID)ppv);
  1075.       }
  1076.       else
  1077.         DELETE_POINTER(pCob);
  1078.     }
  1079.     else
  1080.       hr = E_OUTOFMEMORY;
  1081.   }
  1082.  
  1083.   if (SUCCEEDED(hr))
  1084.   {
  1085.     LOGF1("C: CreateUtilityCruiseCar Succeeded. *ppv=0x%X.",*ppv);
  1086.   }
  1087.   else
  1088.   {
  1089.     LOGF1("C: CreateUtilityCruiseCar Failed. hr=0x%X.",hr);
  1090.   }
  1091.  
  1092.   return hr;
  1093. }
  1094.