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 / comuser / utcrucar.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-05  |  21.3 KB  |  597 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 Aggregation 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 COMUSER.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:    8-29-95: atrent - Editor inheritance from NUKESUB.CPP.
  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 ICARS.H and CARGUIDS.H for the common car-related Interface
  46.     class, GUID, and CLSID specifications.
  47.   We include COMOBJ.H because it has the function prototypes and interface
  48.     declarations for the COM objects supplied by COMOBJ.DLL.
  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 <icars.h>
  55. #include <carguids.h>
  56. #include <comobj.h>
  57. #include "comuser.h"
  58. #include "utcrucar.h"
  59.  
  60.  
  61. /*---------------------------------------------------------------------------
  62.   COUtilityCruiseCar's implementation of its main COM object class including
  63.   Constructor, Destructor, QueryInterface, AddRef, and Release.
  64. ---------------------------------------------------------------------------*/
  65.  
  66. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  67.   Method:   COUtilityCruiseCar::COUtilityCruiseCar
  68.  
  69.   Summary:  COUtilityCruiseCar Constructor. Note the member initializer:
  70.             "m_ImpIUtility(this, pUnkOuter)" which is used to pass the 'this'
  71.             and pUnkOuter pointers of this constructor function to the
  72.             constructor in the instantiation of the implementation of
  73.             the CImpIUtility interface (which is nested inside this present
  74.             COUtilityCruiseCar Object Class).
  75.  
  76.   Args:     IUnknown* pUnkOuter)
  77.               Pointer to the the outer Unknown.  NULL means this COM Object
  78.               is not being Aggregated.  Non NULL means it is being created
  79.               on behalf of an outside COM object that is reusing it via
  80.               aggregation.
  81.  
  82.   Modifies: m_cRefs, m_pUnkOuter, m_pUnkCruiseCar.
  83.  
  84.   Returns:  void
  85. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  86. COUtilityCruiseCar::COUtilityCruiseCar(
  87.   IUnknown* pUnkOuter) :
  88.   m_ImpIUtility(this, pUnkOuter)
  89. {
  90.   // Zero the COM object's reference count.
  91.   m_cRefs = 0;
  92.  
  93.   // No AddRef necessary if non-NULL, as this COM object's lifetime
  94.   // is totally coupled with the controlling Outer object's lifetime.
  95.   m_pUnkOuter = pUnkOuter;
  96.  
  97.   // Zero the pointer to the aggregated COCruiseCar object's IUnknown
  98.   // interface (for delegation of IUnknown calls to it).
  99.   m_pUnkCruiseCar = NULL;
  100.  
  101.   LOGF1("E: COUtilityCruiseCar Constructor. m_pUnkOuter=0x%X.", m_pUnkOuter);
  102.  
  103.   return;
  104. }
  105.  
  106.  
  107. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  108.   Method:   COUtilityCruiseCar::~COUtilityCruiseCar
  109.  
  110.   Summary:  COUtilityCruiseCar Destructor.
  111.  
  112.   Args:     void
  113.  
  114.   Modifies: .
  115.  
  116.   Returns:  void
  117. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  118. COUtilityCruiseCar::~COUtilityCruiseCar(void)
  119. {
  120.   LOG("E: COUtilityCruiseCar::Destructor.");
  121.  
  122.   RELEASE_INTERFACE(m_pUnkCruiseCar);
  123.  
  124.   return;
  125. }
  126.  
  127.  
  128. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  129.   Method:   COUtilityCruiseCar::Init
  130.  
  131.   Summary:  COUtilityCruiseCar Initialization method.
  132.  
  133.   Args:     void
  134.  
  135.   Modifies: m_pUnkCruiseCar, m_pICar, m_pICruise, m_cRefs.
  136.  
  137.   Returns:  HRESULT
  138.               Standard result code. NOERROR for success.
  139. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  140. HRESULT COUtilityCruiseCar::Init(void)
  141. {
  142.   HRESULT hr;
  143.  
  144.   // Set up the right pIUnknown for delegation.  If we are being
  145.   // aggregated then we pass the pUnkOuter in turn to any COM objects
  146.   // that we are aggregating.  m_pUnkOuter was set in the Constructor.
  147.   IUnknown* pUnkOuter = (NULL == m_pUnkOuter) ? this : m_pUnkOuter;
  148.  
  149.   LOG("E: COUtilityCruiseCar::Init.");
  150.  
  151.   // We create an instance of the COCruiseCar object and do this via the
  152.   // Aggregation reuse technique.  Note we pass pUnkOuter as the
  153.   // Aggregation pointer.  It is the 'this' pointer to this present
  154.   // COUtilityCruiseCar object if we are not being aggregated; otherwise it
  155.   // is the pointer to the outermost object's controlling IUnknown.
  156.   // Following the rules of Aggregation we ask CreateCruiseCar for an
  157.   // IID_IUnknown interface.  We cache this pointer to the IUnknown of
  158.   // the new COCruiseCar COM object for later use in delegating
  159.   // IUnknown calls.
  160.   hr = CreateCruiseCar(pUnkOuter, IID_IUnknown, (PPVOID)&m_pUnkCruiseCar);
  161.  
  162.   return (hr);
  163. }
  164.  
  165.  
  166. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  167.   Method:   COUtilityCruiseCar::QueryInterface
  168.  
  169.   Summary:  QueryInterface of the COUtilityCruiseCar non-delegating
  170.             IUnknown implementation.
  171.  
  172.   Args:     REFIID riid,
  173.               [in] GUID of the Interface being requested.
  174.             PPVOID ppv)
  175.               [out] Address of the caller's pointer variable that will
  176.               receive the requested interface pointer.
  177.  
  178.   Modifies: .
  179.  
  180.   Returns:  HRESULT
  181. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  182. STDMETHODIMP COUtilityCruiseCar::QueryInterface(
  183.                REFIID riid,
  184.                PPVOID ppv)
  185. {
  186.   HRESULT hr = E_NOINTERFACE;
  187.   *ppv = NULL;
  188.  
  189.   if (IID_IUnknown == riid)
  190.   {
  191.     *ppv = this;
  192.     LOG("E: COUtilityCruiseCar::QueryInterface. 'this' pIUnknown returned.");
  193.   }
  194.   else if (IID_IUtility == riid)
  195.   {
  196.     // This IUtility interface is implemented in this COUtilityCruiseCar
  197.     // object as a native interface of COUtilityCruiseCar.
  198.     *ppv = &m_ImpIUtility;
  199.     LOG("E: COUtilityCruiseCar::QueryInterface. pIUtility returned.");
  200.   }
  201.  
  202.   if (NULL != *ppv)
  203.   {
  204.     // We've handed out a pointer to an interface so obey the COM rules
  205.     //   and AddRef its reference count.
  206.     ((LPUNKNOWN)*ppv)->AddRef();
  207.     hr = NOERROR;
  208.   }
  209.   else if (IID_ICar == riid)
  210.   {
  211.     LOG("E: COUtilityCruiseCar::QueryInterface. ICar delegating.");
  212.     // We didn't implement the ICar interface in this COUtilityCruiseCar
  213.     // object.  The aggregated inner object (CruiseCar) is contributing
  214.     // the ICar interface to this present composite or aggregating
  215.     // UtilityCruiseCar object.  So, to satisfy a QI request for the ICar
  216.     // interface, we delegate the QueryInterface to the inner
  217.     // object's IUnknown.
  218.     hr = m_pUnkCruiseCar->QueryInterface(riid, ppv);
  219.   }
  220.   else if (IID_ICruise == riid)
  221.   {
  222.     LOG("E: COUtilityCruiseCar::QueryInterface. ICruise delegating.");
  223.     // We didn't implement the ICruise interface in this COUtilityCruiseCar
  224.     // object.  The aggregated inner object (CruiseCar) is contributing
  225.     // the ICruise interface to this present composite or aggregating
  226.     // UtilityCruiseCar object.  As above we delegate this QI to the
  227.     // aggregated object's IUnknown.
  228.     hr = m_pUnkCruiseCar->QueryInterface(riid, ppv);
  229.   }
  230.  
  231.   return (hr);
  232. }
  233.  
  234.  
  235. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  236.   Method:   COUtilityCruiseCar::AddRef
  237.  
  238.   Summary:  AddRef of the COUtilityCruiseCar non-delegating
  239.             IUnknown implementation.
  240.  
  241.   Args:     void
  242.  
  243.   Modifies: m_cRefs.
  244.  
  245.   Returns:  ULONG
  246.               New value of m_cRefs (COM object's reference count).
  247. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  248. STDMETHODIMP_(ULONG) COUtilityCruiseCar::AddRef(void)
  249. {
  250.   m_cRefs++;
  251.  
  252.   LOGF1("E: COUtilityCruiseCar::AddRef. New cRefs=%i.", m_cRefs);
  253.  
  254.   return m_cRefs;
  255. }
  256.  
  257.  
  258. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  259.   Method:   COUtilityCruiseCar::Release
  260.  
  261.   Summary:  Release of the COUtilityCruiseCar non-delegating IUnknown
  262.             implementation.
  263.  
  264.   Args:     void
  265.  
  266.   Modifies: m_cRefs.
  267.  
  268.   Returns:  ULONG
  269.               New value of m_cRefs (COM object's reference count).
  270. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  271. STDMETHODIMP_(ULONG) COUtilityCruiseCar::Release(void)
  272. {
  273.   ULONG ulCount = --m_cRefs;
  274.  
  275.   LOGF1("E: COUtilityCruiseCar::Release. New cRefs=%i.", m_cRefs);
  276.  
  277.   if (0 == m_cRefs)
  278.   {
  279.     // We artificially bump the main ref count.  Thie fulfills one of
  280.     // the rules of aggregated objects and ensures that an indirect
  281.     // recursive call to this release won't occur because of other
  282.     // delegating releases that might happen in our own destructor.
  283.     m_cRefs++;
  284.     delete this;
  285.   }
  286.  
  287.   return ulCount;
  288. }
  289.  
  290.  
  291. /*---------------------------------------------------------------------------
  292.   COUtilityCruiseCar's nested implementation of the IUtility interface
  293.   including methods: Constructor, Destructor, QueryInterface, AddRef,
  294.   Release, Offroad, and Winch.
  295. ---------------------------------------------------------------------------*/
  296.  
  297. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  298.   Method:   COUtilityCruiseCar::CImpIUtility::CImpIUtility
  299.  
  300.   Summary:  Constructor for the CImpIUtility interface instantiation.
  301.  
  302.   Args:     COUtilityCruiseCar* pBackObj,
  303.               Back pointer to the parent outer object.
  304.             IUnknown* pUnkOuter)
  305.               Pointer to the outer Unknown.  For delegation.
  306.  
  307.   Modifies: m_cRefI, m_pBackObj, m_pUnkOuter.
  308.  
  309.   Returns:  void
  310. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  311. COUtilityCruiseCar::CImpIUtility::CImpIUtility(
  312.   COUtilityCruiseCar* pBackObj,
  313.   IUnknown* pUnkOuter)
  314. {
  315.   // Init the Interface Ref Count (used for debugging only).
  316.   m_cRefI = 0;
  317.  
  318.   // Init the Back Object Pointer to point to the outer object.
  319.   m_pBackObj = pBackObj;
  320.  
  321.   // Init the CImpIUtility interface's delegating IUnknown pointer.  We use
  322.   // the Back Object pointer for IUnknown delegation here if we are not
  323.   // being aggregated.  If we are being aggregated we use the supplied
  324.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  325.   // assignment requires no AddRef because the CImpIUtility lifetime is
  326.   // quaranteed by the lifetime of the parent object in which
  327.   // CImpIUtility is nested.
  328.   if (NULL == pUnkOuter)
  329.   {
  330.     m_pUnkOuter = pBackObj;
  331.     LOG("E: COUtilityCruiseCar::CImpIUtility Constructor. Non-Aggregating.");
  332.   }
  333.   else
  334.   {
  335.     m_pUnkOuter = pUnkOuter;
  336.     LOG("E: COUtilityCruiseCar::CImpIUtility Constructor. Aggregating.");
  337.   }
  338.  
  339.   return;
  340. }
  341.  
  342.  
  343. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  344.   Method:   COUtilityCruiseCar::CImpIUtility::~CImpIUtility
  345.  
  346.   Summary:  Destructor for the CImpIUtility interface instantiation.
  347.  
  348.   Args:     void
  349.  
  350.   Modifies: .
  351.  
  352.   Returns:  void
  353. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  354. COUtilityCruiseCar::CImpIUtility::~CImpIUtility(void)
  355. {
  356.   LOG("E: COUtilityCruiseCar::CImpIUtility Destructor.");
  357.  
  358.   return;
  359. }
  360.  
  361.  
  362. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  363.   Method:   COUtilityCruiseCar::CImpIUtility::QueryInterface
  364.  
  365.   Summary:  The QueryInterface IUnknown member of this IUtility interface
  366.             implementation that delegates to m_pUnkOuter, whatever it is.
  367.  
  368.   Args:     REFIID riid,
  369.               [in] GUID of the Interface being requested.
  370.             PPVOID ppv)
  371.               [out] Address of the caller's pointer variable that will
  372.               receive the requested interface pointer.
  373.  
  374.   Modifies: .
  375.  
  376.   Returns:  HRESULT
  377.               Returned by the delegated outer QueryInterface call.
  378. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  379. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::QueryInterface(
  380.                REFIID riid,
  381.                PPVOID ppv)
  382. {
  383.   LOG("E: COUtilityCruiseCar::CImpIUtility::QueryInterface. Delegating.");
  384.  
  385.   // Delegate this call to the outer object's QueryInterface.
  386.   return m_pUnkOuter->QueryInterface(riid, ppv);
  387. }
  388.  
  389.  
  390. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  391.   Method:   COUtilityCruiseCar::CImpIUtility::AddRef
  392.  
  393.   Summary:  The AddRef IUnknown member of this IUtility interface
  394.             implementation that delegates to m_pUnkOuter, whatever it is.
  395.  
  396.   Args:     void
  397.  
  398.   Modifies: m_cRefI.
  399.  
  400.   Returns:  ULONG
  401.               Returned by the delegated outer AddRef call.
  402. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  403. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpIUtility::AddRef(void)
  404. {
  405.   // Increment the Interface Reference Count.
  406.   ++m_cRefI;
  407.  
  408.   LOGF1("E: COUtilityCruiseCar::CImpIUtility::Addref. Delegating. New cI=%i.", m_cRefI);
  409.  
  410.   // Delegate this call to the outer object's AddRef.
  411.   return m_pUnkOuter->AddRef();
  412. }
  413.  
  414.  
  415. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  416.   Method:   COUtilityCruiseCar::CImpIUtility::Release
  417.  
  418.   Summary:  The Release IUnknown member of this IUtility interface
  419.             implementation that delegates to m_pUnkOuter, whatever it is.
  420.  
  421.   Args:     void
  422.  
  423.   Modifies: .
  424.  
  425.   Returns:  ULONG
  426.               Returned by the delegated outer Release call.
  427. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  428. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpIUtility::Release(void)
  429. {
  430.   // Decrement the Interface Reference Count.
  431.   --m_cRefI;
  432.  
  433.   LOGF1("E: COUtilityCruiseCar::CImpIUtility::Release. Delegating. New cI=%i.", m_cRefI);
  434.  
  435.   // Delegate this call to the outer object's Release.
  436.   return m_pUnkOuter->Release();
  437. }
  438.  
  439.  
  440. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  441.   Method:   COUtilityCruiseCar::CImpIUtility::Offroad
  442.  
  443.   Summary:  The Offroad member method of this IUtility interface
  444.             implementation.  A simple empty method on a COUtilityCruiseCar
  445.             COM object for tutorial purposes.  Presumably if this
  446.             UtilityCruise Car object were modeling a real Car then the
  447.             Offroad method would function the 4-wheel drive transfer case
  448.             and shift it to the specified 4-wheel drive mode.
  449.  
  450.   Args:     short nGear
  451.               0 = 2H or regular 2-wheel drive;
  452.               1 = 4H or 4-wheel drive high speed;
  453.               2 = neutral; and
  454.               3 = 4L or 4-wheel drive low speed).
  455.  
  456.   Modifies: .
  457.  
  458.   Returns:  HRESULT
  459.               NOERROR
  460. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  461. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::Offroad(
  462.                short nGear)
  463. {
  464.   HRESULT hr;
  465.   ICar* pICar = NULL;
  466.  
  467.   // In our fantasy Sport-Utility Car world we may need to stop the car
  468.   // before switching to 4-Wheel drive low (nGear == 3 for 4L). Let's
  469.   // assume so because it's a convenient excuse to show this aggregating
  470.   // COUtilityCruiseCar outer object using one of the interfaces (ICar)
  471.   // of its aggregated COCruiseCar inner object.  COMUSER gracefully
  472.   // cooperates in this by invoking this Offroad method from the
  473.   // UtilityCruiseCar menu with nGear == 3.
  474.   if (3 == nGear)
  475.   {
  476.     hr = m_pBackObj->m_pUnkCruiseCar->QueryInterface(
  477.                                         IID_ICar,
  478.                                         (PPVOID)&pICar);
  479.     if (SUCCEEDED(hr))
  480.     {
  481.       m_pUnkOuter->Release();
  482.       pICar->Speed(0);
  483.       m_pUnkOuter->AddRef();
  484.       pICar->Release();
  485.     }
  486.   }
  487.  
  488.   LOGF1("E: COUtilityCruiseCar::CImpIUtility::Offroad. Called. nGear=%i.",nGear);
  489.  
  490.   return NOERROR;
  491. }
  492.  
  493.  
  494. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  495.   Method:   COUtilityCruiseCar::CImpIUtility::Winch
  496.  
  497.   Summary:  The Adjust member method of this IUtility interface
  498.             implementation.  A simple empty method on a COUtilityCruiseCar
  499.             COM object for tutorial purposes.  Presumably if this
  500.             UtilityCruiseCar object were modeling a real Car then the
  501.             Winch method would turn on/off the front-mounted Winch to the
  502.             specified RPMs.
  503.  
  504.   Args:     short nRpm
  505.               0 = off; 1 - 50 RPM.
  506.  
  507.   Modifies: .
  508.  
  509.   Returns:  HRESULT
  510.               NOERROR
  511. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  512. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::Winch(
  513.                short nRpm)
  514. {
  515.   LOGF1("E: COUtilityCruiseCar::CImpIUtility::Winch. Called. nRpm=%i.",nRpm);
  516.  
  517.   return NOERROR;
  518. }
  519.  
  520.  
  521. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  522.   Function: CreateUtilityCruiseCar
  523.  
  524.   Summary:  Creates an instance of the COUtilityCruiseCar COM object class
  525.             returning a requested interface pointer. COUtilityCruiseCar
  526.             uses the Aggregation reuse technique to incorporate
  527.             COCruiseCar features (ie, ICar and ICruise implementations)
  528.             into its Interface offerings (ie, IUnknown, and IUtility).
  529.             With this aggregation, the ICar and ICruise interfaces are
  530.             not implemented in COUtilityCruiseCar.  They are instead
  531.             solely implemented in a COCruiseCar object that
  532.             CreateUtilityCruiseCar instantiates.  That COCruiseCar's ICar
  533.             and ICruise implementations are used directly in this
  534.             aggregation.  COCruiseCar is provided by the outside COMOBJ.DLL.
  535.  
  536.   Args:     IUnknown* pUnkOuter,
  537.               Pointer the outer Unknown interface.  Non NULL implies
  538.               that the new COM object is being created via an
  539.               aggregation with an Outer object.  NULL implies that the
  540.               object is not being created via aggregation.
  541.             REFIID riid,
  542.               The GUID of the interface requested on the new COM Object.
  543.             PPVOID ppv)
  544.               Address of the caller's pointer variable that will
  545.               receive the requested interface pointer.
  546.  
  547.   Returns:  HRESULT
  548.               NOERROR if successful, CLASS_E_NOAGREGATION if IUnknown is
  549.               not requested with non-NULL pUnkOuter, or other errors as
  550.               appropriate.
  551. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  552. HRESULT CreateUtilityCruiseCar(
  553.           IUnknown* pUnkOuter,
  554.           REFIID riid,
  555.           PPVOID ppv)
  556. {
  557.   HRESULT hr;
  558.   COUtilityCruiseCar* pCob;
  559.  
  560.   LOGF1("E: CreateUtilityCruiseCar. pUnkOuter=0x%X.",pUnkOuter);
  561.  
  562.   // If the creation call is requesting aggregation (pUnkOuter != NULL),
  563.   // the COM rules state the IUnknown interface MUST also be concomitantly
  564.   // requested.  If it is not so requested ( riid != IID_IUnknown) then
  565.   // an error must be returned indicating that no aggregate creation of
  566.   // the COUtilityCruiseCar COM Object can be performed using anything
  567.   // other than a controlling IUnknown interface.
  568.   if (NULL != pUnkOuter && riid != IID_IUnknown)
  569.     hr = CLASS_E_NOAGGREGATION;
  570.   else
  571.   {
  572.     // Instantiate a COUtilityCruiseCar COM Object.
  573.     pCob = new COUtilityCruiseCar(pUnkOuter);
  574.     if (NULL != pCob)
  575.     {
  576.       // If we have succeeded in instantiating the COUtilityCruiseCar object
  577.       // we initialize it to offer it's interfaces.
  578.       hr = pCob->Init();
  579.       if (SUCCEEDED(hr))
  580.       {
  581.         // We QueryInterface this new COM Object not only to deposit the
  582.         // main interface pointer to the caller's pointer variable, but to
  583.         // also automatically bump the Reference Count on the new COM
  584.         // Object after handing out this *ppv reference to it.
  585.         hr = pCob->QueryInterface(riid, (PPVOID)ppv);
  586.       }
  587.     }
  588.     else
  589.       hr = E_OUTOFMEMORY;
  590.   }
  591.  
  592.   if (SUCCEEDED(hr))
  593.     LOGF1("E: CreateUtilityCruiseCar Succeeded. *ppv=0x%X.",*ppv);
  594.  
  595.   return hr;
  596. }
  597.