/*++ Copyright (C) 1996-1999 Microsoft Corporation Module Name: ctrldll.cpp Abstract: DLL methods, class factory. --*/ #define INITGUIDS #define DEFINE_GLOBALS #include "polyline.h" #include #include #include #include #include "smonctrl.h" // For version numbers #include "genprop.h" #include "ctrprop.h" #include "grphprop.h" #include "srcprop.h" #include "appearprop.h" #include "unihelpr.h" #include "unkhlpr.h" #include "appmema.h" #include "globals.h" ITypeLib *g_pITypeLib; DWORD g_dwScriptPolicy = URLPOLICY_ALLOW; BOOL DLLAttach ( HINSTANCE ); VOID DLLDetach ( VOID ); extern HWND CreateFosterWnd( VOID ); BOOL WINAPI DllMain ( IN HINSTANCE hInstance, IN ULONG ulReason, IN LPVOID // pvReserved ) /*++ Routine Description: DllMain is the main entrypoint of the DLL. On a process attach, it calls the DLL initialization routine. On process detach, it calls the clean up routine. Arguments: hInstance - DLL instance handle ulReason - Calling reason (DLL_PROCESS_ATTCH, DLL_PROCESS_DETACH, etc.) pvReserved - Not used Return Value: Boolean result - TRUE = success, FALSE = failure --*/ { BOOL fReturn = TRUE; switch (ulReason) { case DLL_PROCESS_ATTACH: fReturn = DLLAttach(hInstance); break; case DLL_PROCESS_DETACH: DLLDetach(); break; default: break; } return fReturn; } BOOL DLLAttach ( IN HINSTANCE hInst ) /*++ Routine Description: DLLAttach initializes global variables and objects, and loads the type library. It saves the DLL instance handle in global variable, g_hInstance. Arguments: hInst - DLL instance handle Return Value: Boolean status - TRUE = success --*/ { HRESULT hr = S_OK; g_hInstance = hInst; // // Initialize general purpose critical section // try { InitializeCriticalSection(&g_CriticalSection); } catch (...) { hr = E_OUTOFMEMORY; } if (!SUCCEEDED(hr)) { return FALSE; } // // Create foster window // g_hWndFoster = CreateFosterWnd(); if (g_hWndFoster == NULL) { return FALSE; } // // Try loading type library from registry // hr = LoadRegTypeLib(LIBID_SystemMonitor, SMONCTRL_MAJ_VERSION, SMONCTRL_MIN_VERSION, LANG_NEUTRAL, &g_pITypeLib); // // If failed, try loading our typelib resource // if (FAILED(hr)) { LPWSTR szModule = NULL; UINT iModuleLen; DWORD dwReturn; int iRetry = 4; // // The length initialized to iModuleLen must be longer // than the length of "%systemroot%\\system32\\sysmon.ocx" // iModuleLen = MAX_PATH + 1; do { szModule = (LPWSTR) malloc(iModuleLen * sizeof(WCHAR)); if (szModule == NULL) { hr = E_OUTOFMEMORY; break; } // // Something wrong, break out // dwReturn = GetModuleFileName(g_hInstance, szModule, iModuleLen); if (dwReturn == 0) { hr = E_FAIL; break; } // // The buffer is not big enough, try to allocate a biggers one // and retry // if (dwReturn >= iModuleLen) { iModuleLen *= 2; free(szModule); szModule = NULL; hr = E_FAIL; } else { hr = S_OK; break; } iRetry --; } while (iRetry); if (SUCCEEDED(hr)) { hr = LoadTypeLib(szModule, &g_pITypeLib); } if (szModule) { free(szModule); } } if (FAILED(hr)) { return FALSE; } // // Initialize the perf counters // AppPerfOpen(hInst); return TRUE; } VOID DLLDetach ( VOID ) /*++ Routine Description: This routine deletes global variables and objects and unregisters all of the window classes. Arguments: None. Return Value: None. --*/ { INT i; // // Delete the foster window // if (g_hWndFoster) { DestroyWindow(g_hWndFoster); } // // Unregister all window classes // for (i = 0; i < MAX_WINDOW_CLASSES; i++) { if (pstrRegisteredClasses[i] != NULL) { UnregisterClass(pstrRegisteredClasses[i], g_hInstance); } } // // Release the typelib // if (g_pITypeLib != NULL) { g_pITypeLib->Release(); } // // Delete general purpose critical section // DeleteCriticalSection(&g_CriticalSection); AppPerfClose ((HINSTANCE)NULL); } /* * DllGetClassObject * * Purpose: * Provides an IClassFactory for a given CLSID that this DLL is * registered to support. This DLL is placed under the CLSID * in the registration database as the InProcServer. * * Parameters: * clsID REFCLSID that identifies the class factory * desired. Since this parameter is passed this * DLL can handle any number of objects simply * by returning different class factories here * for different CLSIDs. * * riid REFIID specifying the interface the caller wants * on the class object, usually IID_ClassFactory. * * ppv PPVOID in which to return the interface * pointer. * * Return Value: * HRESULT NOERROR on success, otherwise an error code. */ HRESULT APIENTRY DllGetClassObject ( IN REFCLSID rclsid, IN REFIID riid, OUT PPVOID ppv ) /*++ Routine Description: DllGetClassObject creates a class factory for the specified object class. The routine handles the primary control and the property pages. Arguments: rclsid - CLSID of object riid - IID of requested interface (IID_IUNknown or IID_IClassFactory) ppv - Pointer to returned interface pointer Return Value: HRESULT --*/ { HRESULT hr = S_OK; if (ppv == NULL) { return E_POINTER; } try { *ppv = NULL; // // Check for valid interface request // if (IID_IUnknown != riid && IID_IClassFactory != riid) { hr = E_NOINTERFACE; } if (SUCCEEDED(hr)) { // // Create class factory for request class // if (CLSID_SystemMonitor == rclsid) *ppv = new CPolylineClassFactory; else if (CLSID_GeneralPropPage == rclsid) *ppv = new CSysmonPropPageFactory(GENERAL_PROPPAGE); else if (CLSID_SourcePropPage == rclsid) *ppv = new CSysmonPropPageFactory(SOURCE_PROPPAGE); else if (CLSID_CounterPropPage == rclsid) *ppv = new CSysmonPropPageFactory(COUNTER_PROPPAGE); else if (CLSID_GraphPropPage == rclsid) *ppv = new CSysmonPropPageFactory(GRAPH_PROPPAGE); else if (CLSID_AppearPropPage == rclsid) *ppv = new CSysmonPropPageFactory(APPEAR_PROPPAGE); else hr = E_NOINTERFACE; if (*ppv) { ((LPUNKNOWN)*ppv)->AddRef(); } else { hr = E_OUTOFMEMORY; } } } catch (...) { hr = E_POINTER; } return hr; } STDAPI DllCanUnloadNow ( VOID ) /*++ Routine Description: DllCanUnload determines whether the DLL can be unloaded now. The DLL must remain active if any objects exist or any class factories are locked. Arguments: None. Return Value: HRESULT - S_OK if OK to unload, S_FALSE if not --*/ { // // OK to unload if no locks or objects // return (0L == g_cObj && 0L == g_cLock) ? S_OK : S_FALSE; } VOID ObjectDestroyed ( VOID ) /*++ Routine Description: ObjectDestroyed decrements the global object count. It is called whenever an object is destroyed. The count controls the lifetme of the DLL. Arguments: None. Return Value: None. --*/ { InterlockedDecrement(&g_cObj); } //--------------------------------------------------------------------------- // Class factory constructor & destructor //--------------------------------------------------------------------------- /* * CPolylineClassFactory::CPolylineClassFactory * * Purpose: * Constructor for an object supporting an IClassFactory that * instantiates Polyline objects. * * Parameters: * None */ CPolylineClassFactory::CPolylineClassFactory ( VOID ) { m_cRef = 0L; } /* * CPolylineClassFactory::~CPolylineClassFactory * * Purpose: * Destructor for a CPolylineClassFactory object. This will be * called when we Release the object to a zero reference count. */ CPolylineClassFactory::~CPolylineClassFactory ( VOID ) { } //--------------------------------------------------------------------------- // Standard IUnknown implementation for class factory //--------------------------------------------------------------------------- STDMETHODIMP CPolylineClassFactory::QueryInterface ( IN REFIID riid, OUT PPVOID ppv ) { HRESULT hr = S_OK; if (ppv == NULL) { return E_POINTER; } try { *ppv = NULL; if (IID_IUnknown == riid || IID_IClassFactory == riid) { *ppv = this; AddRef(); } else { hr = E_NOINTERFACE; } } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP_(ULONG) CPolylineClassFactory::AddRef ( VOID ) { return ++m_cRef; } STDMETHODIMP_(ULONG) CPolylineClassFactory::Release ( VOID ) { if (0L != --m_cRef) return m_cRef; delete this; return 0L; } STDMETHODIMP CPolylineClassFactory::CreateInstance ( IN LPUNKNOWN pUnkOuter, IN REFIID riid, OUT PPVOID ppvObj ) /*++ Routine Description: CreateInstance creates an instance of the control object and returns the requested interface to it. Arguments: pUnkOuter - IUnknown of outer controling object riid - IID of requested object interface ppvObj - Pointer to returned interface pointer Return Value: HRESULT - NOERROR, E_NOINTERFACE, or E_OUTOFMEMORY --*/ { PCPolyline pObj; HRESULT hr = S_OK; if (ppvObj == NULL) { return E_POINTER; } try { *ppvObj = NULL; // // We use do {} while(0) here to act like a switch statement // do { // // Verify that a controlling unknown asks for IUnknown // if (NULL != pUnkOuter && IID_IUnknown != riid) { hr = E_NOINTERFACE; break; } // // Create the object instance // pObj = new CPolyline(pUnkOuter, ObjectDestroyed); if (NULL == pObj) { hr = E_OUTOFMEMORY; break; } // // Initialize and get the requested interface // if (pObj->Init()) { hr = pObj->QueryInterface(riid, ppvObj); } else { hr = E_FAIL; } // // Delete object if initialization failed // Otherwise increment gloabl object count // if (FAILED(hr)) { delete pObj; } else { InterlockedIncrement(&g_cObj); } } while (0); } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP CPolylineClassFactory::LockServer ( IN BOOL fLock ) /*++ Routine Description: LockServer increments or decrements the DLL lock count. A non-zero lock count prevents the DLL from unloading. Arguments: fLock - Lock operation (TRUE = increment, FALSE = decrement) Return Value: HRESULT - Always NOERROR --*/ { if (fLock) { InterlockedIncrement(&g_cLock); } else { InterlockedDecrement(&g_cLock); } return S_OK; } // // CImpIObjectSafety interface implmentation // IMPLEMENT_CONTAINED_IUNKNOWN(CImpIObjectSafety); CImpIObjectSafety::CImpIObjectSafety(PCPolyline pObj, LPUNKNOWN pUnkOuter) : m_cRef(0), m_pObj(pObj), m_pUnkOuter(pUnkOuter), m_fMessageDisplayed(FALSE) { } CImpIObjectSafety::~CImpIObjectSafety() { } STDMETHODIMP CImpIObjectSafety::GetInterfaceSafetyOptions( REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions ) /*++ Routine Description: Retrieve the safety capability of object Arguments: riid - Interface ID to retrieve pdwSupportedOptions - The options the object knows about(might not support) pdwEnabledOptions - The options the object supports Return Value: HRESULT --*/ { HRESULT hr = S_OK; if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL) { return E_POINTER; } if (riid == IID_IDispatch) { // // Safe for scripting // *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER; *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER; } else if (riid == IID_IPersistPropertyBag || riid == IID_IPersistStreamInit) { // // Safety for initializing // *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA; *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA; } else { // // We don't support interfaces, fail out // *pdwSupportedOptions = 0; *pdwEnabledOptions = 0; hr = E_NOINTERFACE; } return hr; } STDMETHODIMP CImpIObjectSafety::SetInterfaceSafetyOptions( REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions ) /*++ Routine Description: The function is used for container to ask an object if it is safe for scripting or safe for initialization Arguments: riid - Interface ID to query dwSupportedOptions - The options the object knows about(might not support) dwEnabledOptions - The options the object supports Return Value: HRESULT --*/ { // // If we're being asked to set our safe for scripting or // safe for initialization options then oblige // if (0 == dwOptionSetMask && 0 == dwEnabledOptions) { // // the control certainly supports NO requests through the specified interface // so it's safe to return S_OK even if the interface isn't supported. // return S_OK; } SetupSecurityPolicy(); if (riid == IID_IDispatch) { // // Client is asking if it is safe to call through IDispatch // if (INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwEnabledOptions) { return S_OK; } } else if (riid == IID_IPersistPropertyBag || riid == IID_IPersistStreamInit) { // // Client is asking if it's safe to call through IPersistXXX // if (INTERFACESAFE_FOR_UNTRUSTED_DATA == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_DATA == dwEnabledOptions) { return S_OK; } } return E_FAIL; } VOID CImpIObjectSafety::SetupSecurityPolicy() /*++ Routine Description: The function check if we are safe for scripting. Arguments: None Return Value: Return TRUE if we are safe for scripting, othewise return FALSE --*/ { HRESULT hr; IServiceProvider* pSrvProvider = NULL; IWebBrowser2* pWebBrowser = NULL; IInternetSecurityManager* pISM = NULL; BSTR bstrURL; DWORD dwContext = 0; g_dwScriptPolicy = URLPOLICY_ALLOW; // // Get the service provider // hr = m_pObj->m_pIOleClientSite->QueryInterface(IID_IServiceProvider, (void **)&pSrvProvider); if (SUCCEEDED(hr)) { hr = pSrvProvider->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (void **)&pWebBrowser); } if (SUCCEEDED(hr)) { hr = pSrvProvider->QueryService(SID_SInternetSecurityManager, IID_IInternetSecurityManager, (void**)&pISM); } if (SUCCEEDED(hr)) { hr = pWebBrowser->get_LocationURL(&bstrURL); } // // Querying safe for scripting // if (SUCCEEDED(hr)) { hr = pISM->ProcessUrlAction(bstrURL, URLACTION_ACTIVEX_CONFIRM_NOOBJECTSAFETY, (BYTE*)&g_dwScriptPolicy, sizeof(g_dwScriptPolicy), (BYTE*)&dwContext, sizeof(dwContext), PUAF_NOUI, 0); } if (SUCCEEDED(hr)) { if (g_dwScriptPolicy == URLPOLICY_QUERY) { g_dwScriptPolicy = URLPOLICY_ALLOW; } if (g_dwScriptPolicy == URLPOLICY_DISALLOW) { if (!m_fMessageDisplayed) { m_fMessageDisplayed = TRUE; MessageBox(NULL, ResourceString(IDS_SCRIPT_NOT_ALLOWED), ResourceString(IDS_APP_NAME), MB_OK); } } } if (pWebBrowser) { pWebBrowser->Release(); } if (pSrvProvider) { pSrvProvider->Release(); } if (pISM) { pISM->Release(); } }