/*++ Copyright (C) Microsoft Corporation Module Name: factory.cpp Abstract: This module implements CClassFactory class Author: William Hsieh (williamh) created Revision History: --*/ #include "devmgr.h" #include "factory.h" #include "about.h" const TCHAR* const REG_MMC_SNAPINS = TEXT("Software\\Microsoft\\MMC\\Snapins"); const TCHAR* const REG_MMC_NODETYPE = TEXT("Software\\Microsoft\\MMC\\NodeTypes"); const TCHAR* const MMC_NAMESTRING = TEXT("NameString"); const TCHAR* const MMC_NAMESTRINGINDIRECT = TEXT("NameStringIndirect"); const TCHAR* const MMC_PROVIDER = TEXT("Provider"); const TCHAR* const MMC_VERSION = TEXT("Version"); const TCHAR* const MMC_NODETYPES = TEXT("NodeTypes"); const TCHAR* const MMC_STANDALONE = TEXT("StandAlone"); const TCHAR* const MMC_EXTENSIONS = TEXT("Extensions"); const TCHAR* const MMC_NAMESPACE = TEXT("NameSpace"); const TCHAR* const MMC_ABOUT = TEXT("About"); const TCHAR* const REG_INPROCSERVER32 = TEXT("InprocServer32"); const TCHAR* const REG_THREADINGMODEL = TEXT("ThreadingModel"); const TCHAR* const REG_CLSID = TEXT("CLSID"); const TCHAR* const REG_PROGID = TEXT("ProgId"); const TCHAR* const REG_VERSIONINDEPENDENTPROGID = TEXT("VersionIndependentProgId"); const TCHAR* const APARTMENT = TEXT("Apartment"); // // CClassFactory implmentation // LONG CClassFactory::s_Locks = 0; LONG CClassFactory::s_Objects = 0; ULONG CClassFactory::AddRef() { return ::InterlockedIncrement(&m_Ref); } ULONG CClassFactory::Release() { ASSERT( 0 != m_Ref ); ULONG cRef = ::InterlockedDecrement(&m_Ref); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CClassFactory::QueryInterface( REFIID riid, LPVOID* ppv ) { if (!ppv) { return E_INVALIDARG; } HRESULT hr = S_OK; if (IsEqualIID(riid, IID_IUnknown)) { *ppv = (IUnknown *)(IClassFactory *)this; } else if (IsEqualIID(riid, IID_IClassFactory)) { *ppv = (IUnknown *)(IClassFactory *)this; } else { hr = E_NOINTERFACE; } if (SUCCEEDED(hr)) { AddRef(); } else { *ppv = NULL; } return hr; } STDMETHODIMP CClassFactory::CreateInstance( IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv ) { if (!ppv) { return E_INVALIDARG; } HRESULT hr = S_OK; *ppv = NULL; if (pUnkOuter != NULL) { hr = CLASS_E_NOAGGREGATION; } try { switch (m_ClassType) { case DM_CLASS_TYPE_SNAPIN: { // create the factory with the request class(class type). // When a new OLE object is created, it initializes its // ref count to 1. We do a release right after the QI // so that if the QI failed, the object will be self-destructed CComponentData* pCompData = new CComponentDataPrimary(); hr = pCompData->QueryInterface(riid, ppv); pCompData->Release(); break; } case DM_CLASS_TYPE_SNAPIN_EXTENSION: { // create the factory with the request class(class type). // When a new OLE object is created, it initializes its // ref count to 1. We do a release right after the QI // so that if the QI failed, the object will be self-destructed CComponentData* pCompData = new CComponentDataExtension(); hr = pCompData->QueryInterface(riid, ppv); pCompData->Release(); break; } case DM_CLASS_TYPE_SNAPIN_ABOUT: { // create the factory with the request class(class type). // When a new OLE object is created, it initializes its // ref count to 1. We do a release right after the QI // so that if the QI failed, the object will be self-destructed CDevMgrAbout* pAbout = new CDevMgrAbout; hr = pAbout->QueryInterface(riid, ppv); pAbout->Release(); break; } default: { hr = E_NOINTERFACE; } } } catch (CMemoryException* e) { hr = E_OUTOFMEMORY; e->Delete(); } return hr; } STDMETHODIMP CClassFactory::LockServer( BOOL fLock ) { if (fLock) { ::InterlockedIncrement((LONG*)&s_Locks); } else { ASSERT( 0 != s_Locks ); ::InterlockedDecrement((LONG*)&s_Locks); } return S_OK; } HRESULT CClassFactory::CanUnloadNow() { return (s_Objects || s_Locks) ? S_FALSE : S_OK; } // // This function create a CClassFactory. It is mainly called // by DllGetClassObject API // INPUT: // rclsid -- reference to the CLSID // riid -- reference to the interface IID // ppv -- interface pointer holder // // OUTPUT: // S_OK if succeeded else standard OLE error code // // HRESULT CClassFactory::GetClassObject( REFCLSID rclsid, REFIID riid, void** ppv ) { if (!ppv) { return E_INVALIDARG; } *ppv = NULL; HRESULT hr = S_OK; DM_CLASS_TYPE ClassType; // // determine the class type so that CreateInstance will be // creating the right object. We use a single class factory // to create all the object types. // if (IsEqualCLSID(rclsid, CLSID_DEVMGR)) { ClassType = DM_CLASS_TYPE_SNAPIN; } else if (IsEqualCLSID(rclsid, CLSID_DEVMGR_EXTENSION)) { ClassType = DM_CLASS_TYPE_SNAPIN_EXTENSION; } else if (IsEqualCLSID(rclsid, CLSID_DEVMGR_ABOUT)) { ClassType = DM_CLASS_TYPE_SNAPIN_ABOUT; } else { ClassType = DM_CLASS_TYPE_UNKNOWN; hr = E_NOINTERFACE; } if (SUCCEEDED(hr)) { CClassFactory* pUnk; // guard memory allocation error because we do not want // to cause an execption here. try { // create the factory with the request class(class type). // When a new OLE object is created, it initializes its // ref count to 1. We do a release right after the QI // so that if the QI failed, the object will be self-destructed pUnk = new CClassFactory(ClassType); hr = pUnk->QueryInterface(riid, ppv); pUnk->Release(); } catch (CMemoryException* e) { e->Delete(); hr = E_OUTOFMEMORY; } } return hr; } // // This function registers the dll to MMC // HRESULT CClassFactory::RegisterAll() { BOOL Result; TCHAR szText[MAX_PATH]; TCHAR ModuleName[MAX_PATH]; GetModuleFileName(g_hInstance, ModuleName, ARRAYLEN(ModuleName)); Result = FALSE; szText[0] = TEXT('\0'); // first register standalone snapin CLSID CSafeRegistry regRootCLSID; if (regRootCLSID.Open(HKEY_CLASSES_ROOT, REG_CLSID)) { CSafeRegistry regCLSID; // register our CLSID to HKEY_CLASS_ROOT\CLSID if (regCLSID.Create(regRootCLSID, CLSID_STRING_DEVMGR)) { // write the description ::LoadString(g_hInstance, IDS_DESC_DEVMGR, szText, ARRAYLEN(szText)); if (regCLSID.SetValue(NULL, szText)) { CSafeRegistry regServer; if (regServer.Create(regCLSID, REG_INPROCSERVER32) && regServer.SetValue(NULL, ModuleName) && regServer.SetValue(REG_THREADINGMODEL, APARTMENT)) { CSafeRegistry regProgId; if (regProgId.Create(regCLSID, REG_PROGID) && regProgId.SetValue(NULL, PROGID_DEVMGR)) { CSafeRegistry regVerIndProgId; if (regVerIndProgId.Create(regCLSID, REG_VERSIONINDEPENDENTPROGID)) { Result = regVerIndProgId.SetValue(NULL, PROGID_DEVMGR); } } } } } if (Result) { regCLSID.Close(); Result = FALSE; // register extension snapin CLSID if (regCLSID.Create(regRootCLSID, CLSID_STRING_DEVMGR_EXTENSION)) { ::LoadString(g_hInstance, IDS_EXTENSION_DESC, szText, ARRAYLEN(szText)); if (regCLSID.SetValue(NULL, szText)) { CSafeRegistry regServer; if (regServer.Create(regCLSID, REG_INPROCSERVER32)&& regServer.SetValue(NULL, ModuleName) && regServer.SetValue(REG_THREADINGMODEL, APARTMENT)) { CSafeRegistry regProgId; if (regProgId.Create(regCLSID, REG_PROGID) && regProgId.SetValue(NULL, PROGID_DEVMGREXT)) { CSafeRegistry regVerIndProgId; if (regVerIndProgId.Create(regCLSID, REG_VERSIONINDEPENDENTPROGID)) { Result = regVerIndProgId.SetValue(NULL, PROGID_DEVMGREXT); } } } } } } if (Result) { regCLSID.Close(); Result = FALSE; // register snapin about CLSID if (regCLSID.Create(regRootCLSID, CLSID_STRING_DEVMGR_ABOUT)) { ::LoadString(g_hInstance, IDS_ABOUT_DEVMGR, szText, ARRAYLEN(szText)); if (regCLSID.SetValue(NULL, szText)) { CSafeRegistry regServer; if (regServer.Create(regCLSID, REG_INPROCSERVER32)&& regServer.SetValue(NULL, ModuleName) && regServer.SetValue(REG_THREADINGMODEL, APARTMENT)) { CSafeRegistry regProgId; if (regProgId.Create(regCLSID, REG_PROGID) && regProgId.SetValue(NULL, PROGID_DEVMGR_ABOUT)) { CSafeRegistry regVerIndProgId; if (regVerIndProgId.Create(regCLSID, REG_VERSIONINDEPENDENTPROGID)) { Result = regVerIndProgId.SetValue(NULL, PROGID_DEVMGR_ABOUT); } } } } } } } if (Result) { Result = FALSE; CSafeRegistry regSnapins; // // open mmc snapin subkey // if (regSnapins.Open(HKEY_LOCAL_MACHINE, REG_MMC_SNAPINS)) { PNODEINFO pniDevMgr = (PNODEINFO)&NodeInfo[COOKIE_TYPE_SCOPEITEM_DEVMGR]; CSafeRegistry regDevMgr; if (regDevMgr.Create(regSnapins, CLSID_STRING_DEVMGR)) { StringCchPrintf(szText, ARRAYLEN(szText), TEXT("@%s,-%d"), ModuleName, IDS_DESC_DEVMGR); if (regDevMgr.SetValue(MMC_NAMESTRINGINDIRECT, szText)) { ::LoadString(g_hInstance, pniDevMgr->idsName, szText, ARRAYLEN(szText)); if (regDevMgr.SetValue(MMC_NAMESTRING, szText)) { ::LoadString(g_hInstance, IDS_PROGRAM_PROVIDER, szText, ARRAYLEN(szText)); if (regDevMgr.SetValue(MMC_PROVIDER, szText)) { ::LoadString(g_hInstance, IDS_PROGRAM_VERSION, szText, ARRAYLEN(szText)); if (regDevMgr.SetValue(MMC_VERSION, szText) && regDevMgr.SetValue(MMC_ABOUT, CLSID_STRING_DEVMGR_ABOUT)) { // // Let MMC knows that we are a standalone snapin -- // meaning we do not need any extension snapins for us // to run. // CSafeRegistry regStandAlone; Result = regStandAlone.Create(regDevMgr, MMC_STANDALONE); } } } } } CSafeRegistry regMMCNodeTypes; if (Result) { // populate our nodes Result = regMMCNodeTypes.Open(HKEY_LOCAL_MACHINE, REG_MMC_NODETYPE); if (Result) { CSafeRegistry regTheNode; int i = NODETYPE_FIRST; do { PNODEINFO pni = (PNODEINFO) &NodeInfo[i]; Result = regTheNode.Create(regMMCNodeTypes, pni->GuidString); regTheNode.Close(); } while (Result && ++i <= NODETYPE_LAST); } } if (Result) { // register as an extension to Computer management snapin CSafeRegistry regDevMgrExt; if (regDevMgrExt.Create(regSnapins, CLSID_STRING_DEVMGR_EXTENSION)) { ::LoadString(g_hInstance, IDS_EXTENSION_DESC, szText, ARRAYLEN(szText)); if (regDevMgrExt.SetValue(MMC_NAMESTRING, szText)) { ::LoadString(g_hInstance, IDS_PROGRAM_PROVIDER, szText, ARRAYLEN(szText)); if (regDevMgrExt.SetValue(MMC_PROVIDER, szText)) { ::LoadString(g_hInstance, IDS_PROGRAM_VERSION, szText, ARRAYLEN(szText)); if (regDevMgrExt.SetValue(MMC_VERSION, szText) && regDevMgrExt.SetValue(MMC_ABOUT, CLSID_STRING_DEVMGR_ABOUT)) { CSafeRegistry regSysTools; if (regSysTools.Open(regMMCNodeTypes, CLSID_STRING_SYSTOOLS)) { CSafeRegistry regExtensions; if (regExtensions.Open(regSysTools,MMC_EXTENSIONS)) { CSafeRegistry regNameSpace; if (regNameSpace.Open(regExtensions, MMC_NAMESPACE)) { // add our guid as a value of Name space Result = regNameSpace.SetValue(CLSID_STRING_DEVMGR_EXTENSION, szText); } } } } } } } } } } if (!Result) { HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); UnregisterAll(); return hr; } return S_OK; } // // This function unregisters the dll from MMC // HRESULT CClassFactory::UnregisterAll() { CSafeRegistry regSnapins; // // open mmc snapin subkey // if (regSnapins.Open(HKEY_LOCAL_MACHINE, REG_MMC_SNAPINS)) { // remove devmgr subkey from MMC snapins main key // both primary and extension regSnapins.DeleteSubkey(CLSID_STRING_DEVMGR); regSnapins.DeleteSubkey(CLSID_STRING_DEVMGR_EXTENSION); // removed populated node types CSafeRegistry regMMCNodeTypes; if (regMMCNodeTypes.Open(HKEY_LOCAL_MACHINE, REG_MMC_NODETYPE)) { for (int i = NODETYPE_FIRST; i <= NODETYPE_LAST; i++) { PNODEINFO pni = (PNODEINFO) &NodeInfo[i]; regMMCNodeTypes.DeleteValue(pni->GuidString); } // remove from system tools CSafeRegistry regSysTools; if (regSysTools.Open(regMMCNodeTypes, CLSID_STRING_SYSTOOLS)) { CSafeRegistry regExtensions; if (regExtensions.Open(regSysTools, MMC_EXTENSIONS)) { CSafeRegistry regNameSpace; if (regNameSpace.Open(regExtensions, MMC_NAMESPACE)) { regNameSpace.DeleteValue(CLSID_STRING_DEVMGR_EXTENSION); } } } } } // unregister from OLE CSafeRegistry regRootCLSID; if (regRootCLSID.Open(HKEY_CLASSES_ROOT, REG_CLSID)) { regRootCLSID.DeleteSubkey(CLSID_STRING_DEVMGR); regRootCLSID.DeleteSubkey(CLSID_STRING_DEVMGR_EXTENSION); regRootCLSID.DeleteSubkey(CLSID_STRING_DEVMGR_ABOUT); } return S_OK; }