Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

600 lines
18 KiB

/*++
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;
}