/*++ Copyright (C) Microsoft Corporation, 1998 - 1999 Module Name: noncom Abstract: This module provides a means to bypass COM, such that typical in-process COM objects can be called directly in any operating system. Author: Doug Barlow (dbarlow) 1/4/1999 Notes: ?Notes? --*/ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include typedef HRESULT (STDAPICALLTYPE *GetClassObjectFunc)( REFCLSID rclsid, REFIID riid, LPVOID * ppv); #ifdef UNDER_TEST typedef struct { IID iid; HINSTANCE hDll; GetClassObjectFunc pgco; } NonComModuleStruct; class NonComControlStruct { public: DWORD dwInitializeCount; CRITICAL_SECTION csLock; CDynamicArray rgModules; }; static NonComControlStruct *l_pControl = NULL; /*++ NoCoInitialize: This function initializes the NonCOM subsystem. Arguments: pvReserved - [in] Reserved; must be NULL. Return Value: S_OK - The NonCOM subsystem was initialized correctly. S_FALSE - The NonCOM library is already initialized. Remarks: ?Remarks? Author: Doug Barlow (dbarlow) 1/4/1999 --*/ STDAPI NoCoInitialize( LPVOID pvReserved) { HRESULT hReturn = E_UNEXPECTED; // // Validate parameters. // if (NULL != pvReserved) { hReturn = E_INVALIDARG; goto ErrorExit; } // // Create the Control structure, if necessary. // if (NULL == l_pControl) { l_pControl = new NonComControlStruct; if (NULL == l_pControl) { hReturn = E_OUTOFMEMORY; goto ErrorExit; } InitializeCriticalSection(&l_pControl->csLock); CCritSect csLock(&l_pControl->csLock); // ?code? Database initialization l_pControl->dwInitializeCount = 1; } else { CCritSect csLock(&l_pControl->csLock); ASSERT(0 < l_pControl->dwInitializeCount); l_pControl->dwInitializeCount += 1; } return S_OK; ErrorExit: return hReturn; } /*++ NoCoUninitialize: Closes the NonCOM library on the current apartment, unloads all DLLs loaded by the apartment, frees any other resources that the apartment maintains, and forces all RPC connections on the apartment to close. Arguments: None Return Value: None Remarks: ?Remarks? Author: Doug Barlow (dbarlow) 1/4/1999 --*/ STDAPI_(void) NoCoUninitialize( void) { DWORD dwI; NonComModuleStruct *pMod; if (NULL != l_pControl) { { CCritSect csLock(&l_pControl->csLock); ASSERT(0 < l_pControl->dwInitializeCount); l_pControl->dwInitializeCount -= 1; if (0 == l_pControl->dwInitializeCount) { for (dwI = l_pControl->rgModules.Count(); 0 < dwI;) { pMod = l_pControl->rgModules[--dwI]; FreeLibrary(pMod->hDll); delete pMod; } l_pControl->rgModules.Clear(); } } DeleteCriticalSection(&l_pControl->csLock); delete l_pControl; l_pControl = NULL; } } #endif /*++ NoCoGetClassObject: Provides a pointer to an interface on a class object associated with a specified CLSID. CoGetClassObject locates, and if necessary, dynamically loads the executable code required to do this. Arguments: rclsid - [in] CLSID associated with the data and code that you will use to create the objects. riid - [in] Reference to the identifier of the interface, which will be supplied in ppv on successful return. This interface will be used to communicate with the class object. ppv - [out] Address of pointer variable that receives the interface pointer requested in riid. Upon successful return, *ppv contains the requested interface pointer. Return Value: S_OK - Location and connection to the specified class object was successful. REGDB_E_CLASSNOTREG - CLSID is not properly registered. Can also indicate that the value you specified in dwClsContext is not in the registry. E_NOINTERFACE - Either the object pointed to by ppv does not support the interface identified by riid, or the QueryInterface operation on the class object returned E_NOINTERFACE. REGDB_E_READREGDB - Error reading the registration database. CO_E_DLLNOTFOUND - In-process DLL not found. E_ACCESSDENIED - General access failure. Remarks: ?Remarks? Author: Doug Barlow (dbarlow) 1/4/1999 --*/ STDAPI NoCoGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID * ppv) { DWORD dwStatus; HRESULT hReturn = E_UNEXPECTED; TCHAR szGuid[40]; CBuffer szDll; HINSTANCE hDll = NULL; GetClassObjectFunc pfGetObject; #ifdef UNDER_TEST if (NULL == l_pControl) { hReturn = NoCoInitialize(NULL); if (S_OK != hReturn) goto ErrorExit; } { DWORD dwI; CCritSect(&l_pControl->csLock); for (dwI = l_pControl->rgModules.Count(); 0 < dwI;) { dwI -= 1; if (IsEqualGUID(l_pControl->rgModules[dwI]->iid, rclsid)) { try { hReturn = (*l_pControl->rgModules[dwI]->pgco)(rclsid, riid, ppv); } catch (...) { hReturn = E_UNEXPECTED; } goto ErrorExit; } } } #endif StringFromGuid(&rclsid, szGuid); try { // // Open the Class Registry Database. // CRegistry regClsId( HKEY_CLASSES_ROOT, TEXT("ClsID"), KEY_READ); dwStatus = regClsId.Status(TRUE); if (ERROR_SUCCESS != dwStatus) { hReturn = REGDB_E_READREGDB; goto ErrorExit; } // // Look up the specified Class. // CRegistry regClass( regClsId, szGuid, KEY_READ); dwStatus = regClass.Status(TRUE); if (ERROR_SUCCESS != dwStatus) { hReturn = REGDB_E_CLASSNOTREG; goto ErrorExit; } // // Get the registered InProcess Server. // CRegistry regServer( regClass, TEXT("InprocServer32"), KEY_READ); dwStatus = regServer.Status(TRUE); if (ERROR_SUCCESS != dwStatus) { hReturn = REGDB_E_CLASSNOTREG; goto ErrorExit; } // // Get the handler DLL name. // regServer.GetValue(TEXT(""), szDll); } catch (DWORD dwError) { switch (dwError) { case ERROR_OUTOFMEMORY: hReturn = E_OUTOFMEMORY; break; default: hReturn = HRESULT_FROM_WIN32(dwError); } goto ErrorExit; } // // We've got the target DLL. Load it and look for the entrypoint. // hDll = LoadLibrary((LPCTSTR)szDll.Access()); if (NULL == hDll) { hReturn = CO_E_DLLNOTFOUND; goto ErrorExit; } pfGetObject = (GetClassObjectFunc)GetProcAddress( hDll, "DllGetClassObject"); if (NULL == pfGetObject) { hReturn = E_NOINTERFACE; goto ErrorExit; } #ifdef UNDER_TEST { NonComModuleStruct *pMod = new NonComModuleStruct; if (NULL == pMod) { hReturn = E_OUTOFMEMORY; goto ErrorExit; } pMod->hDll = hDll; CopyMemory(&pMod->iid, &rclsid, sizeof(IID)); pMod->pgco = pfGetObject; try { l_pControl->rgModules.Add(pMod); } catch (...) { delete pMod; } } #endif try { hReturn = (*pfGetObject)(rclsid, riid, ppv); } catch (...) { hReturn = E_UNEXPECTED; } if (S_OK != hReturn) goto ErrorExit; // // Add the Handler to our database. // // ?code? -- No database yet. hDll = NULL; ASSERT(NULL == hDll); return S_OK; ErrorExit: if (NULL != hDll) FreeLibrary(hDll); return hReturn; } /*++ NoCoCreateInstance: Creates a single uninitialized object of the class associated with a specified CLSID. Call CoCreateInstance when you want to create only one object on the local system. Arguments: rclsid - [in] CLSID associated with the data and code that will be used to create the object. pUnkOuter - [in] If NULL, indicates that the object is not being created as part of an aggregate. If non-NULL, pointer to the aggregate object's IUnknown interface (the controlling IUnknown). riid - [in] Reference to the identifier of the interface to be used to communicate with the object. ppv - [out] Address of pointer variable that receives the interface pointer requested in riid. Upon successful return, *ppv contains the requested interface pointer. Return Value: S_OK - An instance of the specified object class was successfully created. REGDB_E_CLASSNOTREG - A specified class is not registered in the registration database. Also can indicate that the type of server you requested in the CLSCTX enumeration is not registered or the values for the server types in the registry are corrupt. Author: Doug Barlow (dbarlow) 1/15/1999 --*/ STDAPI NoCoCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID * ppv) { HRESULT hReturn = E_UNEXPECTED; IClassFactory *pCF = NULL; hReturn = NoCoGetClassObject(rclsid, IID_IClassFactory, (LPVOID*)&pCF); if (S_OK != hReturn) goto ErrorExit; hReturn = pCF->CreateInstance(pUnkOuter, riid, ppv); if (S_OK != hReturn) goto ErrorExit; pCF->Release(); pCF = NULL; return S_OK; ErrorExit: if (NULL != pCF) pCF->Release(); return hReturn; }