//*************************************************************************** // // Copyright (c) Microsoft Corporation. All rights reserved. // // SERVER.CPP // // Generic COM server framework, adapted for the NT perf counter sample // // This module contains nothing specific to the NT perf counter provider // except what is defined in the section bracketed by the CLSID SPECIFIC // comments below. // // History: // raymcc 25-Nov-97 Created. // raymcc 18-Feb-98 Updated for NT5 Beta 2 version. // //*************************************************************************** #include #include #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////// // // BEGIN CLSID SPECIFIC SECTION // // #pragma warning ( disable : 4268) #include #pragma warning ( default : 4268) #include #include "ntperf.h" #include "strings.h" // // this is going to be the ClientLoadable one // // {FF37A93C-C28E-11d1-AEB6-00C04FB68820} DEFINE_GUID(CLSID_NT5PerfProvider_V1, 0xff37a93c, 0xc28e, 0x11d1, 0xae, 0xb6, 0x0, 0xc0, 0x4f, 0xb6, 0x88, 0x20); // // this is going to be the Server Loadable // // {76A94DE3-7C26-44f5-8E98-C5AEA48186CB} DEFINE_GUID(CLSID_NT5PerfProvider_V1_Srv, 0x76a94de3, 0x7c26, 0x44f5, 0x8e, 0x98, 0xc5, 0xae, 0xa4, 0x81, 0x86, 0xcb); #define IMPLEMENTED_CLSID_1 CLSID_NT5PerfProvider_V1 #define IMPLEMENTED_CLSID_2 CLSID_NT5PerfProvider_V1_Srv #define SERVER_REGISTRY_COMMENT cszOleRegistryComment #define CPP_CLASS_NAME CNt5PerfProvider #define INTERFACE_CAST (IWbemHiPerfProvider *) // // END CLSID SPECIFIC SECTION // ///////////////////////////////////////////////////////////////////////////// HINSTANCE g_hInstance; static ULONG g_cLock = 0; void ObjectCreated() { g_cLock++; } void ObjectDestroyed() { g_cLock--; } //*************************************************************************** // // class CFactory // // Generic implementation of IClassFactory for CWbemLocator. // //*************************************************************************** class CFactory : public IClassFactory { ULONG m_cRef; CLSID m_ClsId; public: CFactory(const CLSID & ClsId); ~CFactory(); // // IUnknown members // STDMETHODIMP QueryInterface(REFIID, LPVOID *); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // // IClassFactory members // STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID *); STDMETHODIMP LockServer(BOOL); }; //*************************************************************************** // // DllMain // // Dll entry point. // // PARAMETERS: // // HINSTANCE hinstDLL The handle to our DLL. // DWORD dwReason DLL_PROCESS_ATTACH on load, // DLL_PROCESS_DETACH on shutdown, // DLL_THREAD_ATTACH/DLL_THREAD_DETACH otherwise. // LPVOID lpReserved Reserved // // RETURN VALUES: // // TRUE is successful, FALSE if a fatal error occured. // NT behaves very ugly if FALSE is returned. // //*************************************************************************** BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) { UNREFERENCED_PARAMETER(lpReserved); if (dwReason == DLL_PROCESS_ATTACH) { setlocale(LC_ALL, ""); // Set to the 'current' locale g_hInstance = hinstDLL; } else if (dwReason == DLL_PROCESS_DETACH) { } return TRUE; } //*************************************************************************** // // DllGetClassObject // // Standard OLE In-Process Server entry point to return an class factory // instance. // // PARAMETERS: // // RETURNS: // // S_OK Success // E_NOINTERFACE An interface other that IClassFactory was asked for // E_OUTOFMEMORY // E_FAILED Initialization failed, or an unsupported clsid was // asked for. // //*************************************************************************** extern "C" HRESULT APIENTRY DllGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID * ppv ) { CFactory *pFactory; // // Verify the caller is asking for our type of object. // if (IMPLEMENTED_CLSID_1 != rclsid && IMPLEMENTED_CLSID_2 != rclsid) return ResultFromScode(E_FAIL); // // Check that we can provide the interface. // if (IID_IUnknown != riid && IID_IClassFactory != riid) return ResultFromScode(E_NOINTERFACE); // // Get a new class factory. // pFactory = new CFactory(rclsid); if (!pFactory) return ResultFromScode(E_OUTOFMEMORY); // // Verify we can get an instance. // HRESULT hRes = pFactory->QueryInterface(riid, ppv); if (FAILED(hRes)) delete pFactory; return hRes; } //*************************************************************************** // // DllCanUnloadNow // // Standard OLE entry point for server shutdown request. Allows shutdown // only if no outstanding objects or locks are present. // // RETURN VALUES: // // S_OK May unload now. // S_FALSE May not. // //*************************************************************************** extern "C" HRESULT APIENTRY DllCanUnloadNow(void) { SCODE sc = TRUE; if (g_cLock) sc = S_FALSE; return sc; } #ifdef _X86_ BOOL IsReallyWOW64( void ) { // Environment variable should only exist on WOW64 return ( GetEnvironmentVariableW( L"PROCESSOR_ARCHITEW6432", 0L, NULL ) != 0L ); } #endif //*************************************************************************** // // DllRegisterServer // // Standard OLE entry point for registering the server. // // RETURN VALUES: // // S_OK Registration was successful // E_FAIL Registration failed. // //*************************************************************************** extern "C" HRESULT APIENTRY DllRegisterServer(void) { LPCWSTR Path = L"%systemroot%\\system32\\wbem\\wbemperf.dll"; wchar_t *pGuidStr = 0; wchar_t KeyPath[WBEMPERF_STRING_SIZE]; HKEY hKey = NULL; LONG lRes; wchar_t *pName; HKEY hSubkey = NULL; // Convert CLSID to string. // ======================== // Place it in registry. // CLSID\\CLSID_Nt5PerProvider_v1 : : "name" // \\CLSID_Nt5PerProvider_v1\\InProcServer32 : : "path to DLL" // : ThreadingModel : "both" // ============================================================== StringFromCLSID(IMPLEMENTED_CLSID_1, &pGuidStr); StringCchPrintfW(KeyPath, WBEMPERF_STRING_SIZE, cszClsidFormatString, pGuidStr); lRes = RegCreateKeyW(HKEY_LOCAL_MACHINE, KeyPath, &hKey); if (lRes){ goto cleanup; } pName = (LPWSTR)SERVER_REGISTRY_COMMENT; RegSetValueExW(hKey, 0, 0, REG_SZ, (const BYTE *) pName, (DWORD)(((DWORD)(wcslen(pName)) + 1) * 2)); lRes = RegCreateKey(hKey, "InprocServer32", &hSubkey); if( lRes ){ goto cleanup; } RegSetValueExW(hSubkey, 0, 0, REG_EXPAND_SZ, (const BYTE *) Path, (DWORD)(((DWORD)(wcslen(Path)) + 1) * 2)); RegSetValueExW(hSubkey, cszThreadingModel, 0, REG_SZ, (const BYTE *) cszBoth, (DWORD)(((DWORD)(wcslen(cszBoth)) + 1) * 2)); RegCloseKey(hSubkey); hSubkey = NULL; RegCloseKey(hKey); hKey = NULL; CoTaskMemFree(pGuidStr); pGuidStr = NULL; #ifdef _X86 if (!IsReallyWOW64()) { // on 32-bit builds, we want to register the server loadable // perf provider only if we are not really running in syswow64 #endif // Place it in registry. // CLSID\\CLSID_Nt5PerProvider_v1_Srv : : "name" // \\CLSID_Nt5PerProvider_v1_Srv\\InProcServer32 : : "path to DLL" // : ThreadingModel : "both" // ============================================================== StringFromCLSID(IMPLEMENTED_CLSID_2, &pGuidStr); StringCchPrintfW( KeyPath, WBEMPERF_STRING_SIZE, cszClsidFormatString, pGuidStr); lRes = RegCreateKeyW(HKEY_LOCAL_MACHINE, KeyPath, &hKey); if (lRes){ goto cleanup; } pName = (LPWSTR)SERVER_REGISTRY_COMMENT; RegSetValueExW(hKey, 0, 0, REG_SZ, (const BYTE *) pName, (DWORD)(((DWORD)(wcslen(pName)) + 1) * 2)); lRes = RegCreateKey(hKey, "InprocServer32", &hSubkey); if( lRes ){ goto cleanup; } RegSetValueExW(hSubkey, 0, 0, REG_EXPAND_SZ, (const BYTE *) Path, (DWORD)(((DWORD)(wcslen(Path)) + 1) * 2)); RegSetValueExW(hSubkey, cszThreadingModel, 0, REG_SZ, (const BYTE *) cszBoth, (DWORD)(((DWORD)(wcslen(cszBoth)) + 1) * 2)); #ifdef _X86 } #endif cleanup: if( NULL != hSubkey ){ RegCloseKey(hSubkey); } if( NULL != hKey ){ RegCloseKey(hKey); } if( NULL != pGuidStr ){ CoTaskMemFree(pGuidStr); } return lRes; } //*************************************************************************** // // DllUnregisterServer // // Standard OLE entry point for unregistering the server. // // RETURN VALUES: // // S_OK Unregistration was successful // E_FAIL Unregistration failed. // //*************************************************************************** extern "C" HRESULT APIENTRY DllUnregisterServer(void) { wchar_t *pGuidStr = 0; HKEY hKey; wchar_t KeyPath[WBEMPERF_STRING_SIZE]; LONG lRes; // Delete InProcServer32 subkey. // ============================= // Delete CLSID GUID key. // ====================== StringFromCLSID(IMPLEMENTED_CLSID_1, &pGuidStr); StringCchPrintfW( KeyPath, WBEMPERF_STRING_SIZE, cszClsidFormatString, pGuidStr); lRes = RegOpenKeyW(HKEY_LOCAL_MACHINE, KeyPath, &hKey); if (lRes) return E_FAIL; RegDeleteKeyW(hKey, cszInprocServer); RegCloseKey(hKey); lRes = RegOpenKeyW(HKEY_LOCAL_MACHINE, cszClsidKey, &hKey); if (lRes) return E_FAIL; RegDeleteKeyW(hKey, pGuidStr); RegCloseKey(hKey); CoTaskMemFree(pGuidStr); #ifdef _X86 if (!IsReallyWOW64()) { // on 32-bit builds, we need to unregister the server loadable // perf provider only if we are not really running in syswow64 #endif StringFromCLSID(IMPLEMENTED_CLSID_2, &pGuidStr); StringCchPrintfW( KeyPath, WBEMPERF_STRING_SIZE, cszClsidFormatString, pGuidStr); lRes = RegOpenKeyW(HKEY_LOCAL_MACHINE, KeyPath, &hKey); if (lRes) return E_FAIL; RegDeleteKeyW(hKey, cszInprocServer); RegCloseKey(hKey); lRes = RegOpenKeyW(HKEY_LOCAL_MACHINE, cszClsidKey, &hKey); if (lRes) return E_FAIL; RegDeleteKeyW(hKey, pGuidStr); RegCloseKey(hKey); CoTaskMemFree(pGuidStr); #ifdef _X86 } #endif return S_OK; } //*************************************************************************** // // CFactory::CFactory // // Constructs the class factory given the CLSID of the objects it is supposed // to create. // // PARAMETERS: // // const CLSID & ClsId The CLSID. // //*************************************************************************** CFactory::CFactory(const CLSID & ClsId) { m_cRef = 0; ObjectCreated(); m_ClsId = ClsId; } //*************************************************************************** // // CFactory::~CFactory // // Destructor. // //*************************************************************************** CFactory::~CFactory() { ObjectDestroyed(); } //*************************************************************************** // // CFactory::QueryInterface, AddRef and Release // // Standard IUnknown methods. // //*************************************************************************** STDMETHODIMP CFactory::QueryInterface(REFIID riid, LPVOID * ppv) { *ppv = 0; if (IID_IUnknown==riid || IID_IClassFactory==riid) { *ppv = this; AddRef(); return NOERROR; } return ResultFromScode(E_NOINTERFACE); } ULONG CFactory::AddRef() { return ++m_cRef; } ULONG CFactory::Release() { if (0 != --m_cRef) return m_cRef; delete this; return 0; } //*************************************************************************** // // CFactory::CreateInstance // // PARAMETERS: // // LPUNKNOWN pUnkOuter IUnknown of the aggregator. Must be NULL. // REFIID riid Interface ID required. // LPVOID * ppvObj Destination for the interface pointer. // // RETURN VALUES: // // S_OK Success // CLASS_E_NOAGGREGATION pUnkOuter must be NULL // E_NOINTERFACE No such interface supported. // //*************************************************************************** STDMETHODIMP CFactory::CreateInstance( LPUNKNOWN pUnkOuter, REFIID riid, LPVOID * ppvObj) { IUnknown* pObj; HRESULT hr; // // Defaults // *ppvObj=NULL; hr = ResultFromScode(E_OUTOFMEMORY); // // We aren't supporting aggregation. // if (pUnkOuter) return ResultFromScode(CLASS_E_NOAGGREGATION); if (m_ClsId == IMPLEMENTED_CLSID_1) { pObj = INTERFACE_CAST new CPP_CLASS_NAME(CPP_CLASS_NAME::CLSID_CLIENT); } else if (m_ClsId == IMPLEMENTED_CLSID_2) { pObj = INTERFACE_CAST new CPP_CLASS_NAME(CPP_CLASS_NAME::CLSID_SERVER); } else { pObj = NULL; } if (!pObj) return hr; // // Initialize the object and verify that it can return the // interface in question. // hr = pObj->QueryInterface(riid, ppvObj); // // Kill the object if initial creation or Init failed. // if (FAILED(hr)) delete pObj; return hr; } //*************************************************************************** // // CFactory::LockServer // // Increments or decrements the lock count of the server. The DLL will not // unload while the lock count is positive. // // PARAMETERS: // // BOOL fLock If TRUE, locks; otherwise, unlocks. // // RETURN VALUES: // // S_OK // //*************************************************************************** STDMETHODIMP CFactory::LockServer(BOOL fLock) { if (fLock) InterlockedIncrement((LONG *) &g_cLock); else InterlockedDecrement((LONG *) &g_cLock); return NOERROR; }