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 / licclien / utcrucar.cpp < prev    next >
C/C++ Source or Header  |  1997-08-05  |  22KB  |  634 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 COLicCruiseCar'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:    10-5-95: atrent - Editor inheritance from DLLCLIEN source.
  23.  
  24. ----------------------------------------------------------------------------
  25.   This file is part of the Microsoft COM Tutorial Code Samples.
  26.  
  27.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  28.  
  29.   This source code is intended only as a supplement to Microsoft
  30.   Development Tools and/or on-line documentation.  See these other
  31.   materials for detailed information regarding Microsoft code samples.
  32.  
  33.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  34.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  35.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  36.   PARTICULAR PURPOSE.
  37. ==========================================================================+*/
  38.  
  39. /*---------------------------------------------------------------------------
  40.   We include WINDOWS.H for all Win32 applications.
  41.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  42.   We include OLECTL.H because we will using IClassFactory2.
  43.   We include APPUTIL.H because we will be building this application using
  44.     the convenient Virtual Window and Dialog classes and other
  45.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  46.   We include ICARS.H and CARGUIDS.H for the common car-related Interface
  47.     class, GUID, and CLSID specifications.
  48.   We include LICCLIEN.H to support this module's use of trace logging.
  49.   We include UTCRUCAR.H because it has the COUtilityCruiseCar declarations.
  50. ---------------------------------------------------------------------------*/
  51. #include <windows.h>
  52. #include <ole2.h>
  53. #include <olectl.h>
  54. #include <apputil.h>
  55. #include <icars.h>
  56. #include <carguids.h>
  57. #include "licclien.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 COLicCruiseCar object's IUnknown
  98.   // interface (for delegation of IUnknown calls to it).
  99.   m_pUnkCruiseCar = NULL;
  100.  
  101.   LOGF1("C: 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("C: 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:     BSTR bstrLicKey
  134.               Runtime license key string.
  135.  
  136.   Modifies: m_pUnkCruiseCar, m_pICar, m_pICruise, m_cRefs.
  137.  
  138.   Returns:  HRESULT
  139.               Standard result code. NOERROR for success.
  140. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  141. HRESULT COUtilityCruiseCar::Init(
  142.           BSTR bstrLicKey)
  143. {
  144.   HRESULT hr;
  145.   IClassFactory2* pICF2LicCruiseCar;
  146.  
  147.   // Set up the right pIUnknown for delegation.  If we are being
  148.   // aggregated then we pass the pUnkOuter in turn to any COM objects
  149.   // that we are aggregating.  m_pUnkOuter was set in the Constructor.
  150.   IUnknown* pUnkOuter = (NULL == m_pUnkOuter) ? this : m_pUnkOuter;
  151.  
  152.   LOG("C: COUtilityCruiseCar::Init.");
  153.  
  154.   // Get a class factory for LicCruiseCar and issue IClassFactory's
  155.   // CreateInstance method to manufacture a COLicCruiseCar COM object.
  156.   hr = CoGetClassObject(
  157.          CLSID_LicCruiseCar,
  158.          CLSCTX_INPROC_SERVER,
  159.          NULL,
  160.          IID_IClassFactory2,
  161.          (PPVOID)&pICF2LicCruiseCar);
  162.   if (SUCCEEDED(hr))
  163.   {
  164.     LOG("C: COUtilityCruiseCar::Init IClassFactory2 obtained.");
  165.     hr = pICF2LicCruiseCar->CreateInstanceLic(
  166.                               pUnkOuter,
  167.                               NULL,
  168.                               IID_IUnknown,
  169.                               bstrLicKey,
  170.                               (PPVOID)&m_pUnkCruiseCar);
  171.     pICF2LicCruiseCar->Release();
  172.     if (SUCCEEDED(hr))
  173.     {
  174.       LOG("C: COUtilityCruiseCar::Init Created LicCruiseCar using License Key.");
  175.     }
  176.     else
  177.     {
  178.       LOG("C: COUtilityCruiseCar::Init Unable to Create LicCruiseCar.");
  179.     }
  180.   }
  181.  
  182.   if (SUCCEEDED(hr))
  183.   {
  184.     LOG("C: COUtilityCruiseCar::Init Succeeded.");
  185.   }
  186.   else
  187.   {
  188.     LOG("C: COUtilityCruiseCar::Init Failed.");
  189.   }
  190.  
  191.   return (hr);
  192. }
  193.  
  194.  
  195. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  196.   Method:   COUtilityCruiseCar::QueryInterface
  197.  
  198.   Summary:  QueryInterface of the COUtilityCruiseCar non-delegating
  199.             IUnknown implementation.
  200.  
  201.   Args:     REFIID riid,
  202.               [in] GUID of the Interface being requested.
  203.             PPVOID ppv)
  204.               [out] Address of the caller's pointer variable that will
  205.               receive the requested interface pointer.
  206.  
  207.   Modifies: .
  208.  
  209.   Returns:  HRESULT
  210. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  211. STDMETHODIMP COUtilityCruiseCar::QueryInterface(
  212.                REFIID riid,
  213.                PPVOID ppv)
  214. {
  215.   HRESULT hr = E_NOINTERFACE;
  216.   *ppv = NULL;
  217.  
  218.   if (IID_IUnknown == riid)
  219.   {
  220.     *ppv = this;
  221.     LOG("C: COUtilityCruiseCar::QueryInterface. 'this' pIUnknown returned.");
  222.   }
  223.   else if (IID_IUtility == riid)
  224.   {
  225.     // This IUtility interface is implemented in this COUtilityCruiseCar
  226.     // object as a native interface of COUtilityCruiseCar.
  227.     *ppv = &m_ImpIUtility;
  228.     LOG("C: COUtilityCruiseCar::QueryInterface. pIUtility returned.");
  229.   }
  230.  
  231.   if (NULL != *ppv)
  232.   {
  233.     // We've handed out a pointer to an interface so obey the COM rules
  234.     //   and AddRef its reference count.
  235.     ((LPUNKNOWN)*ppv)->AddRef();
  236.     hr = NOERROR;
  237.   }
  238.   else if (IID_ICar == riid)
  239.   {
  240.     LOG("C: COUtilityCruiseCar::QueryInterface. ICar delegating.");
  241.     // We didn't implement the ICar interface in this COUtilityCruiseCar
  242.     // object.  The aggregated inner object (LicCruiseCar) is contributing
  243.     // the ICar interface to this present composite or aggregating
  244.     // UtilityCruiseCar object.  So, to satisfy a QI request for the ICar
  245.     // interface, we delegate the QueryInterface to the inner
  246.     // object's IUnknown.
  247.     hr = m_pUnkCruiseCar->QueryInterface(riid, ppv);
  248.   }
  249.   else if (IID_ICruise == riid)
  250.   {
  251.     LOG("C: COUtilityCruiseCar::QueryInterface. ICruise delegating.");
  252.     // We didn't implement the ICruise interface in this COUtilityCruiseCar
  253.     // object.  The aggregated inner object (LicCruiseCar) is contributing
  254.     // the ICruise interface to this present composite or aggregating
  255.     // UtilityCruiseCar object.  As above we delegate this QI to the
  256.     // aggregated object's IUnknown.
  257.     hr = m_pUnkCruiseCar->QueryInterface(riid, ppv);
  258.   }
  259.  
  260.   return (hr);
  261. }
  262.  
  263.  
  264. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  265.   Method:   COUtilityCruiseCar::AddRef
  266.  
  267.   Summary:  AddRef of the COUtilityCruiseCar non-delegating
  268.             IUnknown implementation.
  269.  
  270.   Args:     void
  271.  
  272.   Modifies: m_cRefs.
  273.  
  274.   Returns:  ULONG
  275.               New value of m_cRefs (COM object's reference count).
  276. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  277. STDMETHODIMP_(ULONG) COUtilityCruiseCar::AddRef(void)
  278. {
  279.   m_cRefs++;
  280.  
  281.   LOGF1("C: COUtilityCruiseCar::AddRef. New cRefs=%i.", m_cRefs);
  282.  
  283.   return m_cRefs;
  284. }
  285.  
  286.  
  287. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  288.   Method:   COUtilityCruiseCar::Release
  289.  
  290.   Summary:  Release of the COUtilityCruiseCar non-delegating IUnknown
  291.             implementation.
  292.  
  293.   Args:     void
  294.  
  295.   Modifies: m_cRefs.
  296.  
  297.   Returns:  ULONG
  298.               New value of m_cRefs (COM object's reference count).
  299. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  300. STDMETHODIMP_(ULONG) COUtilityCruiseCar::Release(void)
  301. {
  302.   ULONG ulCount = --m_cRefs;
  303.  
  304.   LOGF1("C: COUtilityCruiseCar::Release. New cRefs=%i.", m_cRefs);
  305.  
  306.   if (0 == m_cRefs)
  307.   {
  308.     // We artificially bump the main ref count.  Thie fulfills one of
  309.     // the rules of aggregated objects and ensures that an indirect
  310.     // recursive call to this release won't occur because of other
  311.     // delegating releases that might happen in our own destructor.
  312.     m_cRefs++;
  313.     delete this;
  314.   }
  315.  
  316.   return ulCount;
  317. }
  318.  
  319.  
  320. /*---------------------------------------------------------------------------
  321.   COUtilityCruiseCar's nested implementation of the IUtility interface
  322.   including methods: Constructor, Destructor, QueryInterface, AddRef,
  323.   Release, Offroad, and Winch.
  324. ---------------------------------------------------------------------------*/
  325.  
  326. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  327.   Method:   COUtilityCruiseCar::CImpIUtility::CImpIUtility
  328.  
  329.   Summary:  Constructor for the CImpIUtility interface instantiation.
  330.  
  331.   Args:     COUtilityCruiseCar* pBackObj,
  332.               Back pointer to the parent outer object.
  333.             IUnknown* pUnkOuter)
  334.               Pointer to the outer Unknown.  For delegation.
  335.  
  336.   Modifies: m_cRefI, m_pBackObj, m_pUnkOuter.
  337.  
  338.   Returns:  void
  339. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  340. COUtilityCruiseCar::CImpIUtility::CImpIUtility(
  341.   COUtilityCruiseCar* pBackObj,
  342.   IUnknown* pUnkOuter)
  343. {
  344.   // Init the Interface Ref Count (used for debugging only).
  345.   m_cRefI = 0;
  346.  
  347.   // Init the Back Object Pointer to point to the outer object.
  348.   m_pBackObj = pBackObj;
  349.  
  350.   // Init the CImpIUtility interface's delegating IUnknown pointer.  We use
  351.   // the Back Object pointer for IUnknown delegation here if we are not
  352.   // being aggregated.  If we are being aggregated we use the supplied
  353.   // pUnkOuter for IUnknown delegation.  In either case the pointer
  354.   // assignment requires no AddRef because the CImpIUtility lifetime is
  355.   // quaranteed by the lifetime of the parent object in which
  356.   // CImpIUtility is nested.
  357.   if (NULL == pUnkOuter)
  358.   {
  359.     m_pUnkOuter = pBackObj;
  360.     LOG("C: COUtilityCruiseCar::CImpIUtility Constructor. Non-Aggregating.");
  361.   }
  362.   else
  363.   {
  364.     m_pUnkOuter = pUnkOuter;
  365.     LOG("C: COUtilityCruiseCar::CImpIUtility Constructor. Aggregating.");
  366.   }
  367.  
  368.   return;
  369. }
  370.  
  371.  
  372. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  373.   Method:   COUtilityCruiseCar::CImpIUtility::~CImpIUtility
  374.  
  375.   Summary:  Destructor for the CImpIUtility interface instantiation.
  376.  
  377.   Args:     void
  378.  
  379.   Modifies: .
  380.  
  381.   Returns:  void
  382. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  383. COUtilityCruiseCar::CImpIUtility::~CImpIUtility(void)
  384. {
  385.   LOG("C: COUtilityCruiseCar::CImpIUtility Destructor.");
  386.  
  387.   return;
  388. }
  389.  
  390.  
  391. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  392.   Method:   COUtilityCruiseCar::CImpIUtility::QueryInterface
  393.  
  394.   Summary:  The QueryInterface IUnknown member of this IUtility interface
  395.             implementation that delegates to m_pUnkOuter, whatever it is.
  396.  
  397.   Args:     REFIID riid,
  398.               [in] GUID of the Interface being requested.
  399.             PPVOID ppv)
  400.               [out] Address of the caller's pointer variable that will
  401.               receive the requested interface pointer.
  402.  
  403.   Modifies: .
  404.  
  405.   Returns:  HRESULT
  406.               Returned by the delegated outer QueryInterface call.
  407. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  408. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::QueryInterface(
  409.                REFIID riid,
  410.                PPVOID ppv)
  411. {
  412.   LOG("C: COUtilityCruiseCar::CImpIUtility::QueryInterface. Delegating.");
  413.  
  414.   // Delegate this call to the outer object's QueryInterface.
  415.   return m_pUnkOuter->QueryInterface(riid, ppv);
  416. }
  417.  
  418.  
  419. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  420.   Method:   COUtilityCruiseCar::CImpIUtility::AddRef
  421.  
  422.   Summary:  The AddRef IUnknown member of this IUtility interface
  423.             implementation that delegates to m_pUnkOuter, whatever it is.
  424.  
  425.   Args:     void
  426.  
  427.   Modifies: m_cRefI.
  428.  
  429.   Returns:  ULONG
  430.               Returned by the delegated outer AddRef call.
  431. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  432. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpIUtility::AddRef(void)
  433. {
  434.   // Increment the Interface Reference Count.
  435.   ++m_cRefI;
  436.  
  437.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Addref. Delegating. New cI=%i.", m_cRefI);
  438.  
  439.   // Delegate this call to the outer object's AddRef.
  440.   return m_pUnkOuter->AddRef();
  441. }
  442.  
  443.  
  444. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  445.   Method:   COUtilityCruiseCar::CImpIUtility::Release
  446.  
  447.   Summary:  The Release IUnknown member of this IUtility interface
  448.             implementation that delegates to m_pUnkOuter, whatever it is.
  449.  
  450.   Args:     void
  451.  
  452.   Modifies: .
  453.  
  454.   Returns:  ULONG
  455.               Returned by the delegated outer Release call.
  456. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  457. STDMETHODIMP_(ULONG) COUtilityCruiseCar::CImpIUtility::Release(void)
  458. {
  459.   // Decrement the Interface Reference Count.
  460.   --m_cRefI;
  461.  
  462.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Release. Delegating. New cI=%i.", m_cRefI);
  463.  
  464.   // Delegate this call to the outer object's Release.
  465.   return m_pUnkOuter->Release();
  466. }
  467.  
  468.  
  469. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  470.   Method:   COUtilityCruiseCar::CImpIUtility::Offroad
  471.  
  472.   Summary:  The Offroad member method of this IUtility interface
  473.             implementation.  A simple empty method on a COUtilityCruiseCar
  474.             COM object for tutorial purposes.  Presumably if this
  475.             UtilityCruise Car object were modeling a real Car then the
  476.             Offroad method would function the 4-wheel drive transfer case
  477.             and shift it to the specified 4-wheel drive mode.
  478.  
  479.   Args:     short nGear
  480.               0 = 2H or regular 2-wheel drive;
  481.               1 = 4H or 4-wheel drive high speed;
  482.               2 = neutral; and
  483.               3 = 4L or 4-wheel drive low speed).
  484.  
  485.   Modifies: .
  486.  
  487.   Returns:  HRESULT
  488.               NOERROR
  489. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  490. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::Offroad(
  491.                short nGear)
  492. {
  493.   HRESULT hr;
  494.   ICar* pICar = NULL;
  495.  
  496.   // In our fantasy Sport-Utility Car world we may need to stop the car
  497.   // before switching to 4-Wheel drive low (nGear == 3 for 4L). Let's
  498.   // assume so because it's a convenient excuse to show this aggregating
  499.   // COUtilityCruiseCar outer object using one of the interfaces (ICar)
  500.   // of its aggregated COLicCruiseCar inner object.  LICCLIEN gracefully
  501.   // cooperates in this by invoking this Offroad method from the
  502.   // UtilityCruiseCar menu with nGear == 3.
  503.   if (3 == nGear)
  504.   {
  505.     hr = m_pBackObj->m_pUnkCruiseCar->QueryInterface(
  506.                                         IID_ICar,
  507.                                         (PPVOID)&pICar);
  508.     if (SUCCEEDED(hr))
  509.     {
  510.       m_pUnkOuter->Release();
  511.       pICar->Speed(0);
  512.       m_pUnkOuter->AddRef();
  513.       pICar->Release();
  514.     }
  515.   }
  516.  
  517.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Offroad. Called. nGear=%i.",nGear);
  518.  
  519.   return NOERROR;
  520. }
  521.  
  522.  
  523. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  524.   Method:   COUtilityCruiseCar::CImpIUtility::Winch
  525.  
  526.   Summary:  The Adjust member method of this IUtility interface
  527.             implementation.  A simple empty method on a COUtilityCruiseCar
  528.             COM object for tutorial purposes.  Presumably if this
  529.             UtilityCruiseCar object were modeling a real Car then the
  530.             Winch method would turn on/off the front-mounted Winch to the
  531.             specified RPMs.
  532.  
  533.   Args:     short nRpm
  534.               0 = off; 1 - 50 RPM.
  535.  
  536.   Modifies: .
  537.  
  538.   Returns:  HRESULT
  539.               NOERROR
  540. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  541. STDMETHODIMP COUtilityCruiseCar::CImpIUtility::Winch(
  542.                short nRpm)
  543. {
  544.   LOGF1("C: COUtilityCruiseCar::CImpIUtility::Winch. Called. nRpm=%i.",nRpm);
  545.  
  546.   return NOERROR;
  547. }
  548.  
  549.  
  550. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  551.   Function: CreateUtilityCruiseCar
  552.  
  553.   Summary:  Creates an instance of the COUtilityCruiseCar COM object class
  554.             returning a requested interface pointer. COUtilityCruiseCar
  555.             uses the Aggregation reuse technique to incorporate
  556.             COLicCruiseCar features (ie, ICar and ICruise implementations)
  557.             into its Interface offerings (ie, IUnknown, and IUtility).
  558.             With this aggregation, the ICar and ICruise interfaces are not
  559.             implemented in COUtilityCruiseCar.  They are instead solely
  560.             implemented in a COLicCruiseCar object that
  561.             CreateUtilityCruiseCar instantiates.  That COLicCruiseCar's ICar
  562.             and ICruise implementations are used directly in this
  563.             aggregation.  COLicCruiseCar is provided as a licensed component
  564.             by the outside LICSERVE.DLL server.
  565.  
  566.   Args:     IUnknown* pUnkOuter,
  567.               Pointer the outer Unknown interface.  Non NULL implies
  568.               that the new COM object is being created via an
  569.               aggregation with an Outer object.  NULL implies that the
  570.               object is not being created via aggregation.
  571.             REFIID riid,
  572.               The GUID of the interface requested on the new COM Object.
  573.             PPVOID ppv)
  574.               Address of the caller's pointer variable that will
  575.               receive the requested interface pointer.
  576.  
  577.   Returns:  HRESULT
  578.               NOERROR if successful, CLASS_E_NOAGREGATION if IUnknown is
  579.               not requested with non-NULL pUnkOuter, or other errors as
  580.               appropriate.
  581. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  582. HRESULT CreateUtilityCruiseCar(
  583.           IUnknown* pUnkOuter,
  584.           REFIID riid,
  585.           BSTR bstrLicKey,
  586.           PPVOID ppv)
  587. {
  588.   HRESULT hr;
  589.   COUtilityCruiseCar* pCob;
  590.  
  591.   LOGF1("C: CreateUtilityCruiseCar. pUnkOuter=0x%X.",pUnkOuter);
  592.  
  593.   // If the creation call is requesting aggregation (pUnkOuter != NULL),
  594.   // the COM rules state the IUnknown interface MUST also be concomitantly
  595.   // requested.  If it is not so requested ( riid != IID_IUnknown) then
  596.   // an error must be returned indicating that no aggregate creation of
  597.   // the COUtilityCruiseCar COM Object can be performed using anything
  598.   // other than a controlling IUnknown interface.
  599.   if (NULL != pUnkOuter && riid != IID_IUnknown)
  600.     hr = CLASS_E_NOAGGREGATION;
  601.   else
  602.   {
  603.     // Instantiate a COUtilityCruiseCar COM Object.
  604.     pCob = new COUtilityCruiseCar(pUnkOuter);
  605.     if (NULL != pCob)
  606.     {
  607.       // If we have succeeded in instantiating the COUtilityCruiseCar object
  608.       // we initialize it to offer it's interfaces.
  609.       hr = pCob->Init(bstrLicKey);
  610.       if (SUCCEEDED(hr))
  611.       {
  612.         // We QueryInterface this new COM Object not only to deposit the
  613.         // main interface pointer to the caller's pointer variable, but to
  614.         // also automatically bump the Reference Count on the new COM
  615.         // Object after handing out this *ppv reference to it.
  616.         hr = pCob->QueryInterface(riid, (PPVOID)ppv);
  617.       }
  618.     }
  619.     else
  620.       hr = E_OUTOFMEMORY;
  621.   }
  622.  
  623.   if (SUCCEEDED(hr))
  624.   {
  625.     LOGF1("C: CreateUtilityCruiseCar Succeeded. *ppv=0x%X.",*ppv);
  626.   }
  627.   else
  628.   {
  629.     LOG("C: CreateUtilityCruiseCar Failed.");
  630.   }
  631.  
  632.   return hr;
  633. }
  634.