home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / wincom / dllcom / src / dllcom.cpp next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  10.3 KB  |  370 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. #include "dllcom.h"
  21. #include <shellapi.h>
  22.  
  23. HINSTANCE CComDll::m_hInstance = NULL;
  24.  
  25. #ifdef DLL_DEBUG
  26. //  Set this to your module name if you need something
  27. //      more specific in your derived constructor.
  28. const char *CComDll::m_pTraceID = "CComDll";
  29. #endif
  30.  
  31. HINSTANCE CComDll::GetInstanceHandle()
  32. {
  33.     //  Should be non null by the time this
  34.     //      gets called.
  35.     DLL_ASSERT(m_hInstance);
  36.     return(m_hInstance);
  37. }
  38.  
  39. CComDll::CComDll()
  40. {
  41.     //  No COM objects created yet.
  42.     m_ulCount = 0;
  43.  
  44.     //  Be sure to register this instance with the
  45.     //      process ID map.
  46.     m_pEntry = new CProcessEntry(this);
  47.     DLL_ASSERT(m_pEntry);
  48.  
  49.     //  Add a reference upon creation.
  50.     AddRef();
  51. }
  52.  
  53. CComDll::~CComDll()
  54. {
  55.     DLL_ASSERT(m_ulCount == 0);
  56.  
  57.     //  Unregister us from this particular process.
  58.     if(m_pEntry)    {
  59.         delete m_pEntry;
  60.         m_pEntry = NULL;
  61.     }
  62. }
  63.  
  64. HRESULT CComDll::QueryInterface(REFIID rIid, void **ppObj)  {
  65.     HRESULT hRetval = ResultFromScode(E_NOINTERFACE);
  66.     *ppObj = NULL;
  67.  
  68.     //  Just check to see if we should return our IUnknown
  69.     //      implementation.
  70.     if(IsEqualIID(rIid, IID_IUnknown))  {
  71.         AddRef();
  72.         *ppObj = (void *)((IUnknown *)this);
  73.         hRetval = ResultFromScode(S_OK);
  74.     }
  75.  
  76.     return(hRetval);
  77. }
  78.  
  79. DWORD CComDll::AddRef()
  80. {
  81.     m_ulCount++;
  82.  
  83.     return(m_ulCount);
  84. }
  85.  
  86. DWORD CComDll::Release()
  87. {
  88.     m_ulCount--;
  89.  
  90.     DWORD ulRetval = m_ulCount;
  91.  
  92.     if(!m_ulCount)   {
  93.         delete this;
  94.     }
  95.  
  96.     //  DO NOTHING BETWEEN THE DELETE AND RETURN
  97.     //      EXCEPT RETURN STACK DATA.
  98.  
  99.     return(ulRetval);
  100. }
  101.  
  102. // Given a CLSID, copies the string for registering the CLSID as an in-proc server
  103. // into the specified buffer
  104. static HRESULT
  105. BuildRegistryCLSIDKey(REFGUID rGuid, LPSTR szStringKey)
  106. {
  107.     //  Convert the CLSID to a string.
  108.     LPSTR    lpszGuid = DLL_StringFromCLSID(rGuid);
  109.  
  110.     if (!lpszGuid)
  111.         return ResultFromScode(E_OUTOFMEMORY);
  112.  
  113.     // Get the information into key format.
  114. #ifdef _WIN32
  115.     wsprintf(szStringKey, "CLSID\\%s\\InprocServer32", lpszGuid);
  116. #else
  117.     wsprintf(szStringKey, "CLSID\\%s\\InprocServer", lpszGuid);
  118. #endif
  119.  
  120.     // Free off the string
  121.     CoTaskMemFree(lpszGuid);
  122.     return NOERROR;
  123. }
  124.  
  125. // Make registry entries for implemented CLSIDs.
  126. // As DllRegisterServer.
  127. HRESULT CComDll::RegisterServer()
  128. {
  129.     HRESULT hres = ResultFromScode(E_UNEXPECTED);
  130.  
  131.     // Determine our module (dll) path and name.
  132.     char    szModuleName[_MAX_PATH];
  133.     DWORD     dwModuleNameLen;
  134.      
  135.     dwModuleNameLen = GetModuleFileName(szModuleName, sizeof(szModuleName));
  136.     if (dwModuleNameLen == 0)
  137.         return hres;
  138.     
  139.     // Get the list of CLSIDs
  140.     const CLSID **ppCLSIDs = GetCLSIDs();
  141.  
  142.     if (ppCLSIDs) {
  143.         const CLSID **ppTraverse = ppCLSIDs;
  144.         char             szStringKey[80];
  145.  
  146.         while (*ppTraverse)    {
  147.             // Get the information into registry key format.
  148.             hres = BuildRegistryCLSIDKey(**ppTraverse, szStringKey);
  149.             if (FAILED(hres))
  150.                 break;
  151.  
  152.             // Set the registry key.
  153.             if (RegSetValue(HKEY_CLASSES_ROOT, szStringKey, REG_SZ, szModuleName, dwModuleNameLen) != ERROR_SUCCESS) {
  154.                 hres = ResultFromScode(/*SELFREG_E_CLASS*/ E_UNEXPECTED);
  155.                 break;
  156.             }
  157.  
  158.             // Get the next CLSID
  159.             ppTraverse++;
  160.         }
  161.  
  162.         // Only if we made it all the way through the loop do we consider this a success
  163.         if (*ppTraverse == NULL)
  164.             hres = NOERROR;
  165.  
  166.         // Free off the list of CLSIDs
  167.         CoTaskMemFree((LPVOID)ppCLSIDs);
  168.     }
  169.  
  170.     return hres;
  171. }
  172.  
  173. //  Return name of module.
  174. DWORD CComDll::GetModuleFileName(char *pOutName, size_t stOutSize, BOOL bFullPath)
  175. {
  176.     DWORD dwRetval = 0;
  177.  
  178.     dwRetval = ::GetModuleFileName(GetInstanceHandle(), pOutName, stOutSize);
  179.     if(dwRetval && FALSE == bFullPath)  {
  180.         //  Don't return the full path, split it up to the filename only.
  181.         char aName[_MAX_FNAME];
  182.         char aExt[_MAX_EXT];
  183.         _splitpath(pOutName, NULL, NULL, aName, aExt);
  184.         strcpy(pOutName, aName);
  185.         strcat(pOutName, aExt);
  186.         dwRetval = strlen(pOutName);
  187.     }
  188.  
  189.     return(dwRetval);
  190. }
  191.  
  192. //  Remove registry entries for implemented CLSIDs.
  193. //  As DllUnregisterServer.
  194. HRESULT CComDll::UnregisterServer()
  195. {
  196.     HRESULT    hres = ResultFromScode(E_UNEXPECTED);
  197.  
  198.     //  Determine our module (dll) path and name.
  199.     char    szModuleName[_MAX_PATH];
  200.     DWORD    dwModuleNameLen;
  201.      
  202.     dwModuleNameLen = GetModuleFileName(szModuleName, sizeof(szModuleName));
  203.     if (dwModuleNameLen == 0)
  204.         return hres;
  205.     
  206.     // Get the list of CLSIDs
  207.     const CLSID **ppCLSIDs = GetCLSIDs();
  208.  
  209.     if (ppCLSIDs) {
  210.         const CLSID **ppTraverse = ppCLSIDs;
  211.         char           szStringKey[80];
  212.  
  213.         while (*ppTraverse)    {
  214.             LONG    lSize;
  215.             
  216.             // Get the information into registry key format.
  217.             hres = BuildRegistryCLSIDKey(**ppTraverse, szStringKey);
  218.             if (FAILED(hres))
  219.                 break;
  220.  
  221.             // Figure out if it points to us.
  222.             // Continue if err, as it simply may not exist.
  223.             if (RegQueryValue(HKEY_CLASSES_ROOT, szStringKey, NULL, &lSize) == ERROR_SUCCESS && lSize != 0) {
  224.                 LPSTR    lpszValue = NULL;
  225.  
  226.                 //  Allocate a buffer large enough for it.
  227.                 lpszValue = (LPSTR)CoTaskMemAlloc(lSize);
  228.                 if (!lpszValue)  {
  229.                     hres = ResultFromScode(E_OUTOFMEMORY);
  230.                     break;
  231.                 }
  232.  
  233.                 // We do err on not being able to query the value if we got the size
  234.                 if (RegQueryValue(HKEY_CLASSES_ROOT, szStringKey, lpszValue, &lSize) != ERROR_SUCCESS) {
  235.                     hres = ResultFromScode(E_UNEXPECTED);
  236.                     CoTaskMemFree(lpszValue);
  237.                     break;
  238.                 }
  239.  
  240.                 // Only delete if the same; ignore the case
  241.                 if (lstrcmpi(lpszValue, szModuleName) == 0) {
  242.                     // Delete the registry key.
  243.                     if (RegDeleteKey(HKEY_CLASSES_ROOT, szStringKey) != ERROR_SUCCESS) {
  244.                         hres = ResultFromScode(/*SELFREG_E_CLASS*/ E_UNEXPECTED);
  245.                         break;
  246.                     }
  247.                 }
  248.  
  249.                 // Free the buffer
  250.                 CoTaskMemFree(lpszValue);
  251.             }
  252.  
  253.             // Get the next CLSID
  254.             ppTraverse++;
  255.         }
  256.  
  257.         // Only if we made it through the loop do we consider this a success
  258.         if (*ppTraverse == NULL)
  259.             hres = NOERROR;
  260.  
  261.         // Free off the list of CLSIDs
  262.         CoTaskMemFree((LPVOID)ppCLSIDs);
  263.     }
  264.  
  265.     return hres;
  266. }
  267.  
  268. //  These routines contain the only entry points into your
  269. //      end consumer DLL.
  270. //  You must implement the functions which it calls to
  271. //      your own satisfaction.
  272.  
  273. //  Standard COM callback to usually obtain an IClassFactory.
  274. STDAPI DllGetClassObject(REFCLSID rClsid, REFIID rIid, LPVOID *ppObj)
  275. {
  276.     HRESULT hRetval;
  277.     *ppObj = NULL;
  278.  
  279.     //  Under 16 bits, it is imperative to seperate out each task
  280.     //      which uses this DLL so that they don't all use
  281.     //      the same memory heap, but instead use task specific
  282.     //      memory.
  283.     //  Find the abstract Dll instance for the current task.
  284.     CComDll *pDll = CProcess::GetProcessDll();
  285.     if(pDll)    {
  286.         //  Do it.
  287.         hRetval = pDll->GetClassObject(rClsid, rIid, ppObj);
  288.  
  289.         //  Take off a reference here.
  290.         //  This may also cause the instance data to self
  291.         //      self destruct if no objects were created
  292.         //      in the GetClassObject call.
  293.         pDll->Release();
  294.         pDll = NULL;
  295.     }
  296.     else    {
  297.         hRetval = ResultFromScode(E_OUTOFMEMORY);
  298.     }
  299.  
  300.     return(hRetval);
  301. }
  302.  
  303. //  Standard COM callback to see if the DLL can now be unloaded.
  304. //  This is actually never called on 16 bits (via the
  305. //      CoFreeUnusedLibraries call), but would work if that
  306. //      mechanism is ever fixed.
  307. STDAPI DllCanUnloadNow(void)
  308. {
  309.     HRESULT hRetval = ResultFromScode(S_FALSE);
  310.  
  311.     //  We tell if we can unload by simply checking if
  312.     //      our process list of instance DLL objects is
  313.     //      empty.  If not empty, we can not unload.
  314.     if(CProcess::CanUnloadNow()) {
  315.         hRetval = ResultFromScode(S_OK);
  316.         DLL_TRACE("DllCanUnloadNow is TRUE\n");
  317.     }
  318.  
  319.     return(hRetval);
  320. }
  321.  
  322. STDAPI DllRegisterServer(void)
  323. {
  324.     HRESULT hRetval;
  325.  
  326.     //  Find the abstract Dll instance for the current task.
  327.     CComDll *pDll = CProcess::GetProcessDll();
  328.     if(pDll)    {
  329.         //  Do it.
  330.         hRetval = pDll->RegisterServer();
  331.  
  332.         //  Take off a reference here.
  333.         //  This should cause the instance data to self
  334.         //      self destruct if no objects were created
  335.         //      in the GetClassObject call.
  336.         pDll->Release();
  337.         pDll = NULL;
  338.     }
  339.     else    {
  340.         hRetval = ResultFromScode(E_OUTOFMEMORY);
  341.     }
  342.  
  343.     return(hRetval);
  344. }
  345.  
  346. STDAPI DllUnregisterServer(void)
  347. {
  348.     HRESULT hRetval;
  349.  
  350.     //  Find the abstract Dll instance for the current task.
  351.     CComDll *pDll = CProcess::GetProcessDll();
  352.     if(pDll)    {
  353.         //  Do it.
  354.         hRetval = pDll->UnregisterServer();
  355.  
  356.         //  Take off a reference here.
  357.         //  This should cause the instance data to self
  358.         //      self destruct if no objects were created
  359.         //      in the GetClassObject call.
  360.         pDll->Release();
  361.         pDll = NULL;
  362.     }
  363.     else    {
  364.         hRetval = ResultFromScode(E_OUTOFMEMORY);
  365.     }
  366.  
  367.     return(hRetval);
  368. }
  369.  
  370.