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 / dkoala2 / dkoala2.cpp next >
Encoding:
C/C++ Source or Header  |  1996-05-21  |  10.5 KB  |  471 lines

  1. /*
  2.  * DKOALA2.CPP
  3.  * Koala Object DLL Self-Registering 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 "dkoala2.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. /*
  27.  * LibMain(32)
  28.  *
  29.  * Purpose:
  30.  *  Entry point conditionally compiled for Win32 and Win16.
  31.  *  Provides the proper structure for each environment.
  32.  */
  33.  
  34. #ifdef WIN32
  35. BOOL WINAPI LibMain32(HINSTANCE hInstance, ULONG ulReason
  36.     , LPVOID pvReserved)
  37.     {
  38.     if (DLL_PROCESS_DETACH==ulReason)
  39.         {
  40.         return TRUE;
  41.         }
  42.     else
  43.         {
  44.         if (DLL_PROCESS_ATTACH!=ulReason)
  45.             return TRUE;
  46.         }
  47.  
  48.     g_hInst=hInstance;
  49.     return TRUE;
  50.     }
  51. #else
  52. int PASCAL LibMain(HINSTANCE hInstance, WORD wDataSeg
  53.     , WORD cbHeapSize, LPSTR lpCmdLine)
  54.     {
  55.     if (0!=cbHeapSize)
  56.         UnlockData(0);
  57.  
  58.     g_hInst=hInstance;
  59.     return (int)hInstance;
  60.     }
  61. #endif
  62.  
  63.  
  64.  
  65. /*
  66.  * DllGetClassObject
  67.  *
  68.  * Purpose:
  69.  *  Provides an IClassFactory for a given CLSID that this DLL is
  70.  *  registered to support.  This DLL is placed under the CLSID
  71.  *  in the registration database as the InProcServer.
  72.  *
  73.  * Parameters:
  74.  *  clsID           REFCLSID that identifies the class factory
  75.  *                  desired.  Since this parameter is passed this
  76.  *                  DLL can handle any number of objects simply
  77.  *                  by returning different class factories here
  78.  *                  for different CLSIDs.
  79.  *
  80.  *  riid            REFIID specifying the interface the caller wants
  81.  *                  on the class object, usually IID_ClassFactory.
  82.  *
  83.  *  ppv             PPVOID in which to return the interface
  84.  *                  pointer.
  85.  *
  86.  * Return Value:
  87.  *  HRESULT         NOERROR on success, otherwise an error code.
  88.  */
  89.  
  90. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, PPVOID ppv)
  91.     {
  92.     HRESULT             hr;
  93.     CKoalaClassFactory *pObj;
  94.  
  95.     if (CLSID_Koala!=rclsid)
  96.         return ResultFromScode(E_FAIL);
  97.  
  98.     pObj=new CKoalaClassFactory();
  99.  
  100.     if (NULL==pObj)
  101.         return ResultFromScode(E_OUTOFMEMORY);
  102.  
  103.     hr=pObj->QueryInterface(riid, ppv);
  104.  
  105.     if (FAILED(hr))
  106.         delete pObj;
  107.     else
  108.         g_cObj++;
  109.  
  110.     return hr;
  111.     }
  112.  
  113.  
  114.  
  115.  
  116.  
  117. /*
  118.  * DllCanUnloadNow
  119.  *
  120.  * Purpose:
  121.  *  Answers if the DLL can be freed, that is, if there are no
  122.  *  references to anything this DLL provides.
  123.  *
  124.  * Parameters:
  125.  *  None
  126.  *
  127.  * Return Value:
  128.  *  BOOL            TRUE if nothing is using us, FALSE otherwise.
  129.  */
  130.  
  131. STDAPI DllCanUnloadNow(void)
  132.     {
  133.     SCODE   sc;
  134.  
  135.     //Our answer is whether there are any object or locks
  136.     sc=(0L==g_cObj && 0L==g_cLock) ? S_OK : S_FALSE;
  137.     return ResultFromScode(sc);
  138.     }
  139.  
  140.  
  141.  
  142.  
  143. /*
  144.  * DllRegisterServer
  145.  *
  146.  * Purpose:
  147.  *  Instructs the server to create its own registry entries
  148.  *
  149.  * Parameters:
  150.  *  None
  151.  *
  152.  * Return Value:
  153.  *  HRESULT         NOERROR if registration successful, error
  154.  *                  otherwise.
  155.  */
  156.  
  157. STDAPI DllRegisterServer(void)
  158.     {
  159.     TCHAR       szID[128];
  160.     TCHAR       szCLSID[128];
  161.     TCHAR       szModule[512];
  162.  
  163.     //Create some base key strings.
  164.     StringFromGUID2(CLSID_Koala, szID, 128);
  165.     lstrcpy(szCLSID, TEXT("CLSID\\"));
  166.     lstrcat(szCLSID, szID);
  167.  
  168.     //Create ProgID keys
  169.     SetKeyAndValue(TEXT("Koala1.0"), NULL
  170.         , TEXT("Koala Object Chapter 5"));
  171.     SetKeyAndValue(TEXT("Koala1.0"), TEXT("CLSID"), szID);
  172.  
  173.     //Create VersionIndependentProgID keys
  174.     SetKeyAndValue(TEXT("Koala"), NULL
  175.         , TEXT("Koala Object Chapter 5"));
  176.     SetKeyAndValue(TEXT("Koala"), TEXT("CurVer")
  177.         , TEXT("Koala1.0"));
  178.     SetKeyAndValue(TEXT("Koala"), TEXT("CLSID"), szID);
  179.  
  180.     //Create entries under CLSID
  181.     SetKeyAndValue(szCLSID, NULL, TEXT("Koala Object Chapter 5"));
  182.     SetKeyAndValue(szCLSID, TEXT("ProgID"), TEXT("Koala1.0"));
  183.     SetKeyAndValue(szCLSID, TEXT("VersionIndependentProgID")
  184.         , TEXT("Koala"));
  185.     SetKeyAndValue(szCLSID, TEXT("NotInsertable"), NULL);
  186.  
  187.     GetModuleFileName(g_hInst, szModule
  188.         , sizeof(szModule)/sizeof(TCHAR));
  189.  
  190.    #ifdef WIN32
  191.     SetKeyAndValue(szCLSID, TEXT("InprocServer32"), szModule);
  192.    #else
  193.     SetKeyAndValue(szCLSID, "InprocServer", szModule);
  194.    #endif
  195.  
  196.     return NOERROR;
  197.     }
  198.  
  199.  
  200.  
  201. /*
  202.  * DllRegisterServer
  203.  *
  204.  * Purpose:
  205.  *  Instructs the server to remove its own registry entries
  206.  *
  207.  * Parameters:
  208.  *  None
  209.  *
  210.  * Return Value:
  211.  *  HRESULT         NOERROR if registration successful, error
  212.  *                  otherwise.
  213.  */
  214.  
  215.  
  216. STDAPI DllUnregisterServer(void)
  217.     {
  218.     TCHAR       szID[128];
  219.     TCHAR       szCLSID[128];
  220.     TCHAR       szTemp[256];
  221.  
  222.     //Create some base key strings.
  223.     StringFromGUID2(CLSID_Koala, szID, 128);
  224.     lstrcpy(szCLSID, TEXT("CLSID\\"));
  225.     lstrcat(szCLSID, szID);
  226.  
  227.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala\\CurVer"));
  228.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala\\CLSID"));
  229.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala"));
  230.  
  231.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala1.0\\CLSID"));
  232.     RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Koala1.0"));
  233.  
  234.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("ProgID"));
  235.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  236.  
  237.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("VersionIndependentProgID"));
  238.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  239.  
  240.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("NotInsertable"));
  241.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  242.  
  243.    #ifdef WIN32
  244.     wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("InprocServer32"));
  245.    #else
  246.     wsprintf(szTemp, "%s\\%s", szCLSID, "InprocServer");
  247.    #endif
  248.     RegDeleteKey(HKEY_CLASSES_ROOT, szTemp);
  249.  
  250.     RegDeleteKey(HKEY_CLASSES_ROOT, szCLSID);
  251.     return NOERROR;
  252.     }
  253.  
  254.  
  255.  
  256. /*
  257.  * SetKeyAndValue
  258.  *
  259.  * Purpose:
  260.  *  Private helper function for DllRegisterServer that creates
  261.  *  a key, sets a value, and closes that key.
  262.  *
  263.  * Parameters:
  264.  *  pszKey          LPTSTR to the ame of the key
  265.  *  pszSubkey       LPTSTR ro the name of a subkey
  266.  *  pszValue        LPTSTR to the value to store
  267.  *
  268.  * Return Value:
  269.  *  BOOL            TRUE if successful, FALSE otherwise.
  270.  */
  271.  
  272. BOOL SetKeyAndValue(LPTSTR pszKey, LPTSTR pszSubkey
  273.     , LPTSTR pszValue)
  274.     {
  275.     HKEY        hKey;
  276.     TCHAR       szKey[256];
  277.  
  278.     lstrcpy(szKey, pszKey);
  279.  
  280.     if (NULL!=pszSubkey)
  281.         {
  282.         lstrcat(szKey, TEXT("\\"));
  283.         lstrcat(szKey, pszSubkey);
  284.         }
  285.  
  286.     if (ERROR_SUCCESS!=RegCreateKeyEx(HKEY_CLASSES_ROOT
  287.         , szKey, 0, NULL, REG_OPTION_NON_VOLATILE
  288.         , KEY_ALL_ACCESS, NULL, &hKey, NULL))
  289.         return FALSE;
  290.  
  291.     if (NULL!=pszValue)
  292.         {
  293.         RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)pszValue
  294.             , (lstrlen(pszValue)+1)*sizeof(TCHAR));
  295.         }
  296.  
  297.     RegCloseKey(hKey);
  298.     return TRUE;
  299.     }
  300.  
  301.  
  302.  
  303.  
  304. /*
  305.  * ObjectDestroyed
  306.  *
  307.  * Purpose:
  308.  *  Function for the Koala object to call when it gets destroyed.
  309.  *  Since we're in a DLL we only track the number of objects here,
  310.  *  letting DllCanUnloadNow take care of the rest.
  311.  */
  312.  
  313. void ObjectDestroyed(void)
  314.     {
  315.     g_cObj--;
  316.     return;
  317.     }
  318.  
  319.  
  320.  
  321.  
  322.  
  323. /*
  324.  * CKoalaClassFactory::CKoalaClassFactory
  325.  * CKoalaClassFactory::~CKoalaClassFactory
  326.  *
  327.  * Constructor Parameters:
  328.  *  None
  329.  */
  330.  
  331. CKoalaClassFactory::CKoalaClassFactory(void)
  332.     {
  333.     m_cRef=0L;
  334.     return;
  335.     }
  336.  
  337. CKoalaClassFactory::~CKoalaClassFactory(void)
  338.     {
  339.     return;
  340.     }
  341.  
  342.  
  343.  
  344.  
  345. /*
  346.  * CKoalaClassFactory::QueryInterface
  347.  * CKoalaClassFactory::AddRef
  348.  * CKoalaClassFactory::Release
  349.  */
  350.  
  351. STDMETHODIMP CKoalaClassFactory::QueryInterface(REFIID riid
  352.     , PPVOID ppv)
  353.     {
  354.     *ppv=NULL;
  355.  
  356.     if (IID_IUnknown==riid || IID_IClassFactory==riid)
  357.         *ppv=this;
  358.  
  359.     if (NULL!=*ppv)
  360.         {
  361.         ((LPUNKNOWN)*ppv)->AddRef();
  362.         return NOERROR;
  363.         }
  364.  
  365.     return ResultFromScode(E_NOINTERFACE);
  366.     }
  367.  
  368.  
  369. STDMETHODIMP_(ULONG) CKoalaClassFactory::AddRef(void)
  370.     {
  371.     return ++m_cRef;
  372.     }
  373.  
  374.  
  375. STDMETHODIMP_(ULONG) CKoalaClassFactory::Release(void)
  376.     {
  377.     if (0L!=--m_cRef)
  378.         return m_cRef;
  379.  
  380.     delete this;
  381.     ObjectDestroyed();
  382.     return 0L;
  383.     }
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391. /*
  392.  * CKoalaClassFactory::CreateInstance
  393.  *
  394.  * Purpose:
  395.  *  Instantiates a Koala object returning an interface pointer.
  396.  *
  397.  * Parameters:
  398.  *  pUnkOuter       LPUNKNOWN to the controlling IUnknown if we are
  399.  *                  being used in an aggregation.
  400.  *  riid            REFIID identifying the interface the caller
  401.  *                  desires to have for the new object.
  402.  *  ppvObj          PPVOID in which to store the desired
  403.  *                  interface pointer for the new object.
  404.  *
  405.  * Return Value:
  406.  *  HRESULT         NOERROR if successful, otherwise E_NOINTERFACE
  407.  *                  if we cannot support the requested interface.
  408.  */
  409.  
  410. STDMETHODIMP CKoalaClassFactory::CreateInstance(LPUNKNOWN pUnkOuter
  411.     , REFIID riid, PPVOID ppvObj)
  412.     {
  413.     PCKoala             pObj;
  414.     HRESULT             hr;
  415.  
  416.     *ppvObj=NULL;
  417.     hr=ResultFromScode(E_OUTOFMEMORY);
  418.  
  419.     //Verify that a controlling unknown asks for IUnknown
  420.     if (NULL!=pUnkOuter && IID_IUnknown!=riid)
  421.         return ResultFromScode(CLASS_E_NOAGGREGATION);
  422.  
  423.     //Create the object passing function to notify on destruction.
  424.     pObj=new CKoala(pUnkOuter, ObjectDestroyed);
  425.  
  426.     if (NULL==pObj)
  427.         return hr;
  428.  
  429.     if (pObj->Init())
  430.         hr=pObj->QueryInterface(riid, ppvObj);
  431.  
  432.     //Kill the object if initial creation or Init failed.
  433.     if (FAILED(hr))
  434.         delete pObj;
  435.     else
  436.         g_cObj++;
  437.  
  438.     return hr;
  439.     }
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446. /*
  447.  * CKoalaClassFactory::LockServer
  448.  *
  449.  * Purpose:
  450.  *  Increments or decrements the lock count of the DLL.  If the
  451.  *  lock count goes to zero and there are no objects, the DLL
  452.  *  is allowed to unload.  See DllCanUnloadNow.
  453.  *
  454.  * Parameters:
  455.  *  fLock           BOOL specifying whether to increment or
  456.  *                  decrement the lock count.
  457.  *
  458.  * Return Value:
  459.  *  HRESULT         NOERROR always.
  460.  */
  461.  
  462. STDMETHODIMP CKoalaClassFactory::LockServer(BOOL fLock)
  463.     {
  464.     if (fLock)
  465.         g_cLock++;
  466.     else
  467.         g_cLock--;
  468.  
  469.     return NOERROR;
  470.     }
  471.