home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap05 / dkoala3 / dkoala3.cpp next >
Encoding:
C/C++ Source or Header  |  1996-05-21  |  13.1 KB  |  558 lines

  1. /*
  2.  * DKOALA3.CPP
  3.  * Koala Object DLL Licensed Server Chapter 5
  4.  *
  5.  * Example object structured in a DLL server.
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13.  
  14.  
  15. #define INITGUIDS
  16. #include "dkoala3.h"
  17.  
  18.  
  19. //Count number of objects and number of locks.
  20. ULONG       g_cObj=0;
  21. ULONG       g_cLock=0;
  22.  
  23. HINSTANCE   g_hInst=NULL;
  24.  
  25.  
  26. //License key string, stored in ANSI to match contents of LIC file
  27. char    g_szLic[]="Koala Object #3 Copyright (c)1993-1995 Microsoft Corp.";
  28. BOOL    g_fMachineLicensed=FALSE;
  29.  
  30.  
  31. /*
  32.  * LibMain(32)
  33.  *
  34.  * Purpose:
  35.  *  Entry point conditionally compiled for Win32 and Win16.
  36.  *  Provides the proper structure for each environment.
  37.  */
  38.  
  39. #ifdef WIN32
  40. BOOL WINAPI LibMain32(HINSTANCE hInstance, ULONG ulReason
  41.     , LPVOID pvReserved)
  42.     {
  43.     if (DLL_PROCESS_DETACH==ulReason)
  44.         {
  45.         return TRUE;
  46.         }
  47.     else
  48.         {
  49.         if (DLL_PROCESS_ATTACH!=ulReason)
  50.             return TRUE;
  51.         }
  52.  
  53.     g_fMachineLicensed=CheckForLicenseFile(hInstance
  54.         , TEXT("DKOALA3.LIC"), (BYTE *)g_szLic, lstrlenA(g_szLic));
  55.  
  56.     g_hInst=hInstance;
  57.     return TRUE;
  58.     }
  59. #else
  60. int PASCAL LibMain(HINSTANCE hInstance, WORD wDataSeg
  61.     , WORD cbHeapSize, LPSTR lpCmdLine)
  62.     {
  63.     if (0!=cbHeapSize)
  64.         UnlockData(0);
  65.  
  66.     g_fMachineLicensed=CheckForLicenseFile(hInstance
  67.         , TEXT("DKOALA3.LIC"), (BYTE *)g_szLic, lstrlen(g_szLic));
  68.  
  69.     g_hInst=hInstance;
  70.     return (int)hInstance;
  71.     }
  72. #endif
  73.  
  74.  
  75.  
  76.  
  77. /*
  78.  * CheckForLicenseFile
  79.  *
  80.  * Purpose:
  81.  *  Attempts to load DKOALA3.LIC from the same directory as
  82.  *  this DLL, attempting to match the first part of that file
  83.  *  with our license string (typical licensing scheme).  If
  84.  *  the match is successful, then this DLL can create any
  85.  *  instances of Koala objects without additional trouble.
  86.  *  Otherwise the client has to call IClassFactory2::CreateInstance-
  87.  *  Lic to instantiate anything.
  88.  *
  89.  * Parameters:
  90.  *  hInst           HINSTANCE of the module describing the
  91.  *                  directory in which we expect to find the
  92.  *                  license file.
  93.  *  pszFile         LPTSTR to the name of the file to look for.
  94.  *  pbLic           LPBYTE to the expected contents of the file.
  95.  *  cb              UINT number of butes to compare.
  96.  *
  97.  * Return Value:
  98.  *  BOOL            TRUE if the file is available, FALSE otherwise.
  99.  */
  100.  
  101. BOOL CheckForLicenseFile(HINSTANCE hInst, LPTSTR pszFile
  102.     , LPBYTE pbLic, UINT cb)
  103.     {
  104.     BOOL        fFound=FALSE;
  105.     TCHAR       szPath[_MAX_PATH];
  106.     LPTSTR      pszTemp;
  107.     LPBYTE      pbCompare;
  108.    #ifdef WIN32
  109.     HANDLE      hFile;
  110.    #else
  111.     OFSTRUCT    of;
  112.     HFILE       hFile;
  113.    #endif
  114.     UINT        cbRead;
  115.     ULONG       cbWasRead;
  116.  
  117.     //Get the module path, then replace DLL name with LIC filename
  118.     GetModuleFileName(hInst, szPath, _MAX_PATH);
  119.     pszTemp=_tcsrchr(szPath, '\\')+1;
  120.     lstrcpy(pszTemp, pszFile);
  121.  
  122.     /*
  123.      * Now open the file and read contents into an allocated
  124.      * pbCompare.  The check if the contents of that file and
  125.      * pbLic match.  If so, then return success, otherwise
  126.      * failure.
  127.      */
  128.    #ifdef WIN32
  129.     hFile=CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ
  130.         , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  131.    #else
  132.     hFile=OpenFile(szPath, &of, OF_READ);
  133.    #endif
  134.  
  135.     /*
  136.      * NOTE:  INVALID_HANDLE_VALUE, ReadFile, and CloseHandle
  137.      * are macros in INC\book1632.h when compiling for Win16.
  138.      */
  139.     if (INVALID_HANDLE_VALUE==hFile)
  140.         return FALSE;
  141.  
  142.     cbRead=cb*sizeof(BYTE);
  143.     pbCompare=(LPBYTE)malloc(cbRead+4);
  144.  
  145.     if (NULL!=pbCompare)
  146.         {
  147.         ReadFile(hFile, pbCompare, cbRead, &cbWasRead, NULL);
  148.         fFound=(0==memcmp(pbLic, pbCompare, cb));
  149.         free(pbCompare);
  150.         }
  151.  
  152.     CloseHandle(hFile);
  153.     return fFound;
  154.     }
  155.  
  156.  
  157.  
  158. /*
  159.  * DllGetClassObject
  160.  *
  161.  * Purpose:
  162.  *  Provides an IClassFactory for a given CLSID that this DLL is
  163.  *  registered to support.  This DLL is placed under the CLSID
  164.  *  in the registration database as the InProcServer.
  165.  *
  166.  * Parameters:
  167.  *  clsID           REFCLSID that identifies the class factory
  168.  *                  desired.  Since this parameter is passed this
  169.  *                  DLL can handle any number of objects simply
  170.  *                  by returning different class factories here
  171.  *                  for different CLSIDs.
  172.  *
  173.  *  riid            REFIID specifying the interface the caller wants
  174.  *                  on the class object, usually IID_ClassFactory.
  175.  *
  176.  *  ppv             PPVOID in which to return the interface
  177.  *                  pointer.
  178.  *
  179.  * Return Value:
  180.  *  HRESULT         NOERROR on success, otherwise an error code.
  181.  */
  182.  
  183. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PPVOID ppv)
  184.     {
  185.     HRESULT             hr;
  186.     CKoalaClassFactory *pObj;
  187.  
  188.     if (CLSID_Koala!=rclsid)
  189.         return ResultFromScode(E_FAIL);
  190.  
  191.     pObj=new CKoalaClassFactory();
  192.  
  193.     if (NULL==pObj)
  194.         return ResultFromScode(E_OUTOFMEMORY);
  195.  
  196.     hr=pObj->QueryInterface(riid, ppv);
  197.  
  198.     if (FAILED(hr))
  199.         delete pObj;
  200.     else
  201.         g_cObj++;
  202.  
  203.     return hr;
  204.     }
  205.  
  206.  
  207.  
  208.  
  209.  
  210. /*
  211.  * DllCanUnloadNow
  212.  *
  213.  * Purpose:
  214.  *  Answers if the DLL can be freed, that is, if there are no
  215.  *  references to anything this DLL provides.
  216.  *
  217.  * Parameters:
  218.  *  None
  219.  *
  220.  * Return Value:
  221.  *  BOOL            TRUE if nothing is using us, FALSE otherwise.
  222.  */
  223.  
  224. STDAPI DllCanUnloadNow(void)
  225.     {
  226.     SCODE   sc;
  227.  
  228.     //Our answer is whether there are any object or locks
  229.     sc=(0L==g_cObj && 0L==g_cLock) ? S_OK : S_FALSE;
  230.     return ResultFromScode(sc);
  231.     }
  232.  
  233.  
  234.  
  235.  
  236.  
  237. /*
  238.  * ObjectDestroyed
  239.  *
  240.  * Purpose:
  241.  *  Function for the Koala object to call when it gets destroyed.
  242.  *  Since we're in a DLL we only track the number of objects here,
  243.  *  letting DllCanUnloadNow take care of the rest.
  244.  */
  245.  
  246. void ObjectDestroyed(void)
  247.     {
  248.     g_cObj--;
  249.     return;
  250.     }
  251.  
  252.  
  253.  
  254.  
  255.  
  256. /*
  257.  * CKoalaClassFactory::CKoalaClassFactory
  258.  * CKoalaClassFactory::~CKoalaClassFactory
  259.  *
  260.  * Constructor Parameters:
  261.  *  None
  262.  */
  263.  
  264. CKoalaClassFactory::CKoalaClassFactory(void)
  265.     {
  266.     m_cRef=0L;
  267.     return;
  268.     }
  269.  
  270. CKoalaClassFactory::~CKoalaClassFactory(void)
  271.     {
  272.     return;
  273.     }
  274.  
  275.  
  276.  
  277.  
  278. /*
  279.  * CKoalaClassFactory::QueryInterface
  280.  * CKoalaClassFactory::AddRef
  281.  * CKoalaClassFactory::Release
  282.  */
  283.  
  284. STDMETHODIMP CKoalaClassFactory::QueryInterface(REFIID riid
  285.     , PPVOID ppv)
  286.     {
  287.     *ppv=NULL;
  288.  
  289.     if (IID_IUnknown==riid || IID_IClassFactory==riid
  290.         || IID_IClassFactory2==riid)
  291.         *ppv=this;
  292.  
  293.     if (NULL!=*ppv)
  294.         {
  295.         ((LPUNKNOWN)*ppv)->AddRef();
  296.         return NOERROR;
  297.         }
  298.  
  299.     return ResultFromScode(E_NOINTERFACE);
  300.     }
  301.  
  302.  
  303. STDMETHODIMP_(ULONG) CKoalaClassFactory::AddRef(void)
  304.     {
  305.     return ++m_cRef;
  306.     }
  307.  
  308.  
  309. STDMETHODIMP_(ULONG) CKoalaClassFactory::Release(void)
  310.     {
  311.     if (0L!=--m_cRef)
  312.         return m_cRef;
  313.  
  314.     delete this;
  315.     ObjectDestroyed();
  316.     return 0L;
  317.     }
  318.  
  319.  
  320.  
  321. /*
  322.  * CKoalaClassFactory::CreateAnObject
  323.  * (Private)
  324.  *
  325.  * Purpose:
  326.  *  Central function to create instances of objects that is called
  327.  *  from CreateInstance and CreateInstanceLic.  This takes the same
  328.  *  parameters as CreateInstance below.
  329.  */
  330.  
  331. HRESULT CKoalaClassFactory::CreateAnObject(LPUNKNOWN pUnkOuter
  332.     , REFIID riid, PPVOID ppvObj)
  333.     {
  334.     PCKoala             pObj;
  335.     HRESULT             hr;
  336.  
  337.     //Verify that a controlling unknown asks for IUnknown
  338.     if (NULL!=pUnkOuter && IID_IUnknown!=riid)
  339.         return ResultFromScode(CLASS_E_NOAGGREGATION);
  340.  
  341.     hr=ResultFromScode(E_OUTOFMEMORY);
  342.  
  343.     //Create the object passing function to notify on destruction.
  344.     pObj=new CKoala(pUnkOuter, ObjectDestroyed);
  345.  
  346.     if (NULL==pObj)
  347.         return hr;
  348.  
  349.     if (pObj->Init())
  350.         hr=pObj->QueryInterface(riid, ppvObj);
  351.  
  352.     //Kill the object if initial creation or Init failed.
  353.     if (FAILED(hr))
  354.         delete pObj;
  355.     else
  356.         g_cObj++;
  357.  
  358.     return hr;
  359.     }
  360.  
  361.  
  362.  
  363.  
  364. /*
  365.  * CKoalaClassFactory::CreateInstance
  366.  *
  367.  * Purpose:
  368.  *  Instantiates a Koala object returning an interface pointer.
  369.  *
  370.  * Parameters:
  371.  *  pUnkOuter       LPUNKNOWN to the controlling IUnknown if we are
  372.  *                  being used in an aggregation.
  373.  *  riid            REFIID identifying the interface the caller
  374.  *                  desires to have for the new object.
  375.  *  ppvObj          PPVOID in which to store the desired
  376.  *                  interface pointer for the new object.
  377.  *
  378.  * Return Value:
  379.  *  HRESULT         NOERROR if successful, otherwise E_NOINTERFACE
  380.  *                  if we cannot support the requested interface.
  381.  */
  382.  
  383. STDMETHODIMP CKoalaClassFactory::CreateInstance(LPUNKNOWN pUnkOuter
  384.     , REFIID riid, PPVOID ppvObj)
  385.     {
  386.     *ppvObj=NULL;
  387.  
  388.     /*
  389.      * The license file *must* be around for this simple
  390.      * CreateInstance to work.  One we've checked, call the central
  391.      * creation function.
  392.      */
  393.     if (!g_fMachineLicensed)
  394.         return ResultFromScode(CLASS_E_NOTLICENSED);
  395.  
  396.     return CreateAnObject(pUnkOuter, riid, ppvObj);
  397.     }
  398.  
  399.  
  400.  
  401.  
  402. /*
  403.  * CKoalaClassFactory::LockServer
  404.  *
  405.  * Purpose:
  406.  *  Increments or decrements the lock count of the DLL.  If the
  407.  *  lock count goes to zero and there are no objects, the DLL
  408.  *  is allowed to unload.  See DllCanUnloadNow.
  409.  *
  410.  * Parameters:
  411.  *  fLock           BOOL specifying whether to increment or
  412.  *                  decrement the lock count.
  413.  *
  414.  * Return Value:
  415.  *  HRESULT         NOERROR always.
  416.  */
  417.  
  418. STDMETHODIMP CKoalaClassFactory::LockServer(BOOL fLock)
  419.     {
  420.     if (fLock)
  421.         g_cLock++;
  422.     else
  423.         g_cLock--;
  424.  
  425.     return NOERROR;
  426.     }
  427.  
  428.  
  429.  
  430.  
  431. /*
  432.  * CKoalaClassFactory::GetLicInfo
  433.  *
  434.  * Purpose:
  435.  *  Fills a LICINFO structure with license information for
  436.  *  this class factory.
  437.  *
  438.  * Parameters:
  439.  *  pLicInfo        LPLICINFO to the structure to fill
  440.  */
  441.  
  442. STDMETHODIMP CKoalaClassFactory::GetLicInfo(LPLICINFO pLicInfo)
  443.     {
  444.     if (NULL==pLicInfo)
  445.         return ResultFromScode(E_POINTER);
  446.  
  447.     pLicInfo->cbLicInfo=sizeof(LICINFO);
  448.  
  449.     //This says whether RequestLicKey will work
  450.     pLicInfo->fRuntimeKeyAvail=g_fMachineLicensed;
  451.  
  452.     //This says whether the standard CreateInstance will work
  453.     pLicInfo->fLicVerified=g_fMachineLicensed;
  454.  
  455.     return NOERROR;
  456.     }
  457.  
  458.  
  459.  
  460.  
  461. /*
  462.  * CKoalaClassFactory::RequestLicKey
  463.  *
  464.  * Purpose:
  465.  *  Retrieves a license key from this class factory for use with
  466.  *  CreateInstanceLic.
  467.  *
  468.  * Parameters:
  469.  *  dwReserved      DWORD reserved for future use with multiple
  470.  *                  licenses.
  471.  *  pbstrKey        BSTR * in which to return the key.
  472.  */
  473.  
  474. STDMETHODIMP CKoalaClassFactory::RequestLicKey(DWORD dwReserved
  475.     , BSTR *pbstrKey)
  476.     {
  477.     OLECHAR     szTemp[256];
  478.  
  479.     //Can't give away a key on an unlicensed machine
  480.     if (!g_fMachineLicensed)
  481.         return ResultFromScode(CLASS_E_NOTLICENSED);
  482.  
  483.    #ifndef WIN32
  484.     lstrcpy(g_szLic, szTemp);
  485.    #else
  486.     mbstowcs(szTemp, g_szLic, sizeof(g_szLic));
  487.    #endif
  488.     *pbstrKey=SysAllocString(szTemp);
  489.     return (NULL!=*pbstrKey) ? NOERROR : ResultFromScode(E_OUTOFMEMORY);
  490.     }
  491.  
  492.  
  493.  
  494.  
  495.  
  496. /*
  497.  * CKoalaClassFactory::CreateInstanceLic
  498.  *
  499.  * Purpose:
  500.  *  Creates and instance of the object given a license key.
  501.  *  Same as CreateInstance, and implementations of this function
  502.  *  will typically just validate the key and call CreateInstance.
  503.  *
  504.  * Parameters:
  505.  *  pUnkOuter       LPUNKNOWN to the controlling IUnknown if we are
  506.  *                  being used in an aggregation.
  507.  *  pUnkReserved    LPUNKNOWN reserved.
  508.  *  riid            REFIID identifying the interface the caller
  509.  *                  desires to have for the new object.
  510.  *  bstrKey         BSTR key used to validate creation.
  511.  *  ppvObj          PPVOID in which to store the desired
  512.  *                  interface pointer for the new object.
  513.  */
  514.  
  515. STDMETHODIMP CKoalaClassFactory::CreateInstanceLic(LPUNKNOWN pUnkOuter
  516.     , LPUNKNOWN pUnkReserved, REFIID riid, BSTR bstrKey
  517.     , PPVOID ppvObj)
  518.     {
  519.     BOOL        fMatch;
  520.     BSTR        bstrTemp;
  521.     UINT        cch;
  522.     OLECHAR     szLic[256];
  523.    #ifdef WIN32ANSI
  524.     char        szTemp[256];
  525.    #endif
  526.  
  527.     *ppvObj=NULL;
  528.  
  529.     /*
  530.      * Get our own license key that should match bstrKey exactly.
  531.      * This code is coped from RequestLicKey.
  532.      */
  533.    #ifndef WIN32
  534.     lstrcpy(g_szLic, szLic);
  535.    #else
  536.     mbstowcs(szLic, g_szLic, sizeof(g_szLic));
  537.    #endif
  538.     bstrTemp=SysAllocString(szLic);
  539.  
  540.     if (NULL==bstrTemp)
  541.         return ResultFromScode(E_OUTOFMEMORY);
  542.  
  543.    #ifdef WIN32ANSI
  544.     WideCharToMultiByte(CP_ACP, 0, bstrTemp, -1, szTemp
  545.         , 256, NULL, NULL);
  546.     cch=lstrlen(szTemp);
  547.    #else
  548.     cch=lstrlen(bstrTemp);
  549.    #endif
  550.     fMatch=(0==memcmp(bstrTemp, bstrKey, cch*sizeof(OLECHAR)));
  551.     SysFreeString(bstrTemp);
  552.  
  553.     if (!fMatch)
  554.         return ResultFromScode(CLASS_E_NOTLICENSED);
  555.  
  556.     return CreateAnObject(pUnkOuter, riid, ppvObj);
  557.     }
  558.