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 / comobj / comobj.cpp < prev    next >
C/C++ Source or Header  |  1997-08-05  |  19KB  |  473 lines

  1. /*+==========================================================================
  2.   File:      COMOBJ.CPP
  3.  
  4.   Summary:   Implementation file for a primitive DLL server providing
  5.              several Car-related COM Objects.  This is not a full-blown
  6.              COM Server.  Rather it is a primitive COM Object server
  7.              offering the following COM objects: Car, UtilityCar, and
  8.              CruiseCar.  Appropriate create functions are exported from
  9.              this DLL: CreateCar, CreateUtilityCar, and CreateCruiseCar.
  10.  
  11.              For a comprehensive tutorial code tour of COMOBJ's
  12.              contents and offerings see the tutorial COMOBJ.HTM file.
  13.              For more specific technical details on the internal workings
  14.              see the comments dispersed throughout the COMOBJ source code.
  15.  
  16.   Classes:   none.
  17.  
  18.   Functions: DllMain, ComObjInitMsgLog, ComObjAboutBox, CreateCar,
  19.              CreateUtilityCar, CreateCruiseCar
  20.  
  21.   Origin:    8-20-95: atrent - Editor-inheritance from DLLSKEL.CPP in
  22.                the DLLSKEL Tutorial Code Sample.
  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 INITGUID.H only once (here) in the entire DLL because we
  43.     will be defining GUIDs and want them as constants in the data segment.
  44.   We include APPUTIL.H because we will be building this DLL using
  45.     the convenient Virtual Window and Dialog classes and other
  46.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  47.   We include ICARS.H and CARGUIDS.H for the common car-related Interface
  48.     class, GUID, and CLSID specifications.
  49.   We include COMOBJI.H because it has the necessary internal class and
  50.     resource definitions for this DLL.
  51.   We include COMOBJ.H because it has the necessary DLLENTRY function
  52.     prototypes.  The _DLLEXPORT_ #define is used to tell COMOBJ.H to
  53.     define the appropriate functions as exported from this DLL.
  54.     Otherwise, COMOBJ.H is included by users of this DLL who do not
  55.     define _DLLEXPORT_ so that the appropriate functions are then
  56.     declared as imports rather than defined as exports.  COMOBJ.H also
  57.     has the necessary interface declarations for ICar, IUtility, and ICruise.
  58.   We include CAR.H, UTILCAR,H, and, CRUCAR.H for the object class
  59.     declarations for the COCar, COUtilityCar, and COCruiseCar COM objects.
  60. ---------------------------------------------------------------------------*/
  61. #include <windows.h>
  62. #include <ole2.h>
  63. #include <initguid.h>
  64. #include <apputil.h>
  65. #include <icars.h>
  66. #include <carguids.h>
  67. #include "comobji.h"
  68. #define _DLLEXPORT_
  69. #include "comobj.h"
  70. #include "car.h"
  71. #include "utilcar.h"
  72. #include "crucar.h"
  73.  
  74.  
  75. // Global variable definitions. Initialized in DllMain() below.
  76.  
  77. // Here is a pointer for use by the global Debug Message logging macros.
  78. // Set by the ComObjInitMsgLog function call from an outside EXE user.
  79. CMsgLog* g_pMsgLog;
  80.  
  81. // We encapsulate most of the global data for clarity.  Here is a
  82. // global pointer to the DllData object.
  83. CDllData* g_pDll;
  84.  
  85.  
  86. /*F+F++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  87.   Function: UnicodeOk
  88.  
  89.   Summary:  Checks if the platform will handle unicode versions of
  90.             Win32 string API calls.
  91.  
  92.   Args:     void
  93.  
  94.   Returns:  BOOL
  95.               TRUE if unicode support; FALSE if not.
  96. ------------------------------------------------------------------------F-F*/
  97. BOOL UnicodeOk(void)
  98. {
  99.   BOOL bOk = TRUE;
  100.   TCHAR szUserName[MAX_STRING_LENGTH];
  101.   DWORD dwSize = MAX_STRING_LENGTH;
  102.  
  103.   if (!GetUserName(szUserName, &dwSize))
  104.     bOk = ERROR_CALL_NOT_IMPLEMENTED == GetLastError() ? FALSE : TRUE;
  105.  
  106.   return bOk;
  107. }
  108.  
  109.  
  110. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  111.   Function: DllMain
  112.  
  113.   Summary:  Like WinMain is for an EXE application, this DllMain function
  114.             is the main entry point for this DLL.  It is called when the
  115.             DLL is loaded by a process, and when new threads are created
  116.             by a process that has already loaded this DLL.  DllMain is also
  117.             called when threads of a process that has loaded the DLL exit
  118.             cleanly and when the process itself unloads the DLL.
  119.  
  120.             If you want to use C runtime libraries, keep this function
  121.             named "DllMain" and you won't have to do anything special to
  122.             initialize the runtime libraries.
  123.  
  124.             When fdwReason == DLL_PROCESS_ATTACH, the return value is used
  125.             to determine if the DLL should remain loaded, or should be
  126.             immediately unloaded depending upon whether the DLL could be
  127.             initialized properly.  For all other values of fdwReason,
  128.             the return value is ignored.
  129.  
  130.   Args:     HINSTANCE hDLLInst,
  131.               Instance handle of the DLL.
  132.             DWORD fdwReason,
  133.               Process attach/detach or thread attach/detach.
  134.               Reason for calling.
  135.             LPVOID lpvReserved)
  136.               Reserved and not used.
  137.  
  138.   Returns:  BOOL,
  139.               Return value is used only when fdwReason == DLL_PROCESS_ATTACH.
  140.               TRUE  -  Used to signify that the DLL should remain loaded.
  141.               FALSE -  Used to signify that the DLL should be
  142.                 immediately unloaded.
  143. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  144. BOOL WINAPI DllMain(
  145.               HINSTANCE hDllInst,
  146.               DWORD fdwReason,
  147.               LPVOID lpvReserved)
  148. {
  149.   BOOL bResult = TRUE;
  150.  
  151.   // Dispatch this main call based on the reason it was called.
  152.   switch (fdwReason)
  153.   {
  154.     case DLL_PROCESS_ATTACH:
  155.       // The DLL is being loaded for the first time by a given process.
  156.       // Perform per-process initialization here.  If the initialization
  157.       // is successful, return TRUE; if unsuccessful, return FALSE.
  158.       bResult = FALSE;
  159.       if (UnicodeOk())
  160.       {
  161.         // Instantiate a DLL global data encapsulator class.
  162.         g_pDll = new CDllData;
  163.         if (NULL != g_pDll)
  164.         {
  165.           // Remember the DLL Instance handle.
  166.           g_pDll->hDllInst = hDllInst;
  167.           // Create a MsgBox object.
  168.           g_pDll->pMsgBox = new CMsgBox;
  169.           if (NULL != g_pDll->pMsgBox)
  170.             bResult = TRUE;
  171.         }
  172.       }
  173.       break;
  174.  
  175.     case DLL_PROCESS_DETACH:
  176.       // The DLL is being unloaded by a given process.  Do any
  177.       // per-process clean up here, such as undoing what was done in
  178.       // DLL_PROCESS_ATTACH.  The return value is ignored.
  179.       if (NULL != g_pDll)
  180.       {
  181.         DELETE_POINTER(g_pDll->pMsgBox);
  182.         DELETE_POINTER(g_pDll);
  183.       }
  184.       break;
  185.  
  186.     case DLL_THREAD_ATTACH:
  187.       // A thread is being created in a process that has already loaded
  188.       // this DLL.  Perform any per-thread initialization here.  The
  189.       // return value is ignored.
  190.       break;
  191.  
  192.     case DLL_THREAD_DETACH:
  193.       // A thread is exiting cleanly in a process that has already
  194.       // loaded this DLL.  Perform any per-thread clean up here.  The
  195.       // return value is ignored.
  196.       break;
  197.  
  198.     default:
  199.       break;
  200.   }
  201.  
  202.   return (bResult);
  203. }
  204.  
  205.  
  206. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  207.   Function: ComObjInitMsgLog
  208.  
  209.   Summary:  Initialize a pointer inside this DLL to an outside EXE's
  210.             Message Log facility.  We want to see LOG macro output used
  211.             inside this DLL in the host EXE's message log window.
  212.  
  213.   Args:     CMsgLog* pMsgLog
  214.               Pointer to a message log object.
  215.  
  216.   Returns:  BOOL
  217.               TRUE.
  218. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  219. DLLENTRY BOOL WINAPI ComObjInitMsgLog(
  220.                        CMsgLog* pMsgLog)
  221. {
  222.   // Set up a pointer to the host EXE's Message Log facility so that any
  223.   // LOG macros used in this DLL will log to the host EXE's log window.
  224.   g_pMsgLog = pMsgLog;
  225.  
  226.   LOG("D: --- COMOBJ.DLL now logging ---");
  227.  
  228.   return TRUE;
  229. }
  230.  
  231.  
  232. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  233.   Function: ComObjAboutBox
  234.  
  235.   Summary:  One of the exported service functions of this DLL.  In this
  236.             simple code sample, ComObjAboutBox showcases use of the
  237.             CAboutBox class (from the APPUTIL utility library).  It also
  238.             illustrates how to implement this dialog using resources
  239.             stored in this DLL itself.
  240.  
  241.   Args:     HWND hWnd)
  242.               Handle of window that is to be parent of the dialog window.
  243.  
  244.   Returns:  BOOL,
  245.               Always returns TRUE.
  246. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  247. DLLENTRY BOOL WINAPI ComObjAboutBox(
  248.                        HWND hWnd)
  249. {
  250.   // Define one of those nifty APPUTIL CAboutBox modal dialog objects.
  251.   CAboutBox dlgAboutBox;
  252.  
  253.   // Show the standard About Box dialog for this DLL by telling the dialog
  254.   // C++ object to show itself by invoking its ShowDialog method.
  255.   // Pass it this DLL instance and the parent window handle.  Use a dialog
  256.   // resource ID for the dialog stored in this DLL module's resources.
  257.   dlgAboutBox.ShowDialog(
  258.     g_pDll->hDllInst,
  259.     MAKEINTRESOURCE(IDD_ABOUTBOX),
  260.     hWnd);
  261.  
  262.   return TRUE;
  263. }
  264.  
  265.  
  266. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  267.   Function: CreateCar
  268.  
  269.   Summary:  Creates an instance of the COCar COM object class
  270.             returning a requested interface pointer.
  271.  
  272.   Args:     IUnknown* pUnkOuter,
  273.               Pointer the outer Unknown interface.  Non NULL implies
  274.               that the new COM object is being created via an
  275.               aggregation with an Outer object.  NULL implies that the
  276.               object is not being created via aggregation.
  277.             REFIID riid,
  278.               The GUID of the interface requested on the new COM Object.
  279.             PPVOID ppv)
  280.               Address of the caller's pointer variable that will
  281.               receive the requested interface pointer.
  282.  
  283.   Returns:  HRESULT
  284.               NOERROR if successful, CLASS_E_NOAGREGATION if IUnknown is
  285.               not requested with non-NULL pUnkOuter, or other errors as
  286.               appropriate.
  287. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  288. DLLENTRY HRESULT WINAPI CreateCar(
  289.                           IUnknown* pUnkOuter,
  290.                           REFIID riid,
  291.                           PPVOID ppv)
  292. {
  293.   HRESULT hr;
  294.   COCar* pCob;
  295.  
  296.   LOGF1("D: CreateCar. pUnkOuter=0x%X.",pUnkOuter);
  297.  
  298.   // If the creation call is requesting aggregation (pUnkOuter != NULL),
  299.   // the COM rules state the IUnknown interface MUST also be concomitantly
  300.   // be requested.  If it is not so requested (riid != IID_IUnknown) then
  301.   // an error must be returned indicating that no aggregate creation of
  302.   // the COCar COM Object can be performed.
  303.   if (NULL != pUnkOuter && riid != IID_IUnknown)
  304.     hr = CLASS_E_NOAGGREGATION;
  305.   else
  306.   {
  307.     // Instantiate a CCar COM Object.
  308.     pCob = new COCar(pUnkOuter);
  309.  
  310.     // We QueryInterface this new COM Object not only to deposit the
  311.     // requested interface pointer into the caller's pointer variable,
  312.     // but to also automatically bump the Reference Count on the new
  313.     // COM Object after handing out this reference to it.
  314.     if (NULL != pCob)
  315.       hr = pCob->QueryInterface(riid, (PPVOID)ppv);
  316.     else
  317.       hr = E_OUTOFMEMORY;
  318.   }
  319.  
  320.   if (SUCCEEDED(hr))
  321.     LOGF1("D: CreateCar Succeeded. *ppv=0x%X.",*ppv);
  322.  
  323.   return hr;
  324. }
  325.  
  326.  
  327. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  328.   Function: CreateUtilityCar
  329.  
  330.   Summary:  Creates an instance of the COUtilityCar COM object class
  331.             returning a requested interface pointer. COUtilityCar uses the
  332.             Containment reuse technique to incorporate COCar features
  333.             (ie, ICar implementation) into its Interface offerings
  334.             (ie, IUnknown, ICar, and IUtility).
  335.  
  336.   Args:     IUnknown* pUnkOuter,
  337.               Pointer the outer Unknown interface.  Non NULL implies
  338.               that the new COM object is being created via an
  339.               aggregation with an Outer object.  NULL implies that the
  340.               object is not being created via aggregation.
  341.             REFIID riid,
  342.               The GUID of the interface requested on the new COM Object.
  343.             PPVOID ppv)
  344.               Address of the caller's pointer variable that will
  345.               receive the requested interface pointer.
  346.  
  347.   Returns:  HRESULT
  348.               NOERROR if successful, CLASS_E_NOAGREGATION if IUnknown is
  349.               not requested with non-NULL pUnkOuter, or other errors as
  350.               appropriate.
  351. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  352. DLLENTRY HRESULT WINAPI CreateUtilityCar(
  353.                           IUnknown* pUnkOuter,
  354.                           REFIID riid,
  355.                           PPVOID ppv)
  356. {
  357.   HRESULT hr;
  358.   COUtilityCar* pCob;
  359.  
  360.   LOGF1("D: CreateUtilityCar. pUnkOuter=0x%X.",pUnkOuter);
  361.  
  362.   // If the creation call is requesting aggregation (pUnkOuter != NULL),
  363.   // the COM rules state the IUnknown interface MUST also be concomitantly
  364.   // be requested.  If it is not so requested (riid != IID_IUnknown) then
  365.   // an error must be returned indicating that no aggregate creation of
  366.   // the COUtilityCar COM Object can be performed.
  367.   if (NULL != pUnkOuter && riid != IID_IUnknown)
  368.     hr = CLASS_E_NOAGGREGATION;
  369.   else
  370.   {
  371.     // Instantiate a CUtilityCar COM Object.
  372.     pCob = new COUtilityCar(pUnkOuter);
  373.     if (NULL != pCob)
  374.     {
  375.       // If we have succeeded in instantiating the COUtilityCar object
  376.       // we initialize it to set up any subordinate objects (ie, via
  377.       // containment or aggregation).
  378.       hr = pCob->Init();
  379.       if (SUCCEEDED(hr))
  380.       {
  381.         // We QueryInterface this new COM Object not only to deposit the
  382.         // requested interface pointer into the caller's pointer variable,
  383.         // but to also automatically bump the Reference Count on the new
  384.         // COM Object after handing out this reference to it.
  385.         hr = pCob->QueryInterface(riid, (PPVOID)ppv);
  386.       }
  387.     }
  388.     else
  389.       hr = E_OUTOFMEMORY;
  390.   }
  391.  
  392.   if (SUCCEEDED(hr))
  393.     LOGF1("D: CreateUtilityCar Succeeded. *ppv=0x%X.",*ppv);
  394.  
  395.   return hr;
  396. }
  397.  
  398.  
  399. /*F+F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F+++F
  400.   Function: CreateCruiseCar
  401.  
  402.   Summary:  Creates an instance of the COCruiseCar COM object class
  403.             returning a requested interface pointer. COCruiseCar uses the
  404.             Aggregation reuse technique to incorporate COCar features
  405.             (ie, ICar implementation) into its Interface offerings
  406.             (ie, IUnknown, ICar, and ICruise).  With this aggregation,
  407.             the ICar interface is not implemented in COCruiseCar.  It is
  408.             instead solely implemented in a COCar object that
  409.             CreateCruiseCar instantiates.  That COCar's ICar implementation
  410.             is used directly in this aggregation.
  411.  
  412.   Args:     IUnknown* pUnkOuter,
  413.               Pointer the outer Unknown interface.  Non NULL implies
  414.               that the new COM object is being created via an
  415.               aggregation with an Outer object.  NULL implies that the
  416.               object is not being created via aggregation.
  417.             REFIID riid,
  418.               The GUID of the interface requested on the new COM Object.
  419.             PPVOID ppv)
  420.               Address of the caller's pointer variable that will
  421.               receive the requested interface pointer.
  422.  
  423.   Returns:  HRESULT
  424.               NOERROR if successful, CLASS_E_NOAGREGATION if IUnknown is
  425.               not requested with non-NULL pUnkOuter, or other errors as
  426.               appropriate.
  427. F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F---F-F*/
  428. DLLENTRY HRESULT WINAPI CreateCruiseCar(
  429.                           IUnknown* pUnkOuter,
  430.                           REFIID riid,
  431.                           PPVOID ppv)
  432. {
  433.   HRESULT hr;
  434.   COCruiseCar* pCob;
  435.  
  436.   LOGF1("D: CreateCruiseCar. pUnkOuter=0x%X.",pUnkOuter);
  437.  
  438.   // If the creation call is requesting aggregation (pUnkOuter != NULL),
  439.   // the COM rules state the IUnknown interface MUST also be concomitantly
  440.   // be requested.  If it is not so requested (riid != IID_IUnknown) then
  441.   // an error must be returned indicating that no aggregate creation of
  442.   // the COCruiseCar COM Object can be performed.
  443.   if (NULL != pUnkOuter && riid != IID_IUnknown)
  444.     hr = CLASS_E_NOAGGREGATION;
  445.   else
  446.   {
  447.     // Instantiate a COCruiseCar COM Object.
  448.     pCob = new COCruiseCar(pUnkOuter);
  449.     if (NULL != pCob)
  450.     {
  451.       // If we have succeeded in instantiating the COCruiseCar object
  452.       // we initialize it to set up any subordinate objects (ie, via
  453.       // containment or aggregation).
  454.       hr = pCob->Init();
  455.       if (SUCCEEDED(hr))
  456.       {
  457.         // We QueryInterface this new COM Object not only to deposit the
  458.         // requested interface pointer into the caller's pointer variable,
  459.         // but to also automatically bump the Reference Count on the new
  460.         // COM Object after handing out this reference to it.
  461.         hr = pCob->QueryInterface(riid, (PPVOID)ppv);
  462.       }
  463.     }
  464.     else
  465.       hr = E_OUTOFMEMORY;
  466.   }
  467.  
  468.   if (SUCCEEDED(hr))
  469.     LOGF1("D: CreateCruiseCar Succeeded. *ppv=0x%X.",*ppv);
  470.  
  471.   return hr;
  472. }
  473.