Windows2003-3790/enduser/netmeeting/av/nac/clsfact.cpp
2020-09-30 16:53:55 +02:00

540 lines
13 KiB
C++

/*
- CLSFACT.CPP
-
* Microsoft NetMeeting
* Network Audio Control DLL
* Generic class factory
*
* Revision History:
*
* When Who What
* -------- ------------------ ---------------------------------------
* 2.6.97 Yoram Yaacovi Copied from qosfact.cpp
* Added handling of CInstallCodecs
* 2.27.97 Yoram Yaacovi Added DllRegisterServer and DllUnregisterServer
*
* Functions:
* DllGetClassObject
* DllCanUnloadNow
* DllRegisterServer
* DllUnregisterServer
* CClassFactory::QueryInterface
* CClassFactory::AddRef
* CClassFactory::Release
* CClassFactory::CreateInstance
* CClassFactory::LockServer
* CreateClassFactory
*
*
* Object types supported:
* CQoS
* CInstallCodecs
*
* Notes:
* To add support for manufacturing objects of other types, change:
* DllGetClassObject
* DllCanUnloadNow
* Add the CLSID and description to aObjectInfo
*
*/
#include <precomp.h>
int g_cObjects = 0; // A general object count. Used for LockServer.
EXTERN_C int g_cQoSObjects; // QoS object count. Public in qos\qos.cpp
EXTERN_C int g_cICObjects; // CInstallCodecs object count. Public in inscodec.cpp
EXTERN_C HINSTANCE g_hInst; // global module instance
// Untested code for registering COM objects in the NAC
// when enabled, DllRegisterServer and DllUnregisterServer should be exported
// in nac.def
#define GUID_STR_LEN 40
typedef struct
{
const CLSID *pclsid;
char szDescription[MAX_PATH];
} OBJECT_INFO;
static OBJECT_INFO aObjectInfo[]=
{&CLSID_QoS, TEXT("Microsoft NetMeeting Quality of Service"),
&CLSID_InstallCodecs, TEXT("Microsoft NetMeeting Installable Codecs"),
NULL, TEXT("")};
// Internal helper functions
BOOL DeleteKeyAndSubKeys(HKEY hkIn, LPTSTR pszSubKey);
BOOL UnregisterUnknownObject(const CLSID *prclsid);
BOOL RegisterUnknownObject(LPCTSTR pszObjectName, const CLSID *prclsid);
/***************************************************************************
Name : DllGetClassObject
Purpose : Standard COM entry point to create a COM object
Parameters:
Returns : HRESULT
Comment :
***************************************************************************/
STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, void **ppv)
{
HRESULT hr;
CClassFactory *pObj;
*ppv = 0;
// find out object of what class we need to create and instantiate
// the class factory with the correct create function
if (CLSID_QoS == rclsid)
{
DBG_SAVE_FILE_LINE
pObj = new CClassFactory(CreateQoS);
}
else if (CLSID_InstallCodecs == rclsid)
{
DBG_SAVE_FILE_LINE
pObj = new CClassFactory(CreateInstallCodecs);
}
else
{
hr = CLASS_E_CLASSNOTAVAILABLE;
goto out;
}
if (!pObj)
{
hr = E_OUTOFMEMORY;
goto out;
}
hr = pObj->QueryInterface(riid, ppv);
if (FAILED(hr))
delete pObj;
out:
return hr;
}
/***************************************************************************
Name : DllCanUnloadNow
Purpose : Standard COM entry point tell a DLL it can unload
Parameters:
Returns : HRESULT
Comment :
***************************************************************************/
STDAPI DllCanUnloadNow ()
{
HRESULT hr=S_OK;
int vcObjects = g_cObjects + g_cQoSObjects + g_cICObjects;
return (vcObjects == 0 ? S_OK : S_FALSE);
}
/***************************************************************************
Name : DllRegisterServer
Purpose : Standard COM entry point to register a COM server
Parameters:
Returns : HRESULT
Comment :
***************************************************************************/
STDAPI DllRegisterServer(void)
{
ULONG i=0;
HRESULT hr=NOERROR;
while ((aObjectInfo[i].pclsid != NULL) &&
(lstrlen(aObjectInfo[i].szDescription) != 0))
{
if (!RegisterUnknownObject(aObjectInfo[i].szDescription,
aObjectInfo[i].pclsid))
{
hr = E_FAIL;
goto out;
}
// next server to register
i++;
}
out:
return hr;
}
/***************************************************************************
Name : DllUnregisterServer
Purpose : Standard COM entry point to unregister a COM server
Parameters:
Returns : HRESULT
Comment :
***************************************************************************/
STDAPI DllUnregisterServer(void)
{
ULONG i=0;
HRESULT hr=NOERROR;
while ((aObjectInfo[i].pclsid != NULL) &&
(lstrlen(aObjectInfo[i].szDescription) != 0))
{
if (!UnregisterUnknownObject(aObjectInfo[i].pclsid))
{
hr = E_FAIL;
goto out;
}
// next server to register
i++;
}
out:
return hr;
}
/***************************************************************************
ClassFactory: Generic implementation
***************************************************************************/
CClassFactory::CClassFactory(PFNCREATE pfnCreate)
{
m_cRef=0;
m_pfnCreate = pfnCreate;
return;
}
CClassFactory::~CClassFactory(void)
{
return;
}
/***************************************************************************
IUnknown Methods for CClassFactory
***************************************************************************/
HRESULT CClassFactory::QueryInterface (REFIID riid, void **ppv)
{
HRESULT hr=NOERROR;
#ifdef DEBUG
// parameter validation
if (IsBadReadPtr(&riid, (UINT) sizeof(IID)))
{
hr = ResultFromScode(E_INVALIDARG);
goto out;
}
if (IsBadWritePtr(ppv, sizeof(LPVOID)))
{
hr = ResultFromScode(E_INVALIDARG);
goto out;
}
#endif // DEBUG
*ppv = 0;
if (IID_IUnknown == riid ||
IID_IClassFactory == riid)
{
*ppv = this;
}
else
{
hr = ResultFromScode(E_NOINTERFACE);
goto out;
}
((IUnknown *)*ppv)->AddRef();
out:
return hr;
}
ULONG CClassFactory::AddRef (void)
{
return ++m_cRef;
}
ULONG CClassFactory::Release (void)
{
// if the cRef is already 0 (shouldn't happen), assert, but let it through
ASSERT(m_cRef);
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
/***************************************************************************
Name : CreateInstance
Purpose : Standard COM class factory entry point which creates the
object that this class factory knows to create
Parameters:
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT CClassFactory::CreateInstance ( IUnknown *punkOuter,
REFIID riid,
void **ppv)
{
DEBUGMSG(ZONE_VERBOSE,("CClassFactory::CreateInstance\n"));
return (m_pfnCreate)(punkOuter, riid, ppv);
}
/***************************************************************************
Name : LockServer
Purpose : Standard COM class factory entry point which will prevent
the server from shutting down. Necessary when the caller
keeps the class factory (through CoGetClassObject) instead
of calling CoCreateInstance.
Parameters:
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT CClassFactory::LockServer (BOOL flock)
{
if (flock)
++g_cObjects;
else
--g_cObjects;
return NOERROR;
}
/***************************************************************************
Helper functions
***************************************************************************/
/***************************************************************************
Name : StringFromGuid
Purpose : Creates a string out of a GUID
Parameters: riid - [in] clsid to make string out of.
pszBuf - [in] buffer in which to place resultant GUID
Returns : int - number of chars written out
Comment :
***************************************************************************/
int StringFromGuid(const CLSID *priid, LPTSTR pszBuf)
{
return wsprintf(pszBuf, TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
priid->Data1,
priid->Data2, priid->Data3, priid->Data4[0], priid->Data4[1], priid->Data4[2],
priid->Data4[3], priid->Data4[4], priid->Data4[5], priid->Data4[6], priid->Data4[7]);
}
/***************************************************************************
Name : RegisterUnknownObject
Purpose : Registers a simple CoCreatable object
We add the following information to the registry:
HKEY_CLASSES_ROOT\CLSID\<CLSID> = <ObjectName> Object
HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 = <path to local server>
HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 @ThreadingModel = Apartment
Parameters: pszObjectName - [in] Object Name
prclsid - [in] pointer to the CLSID of the object
Returns : BOOL - FALSE means couldn't register it all
Comment :
***************************************************************************/
BOOL RegisterUnknownObject(LPCTSTR pszObjectName, const CLSID *prclsid)
{
HKEY hk = NULL, hkSub = NULL;
TCHAR szGuidStr[GUID_STR_LEN];
DWORD dwPathLen, dwDummy;
TCHAR szScratch[MAX_PATH];
BOOL bRet = FALSE;
long l;
// clean out any garbage
UnregisterUnknownObject(prclsid);
if (!StringFromGuid(prclsid, szGuidStr))
goto out;
// CLSID/<class-id>
wsprintf(szScratch, TEXT("CLSID\\%s"), szGuidStr);
l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, TEXT(""), REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE, NULL, &hk, &dwDummy);
if (l != ERROR_SUCCESS)
goto out;
// CLSID/<class-id>: class name
wsprintf(szScratch, TEXT("%s Object"), pszObjectName);
l = RegSetValueEx(hk, NULL, 0, REG_SZ, (BYTE *)szScratch,
(lstrlen(szScratch) + 1)*sizeof(TCHAR));
if (l != ERROR_SUCCESS)
goto out;
// CLSID/<class-id>/InprocServer32
l = RegCreateKeyEx(hk, TEXT("InprocServer32"), 0, TEXT(""), REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
if (l != ERROR_SUCCESS)
goto out;
// CLSID/<class-id>/InprocServer32:<file name>
dwPathLen = GetModuleFileName(g_hInst, szScratch, sizeof(szScratch)/sizeof(TCHAR));
if (!dwPathLen)
goto out;
l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, (dwPathLen + 1)*sizeof(TCHAR));
if (l != ERROR_SUCCESS)
goto out;
// CLSID/<class-id>/InprocServer32: ThreadingModel = Apartment
l = RegSetValueEx(hkSub, TEXT("ThreadingModel"), 0, REG_SZ, (BYTE *)TEXT("Apartment"),
sizeof(TEXT("Apartment")));
if (l != ERROR_SUCCESS)
goto out;
bRet = TRUE;
out:
// clean the keys if we failed somewhere
if (!bRet)
UnregisterUnknownObject(prclsid);
if (hk)
RegCloseKey(hk);
if (hkSub)
RegCloseKey(hkSub);
return bRet;
}
/***************************************************************************
Name : UnregisterUnknownObject
Purpose : cleans up all the stuff that RegisterUnknownObject puts in the
registry.
Parameters: prclsid - [in] pointer to the CLSID of the object
Returns : BOOL - FALSE means couldn't register it all
Comment :
***************************************************************************/
BOOL UnregisterUnknownObject(const CLSID *prclsid)
{
TCHAR szScratch[MAX_PATH];
HKEY hk=NULL;
BOOL f;
long l;
BOOL bRet = FALSE;
// delete everybody of the form
// HKEY_CLASSES_ROOT\CLSID\<CLSID> [\] *
//
if (!StringFromGuid(prclsid, szScratch))
goto out;
l = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_ALL_ACCESS, &hk);
if (l != ERROR_SUCCESS)
goto out;
// Delete the object key and subkeys
bRet = DeleteKeyAndSubKeys(hk, szScratch);
out:
if (hk)
RegCloseKey(hk);
return bRet;
}
/***************************************************************************
Name : DeleteKeyAndSubKeys
Purpose : delete's a key and all of it's subkeys.
Parameters: hkIn - [in] delete the descendant specified
pszSubKey - [in] i'm the descendant specified
Returns : BOOL - TRUE = OK
Comment : Despite the win32 docs claiming it does, RegDeleteKey doesn't seem to
work with sub-keys under windows 95.
This function is recursive.
***************************************************************************/
BOOL DeleteKeyAndSubKeys(HKEY hkIn, LPTSTR pszSubKey)
{
HKEY hk;
TCHAR szTmp[MAX_PATH];
DWORD dwTmpSize;
long l;
BOOL f;
int x;
l = RegOpenKeyEx(hkIn, pszSubKey, 0, KEY_ALL_ACCESS, &hk);
if (l != ERROR_SUCCESS) return FALSE;
// loop through all subkeys, blowing them away.
//
f = TRUE;
x = 0;
while (f) {
dwTmpSize = MAX_PATH;
l = RegEnumKeyEx(hk, x, szTmp, &dwTmpSize, 0, NULL, NULL, NULL);
if (l != ERROR_SUCCESS) break;
f = DeleteKeyAndSubKeys(hk, szTmp);
x++;
}
// there are no subkeys left, [or we'll just generate an error and return FALSE].
// let's go blow this dude away.
//
RegCloseKey(hk);
l = RegDeleteKey(hkIn, pszSubKey);
return (l == ERROR_SUCCESS) ? TRUE : FALSE;
}