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