/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "dllcom.h" #include HINSTANCE CComDll::m_hInstance = NULL; #ifdef DLL_DEBUG // Set this to your module name if you need something // more specific in your derived constructor. const char *CComDll::m_pTraceID = "CComDll"; #endif HINSTANCE CComDll::GetInstanceHandle() { // Should be non null by the time this // gets called. DLL_ASSERT(m_hInstance); return(m_hInstance); } CComDll::CComDll() { // No COM objects created yet. m_ulCount = 0; // Be sure to register this instance with the // process ID map. m_pEntry = new CProcessEntry(this); DLL_ASSERT(m_pEntry); // Add a reference upon creation. AddRef(); } CComDll::~CComDll() { DLL_ASSERT(m_ulCount == 0); // Unregister us from this particular process. if(m_pEntry) { delete m_pEntry; m_pEntry = NULL; } } HRESULT CComDll::QueryInterface(REFIID rIid, void **ppObj) { HRESULT hRetval = ResultFromScode(E_NOINTERFACE); *ppObj = NULL; // Just check to see if we should return our IUnknown // implementation. if(IsEqualIID(rIid, IID_IUnknown)) { AddRef(); *ppObj = (void *)((IUnknown *)this); hRetval = ResultFromScode(S_OK); } return(hRetval); } DWORD CComDll::AddRef() { m_ulCount++; return(m_ulCount); } DWORD CComDll::Release() { m_ulCount--; DWORD ulRetval = m_ulCount; if(!m_ulCount) { delete this; } // DO NOTHING BETWEEN THE DELETE AND RETURN // EXCEPT RETURN STACK DATA. return(ulRetval); } // Given a CLSID, copies the string for registering the CLSID as an in-proc server // into the specified buffer static HRESULT BuildRegistryCLSIDKey(REFGUID rGuid, LPSTR szStringKey) { // Convert the CLSID to a string. LPSTR lpszGuid = DLL_StringFromCLSID(rGuid); if (!lpszGuid) return ResultFromScode(E_OUTOFMEMORY); // Get the information into key format. #ifdef _WIN32 wsprintf(szStringKey, "CLSID\\%s\\InprocServer32", lpszGuid); #else wsprintf(szStringKey, "CLSID\\%s\\InprocServer", lpszGuid); #endif // Free off the string CoTaskMemFree(lpszGuid); return NOERROR; } // Make registry entries for implemented CLSIDs. // As DllRegisterServer. HRESULT CComDll::RegisterServer() { HRESULT hres = ResultFromScode(E_UNEXPECTED); // Determine our module (dll) path and name. char szModuleName[_MAX_PATH]; DWORD dwModuleNameLen; dwModuleNameLen = GetModuleFileName(szModuleName, sizeof(szModuleName)); if (dwModuleNameLen == 0) return hres; // Get the list of CLSIDs const CLSID **ppCLSIDs = GetCLSIDs(); if (ppCLSIDs) { const CLSID **ppTraverse = ppCLSIDs; char szStringKey[80]; while (*ppTraverse) { // Get the information into registry key format. hres = BuildRegistryCLSIDKey(**ppTraverse, szStringKey); if (FAILED(hres)) break; // Set the registry key. if (RegSetValue(HKEY_CLASSES_ROOT, szStringKey, REG_SZ, szModuleName, dwModuleNameLen) != ERROR_SUCCESS) { hres = ResultFromScode(/*SELFREG_E_CLASS*/ E_UNEXPECTED); break; } // Get the next CLSID ppTraverse++; } // Only if we made it all the way through the loop do we consider this a success if (*ppTraverse == NULL) hres = NOERROR; // Free off the list of CLSIDs CoTaskMemFree((LPVOID)ppCLSIDs); } return hres; } // Return name of module. DWORD CComDll::GetModuleFileName(char *pOutName, size_t stOutSize, BOOL bFullPath) { DWORD dwRetval = 0; dwRetval = ::GetModuleFileName(GetInstanceHandle(), pOutName, stOutSize); if(dwRetval && FALSE == bFullPath) { // Don't return the full path, split it up to the filename only. char aName[_MAX_FNAME]; char aExt[_MAX_EXT]; _splitpath(pOutName, NULL, NULL, aName, aExt); strcpy(pOutName, aName); strcat(pOutName, aExt); dwRetval = strlen(pOutName); } return(dwRetval); } // Remove registry entries for implemented CLSIDs. // As DllUnregisterServer. HRESULT CComDll::UnregisterServer() { HRESULT hres = ResultFromScode(E_UNEXPECTED); // Determine our module (dll) path and name. char szModuleName[_MAX_PATH]; DWORD dwModuleNameLen; dwModuleNameLen = GetModuleFileName(szModuleName, sizeof(szModuleName)); if (dwModuleNameLen == 0) return hres; // Get the list of CLSIDs const CLSID **ppCLSIDs = GetCLSIDs(); if (ppCLSIDs) { const CLSID **ppTraverse = ppCLSIDs; char szStringKey[80]; while (*ppTraverse) { LONG lSize; // Get the information into registry key format. hres = BuildRegistryCLSIDKey(**ppTraverse, szStringKey); if (FAILED(hres)) break; // Figure out if it points to us. // Continue if err, as it simply may not exist. if (RegQueryValue(HKEY_CLASSES_ROOT, szStringKey, NULL, &lSize) == ERROR_SUCCESS && lSize != 0) { LPSTR lpszValue = NULL; // Allocate a buffer large enough for it. lpszValue = (LPSTR)CoTaskMemAlloc(lSize); if (!lpszValue) { hres = ResultFromScode(E_OUTOFMEMORY); break; } // We do err on not being able to query the value if we got the size if (RegQueryValue(HKEY_CLASSES_ROOT, szStringKey, lpszValue, &lSize) != ERROR_SUCCESS) { hres = ResultFromScode(E_UNEXPECTED); CoTaskMemFree(lpszValue); break; } // Only delete if the same; ignore the case if (lstrcmpi(lpszValue, szModuleName) == 0) { // Delete the registry key. if (RegDeleteKey(HKEY_CLASSES_ROOT, szStringKey) != ERROR_SUCCESS) { hres = ResultFromScode(/*SELFREG_E_CLASS*/ E_UNEXPECTED); break; } } // Free the buffer CoTaskMemFree(lpszValue); } // Get the next CLSID ppTraverse++; } // Only if we made it through the loop do we consider this a success if (*ppTraverse == NULL) hres = NOERROR; // Free off the list of CLSIDs CoTaskMemFree((LPVOID)ppCLSIDs); } return hres; } // These routines contain the only entry points into your // end consumer DLL. // You must implement the functions which it calls to // your own satisfaction. // Standard COM callback to usually obtain an IClassFactory. STDAPI DllGetClassObject(REFCLSID rClsid, REFIID rIid, LPVOID *ppObj) { HRESULT hRetval; *ppObj = NULL; // Under 16 bits, it is imperative to seperate out each task // which uses this DLL so that they don't all use // the same memory heap, but instead use task specific // memory. // Find the abstract Dll instance for the current task. CComDll *pDll = CProcess::GetProcessDll(); if(pDll) { // Do it. hRetval = pDll->GetClassObject(rClsid, rIid, ppObj); // Take off a reference here. // This may also cause the instance data to self // self destruct if no objects were created // in the GetClassObject call. pDll->Release(); pDll = NULL; } else { hRetval = ResultFromScode(E_OUTOFMEMORY); } return(hRetval); } // Standard COM callback to see if the DLL can now be unloaded. // This is actually never called on 16 bits (via the // CoFreeUnusedLibraries call), but would work if that // mechanism is ever fixed. STDAPI DllCanUnloadNow(void) { HRESULT hRetval = ResultFromScode(S_FALSE); // We tell if we can unload by simply checking if // our process list of instance DLL objects is // empty. If not empty, we can not unload. if(CProcess::CanUnloadNow()) { hRetval = ResultFromScode(S_OK); DLL_TRACE("DllCanUnloadNow is TRUE\n"); } return(hRetval); } STDAPI DllRegisterServer(void) { HRESULT hRetval; // Find the abstract Dll instance for the current task. CComDll *pDll = CProcess::GetProcessDll(); if(pDll) { // Do it. hRetval = pDll->RegisterServer(); // Take off a reference here. // This should cause the instance data to self // self destruct if no objects were created // in the GetClassObject call. pDll->Release(); pDll = NULL; } else { hRetval = ResultFromScode(E_OUTOFMEMORY); } return(hRetval); } STDAPI DllUnregisterServer(void) { HRESULT hRetval; // Find the abstract Dll instance for the current task. CComDll *pDll = CProcess::GetProcessDll(); if(pDll) { // Do it. hRetval = pDll->UnregisterServer(); // Take off a reference here. // This should cause the instance data to self // self destruct if no objects were created // in the GetClassObject call. pDll->Release(); pDll = NULL; } else { hRetval = ResultFromScode(E_OUTOFMEMORY); } return(hRetval); }