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