/*++ Copyright (C) Microsoft Corporation, 1997 - 1999 Module Name: senscfg.cxx Abstract: Code to do the configuration (install/uninstall) for SENS. Author: Gopal Parupudi [Notes:] optional-notes Revision History: GopalP 11/11/1997 Start. --*/ #define INITGUID #include #include #include #include #include #include #include #include #include "senscfg.hxx" #include "sensinfo.hxx" #include "memfunc.hxx" #define MAJOR_VER 1 #define MINOR_VER 0 #define DEFAULT_LCID 0x0 #define MAX_QUERY_SIZE 512 #define SENS_SETUP "SENSCFG: " #define SENS_SERVICEA "SENS" #define SENS_SETUPW SENS_BSTR("SENSCFG: ") #define SENS_SERVICE SENS_STRING("SENS") #define SENS_DISPLAY_NAME SENS_STRING("System Event Notification") #define SENS_SERVICE_GROUP SENS_STRING("Network") #define EVENTSYSTEM_REMOVE SENS_STRING("esserver /remove") #define EVENTSYSTEM_INSTALL SENS_STRING("esserver /install") #define SENS_WINLOGON_DLL SENS_STRING("senslogn.dll") #define GUID_STR_SIZE sizeof("{12345678-1234-1234-1234-123456789012}") #define EVENTSYSTEM_KEY SENS_STRING("SOFTWARE\\Microsoft\\EventSystem") #define WINLOGON_NOTIFY_KEY SENS_STRING("SOFTWARE\\Microsoft\\Windows NT\\") \ SENS_STRING("CurrentVersion\\Winlogon\\Notify\\") \ SENS_STRING("senslogn") #define WININET_SENS_EVENTS INETEVT_RAS_CONNECT | \ INETEVT_RAS_DISCONNECT | \ INETEVT_LOGON | \ INETEVT_LOGOFF // // DLL vs EXE dependent constants // #if defined(SENS_NT4) #define SENS_TLBA "SENS.EXE" #define SENS_BINARYA "SENS.EXE" #define SENS_TLB SENS_STRING("SENS.EXE") #define SENS_BINARY SENS_STRING("SENS.EXE") #else // SENS_NT4 #define SENS_TLBA "SENS.DLL" #define SENS_BINARYA "SENS.DLL" #define SENS_TLB SENS_STRING("SENS.DLL") #define SENS_BINARY SENS_STRING("SENS.DLL") #endif // SENS_NT4 // // Misc debugging constants // #ifdef STRICT_HRESULT_CHECKS #ifdef SUCCEEDED #undef SUCCEEDED #define SUCCEEDED(_HR_) (_HR_ == S_OK) #endif // SUCCEEDED #ifdef FAILED #undef FAILED #define FAILED(_HR_) (_HR_ != S_OK) #endif // FAILED #endif // STRICT_HRESULT_CHECKS // // Globals // IEventSystem *gpIEventSystem; ITypeLib *gpITypeLib; #ifdef DBG DWORD gdwDebugOutputLevel; #endif // DBG HRESULT APIENTRY SensRegister( void ) /*++ Routine Description: Register SENS. Arguments: None. Return Value: HRESULT returned from SensConfigurationHelper() --*/ { return (SensConfigurationHelper(FALSE)); } HRESULT APIENTRY SensUnregister( void ) /*++ Routine Description: Unregister SENS. Arguments: None. Return Value: HRESULT returned from SensConfigurationHelper() --*/ { return (SensConfigurationHelper(TRUE)); } HRESULT SensConfigurationHelper( BOOL bUnregister ) /*++ Routine Description: Main entry into the SENS configuration utility. Arguments: bUnregister - If TRUE, then unregister SENS as a publisher. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; hr = S_OK; gpIEventSystem = NULL; gpITypeLib = NULL; #ifdef DBG EnableDebugOutputIfNecessary(); #endif // DBG #if !defined(SENS_CHICAGO) // // Configure EventSystem first during an install and last during an uninstall. // if (FALSE == bUnregister) { hr = SensConfigureEventSystem(FALSE); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to configure EventSystem, HRESULT=%x\n", hr)); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "Successfully configured EventSystem\n")); } #endif // SENS_CHICAGO // // Instantiate the Event System // hr = CoCreateInstance( CLSID_CEventSystem, NULL, CLSCTX_SERVER, IID_IEventSystem, (LPVOID *) &gpIEventSystem ); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to create CEventSystem, HRESULT=%x\n", hr)); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "Successfully created CEventSystem\n")); // // Register Event Classes (and hence, indirectly events) published by SENS. // hr = RegisterSensEventClasses(bUnregister); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to %sregister SENS Events" " - hr = <%x>\n", bUnregister ? "un" : "", hr)); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "%segistered SENS Publisher Events.\n", bUnregister ? "Unr" : "R", hr)); // // Register the subscriptions of SENS. // hr = RegisterSensSubscriptions(bUnregister); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to %sregister SENS Subscriptions" " - hr = <%x>\n", bUnregister ? "un" : "", hr)); goto Cleanup; } SensPrintA(SENS_ERR, (SENS_SETUP "%segistered SENS Subscriptions.\n", bUnregister ? "Unr" : "R", hr)); // // Register the SENS TypeLibs. // hr = RegisterSensTypeLibraries(bUnregister); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to %sregister SENS Type Libraries" " - hr = <%x>\n", bUnregister ? "un" : "", hr)); // Abort only during the Install phase... if (bUnregister == FALSE) { goto Cleanup; } } SensPrintA(SENS_INFO, (SENS_SETUP "%segistered SENS Type Libraries.\n", bUnregister ? "Unr" : "R", hr)); #if !defined(SENS_CHICAGO) #if defined(SENS_NT4) // // Register SENS as a service with SCM. // hr = RegisterSensAsService(bUnregister); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to %sregister SENS as a Service" " - hr = <%x>\n", bUnregister ? "un" : "", hr)); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "%segistered SENS as a Service.\n", bUnregister ? "Unr" : "R", hr)); #endif // SENS_NT4 // // Configure EventSystem first during an install and last during an uninstall. // if (TRUE == bUnregister) { hr = SensConfigureEventSystem(TRUE); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to configure EventSystem, HRESULT=%x\n", hr)); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "Successfully configured EventSystem\n")); } #endif // SENS_CHICAGO // // Register SENS CLSID in the registry. // hr = RegisterSensCLSID( SENSGUID_SUBSCRIBER_LCE, SENS_SUBSCRIBER_NAME_EVENTOBJECTCHANGE, bUnregister ); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to %sregister SENS CLSID" " - hr = <%x>\n", bUnregister ? "un" : "", hr)); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "%segistered SENS CLSID.\n", bUnregister ? "Unr" : "R", hr)); // // Update Configured value // hr = SensUpdateVersion(bUnregister); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "Failed to update SENS version" " - hr = <%x>\n", hr)); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "Updated SENS version.\n")); Cleanup: // // Cleanup // if (gpIEventSystem) { gpIEventSystem->Release(); } if (gpITypeLib) { gpITypeLib->Release(); } SensPrintA(SENS_ERR, ("\n" SENS_SETUP "SENS Configuration %s.\n", SUCCEEDED(hr) ? "successful" : "failed")); return (hr); } HRESULT RegisterSensEventClasses( BOOL bUnregister ) /*++ Routine Description: Register/Unregister all the Events published by SENS. Arguments: bUnregister - If TRUE, then unregister all SENS Events. Return Value: S_OK, if successful hr, otherwise --*/ { int i; int errorIndex; HRESULT hr; LPOLESTR strGuid; LPOLESTR strEventClassID; WCHAR szQuery[MAX_QUERY_SIZE]; BSTR bstrEventClassID; BSTR bstrEventClassName; BSTR bstrFiringInterface; IEventClass *pIEventClass; hr = S_OK; strGuid = NULL; errorIndex = 0; strEventClassID = NULL; bstrEventClassID = NULL; bstrEventClassName = NULL; bstrFiringInterface = NULL; pIEventClass = NULL; for (i = 0; i < SENS_PUBLISHER_EVENTCLASS_COUNT; i++) { // Get a new IEventClass. hr = CoCreateInstance( CLSID_CEventClass, NULL, CLSCTX_SERVER, IID_IEventClass, (LPVOID *) &pIEventClass ); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "RegisterSensEventClasses() failed to create " "IEventClass - hr = <%x>\n", hr)); goto Cleanup; } if (bUnregister) { // Form the query wcscpy(szQuery, SENS_BSTR("EventClassID")); wcscat(szQuery, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, *(gSensEventClasses[i].pEventClassID)); wcscat(szQuery, strEventClassID); wcscat(szQuery, SENS_BSTR("")); hr = gpIEventSystem->Remove( PROGID_EventClass, szQuery, &errorIndex ); FreeStr(strEventClassID); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "RegisterSensEventClasses(%d) failed to Store" " - hr = <%x>\n", i, hr)); goto Cleanup; } pIEventClass->Release(); pIEventClass = NULL; continue; } AllocateBstrFromGuid(bstrEventClassID, *(gSensEventClasses[i].pEventClassID)); hr = pIEventClass->put_EventClassID(bstrEventClassID); ASSERT(SUCCEEDED(hr)); AllocateBstrFromString(bstrEventClassName, gSensEventClasses[i].strEventClassName); hr = pIEventClass->put_EventClassName(bstrEventClassName); ASSERT(SUCCEEDED(hr)); AllocateBstrFromGuid(bstrFiringInterface, *(gSensEventClasses[i].pFiringInterfaceGUID)); hr = pIEventClass->put_FiringInterfaceID(bstrFiringInterface); ASSERT(SUCCEEDED(hr)); FreeBstr(bstrEventClassID); FreeBstr(bstrEventClassName); FreeBstr(bstrFiringInterface); hr = gpIEventSystem->Store(PROGID_EventClass, pIEventClass); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "RegisterSensEventClasses(%d) failed to Store" " - hr = <%x>\n", i, hr)); goto Cleanup; } pIEventClass->Release(); pIEventClass = NULL; } // for loop Cleanup: // // Cleanup // if (pIEventClass) { pIEventClass->Release(); } FreeStr(strGuid); return (hr); } HRESULT RegisterSensSubscriptions( BOOL bUnregister ) /*++ Routine Description: Register/Unregister the Event subscriptions of SENS. Arguments: bUnregister - If TRUE, then unregister all subscriptions of SENS. Return Value: S_OK, if successful hr, otherwise --*/ { int i; int errorIndex; HRESULT hr; LPOLESTR strGuid; LPOLESTR strSubscriptionID; LPOLESTR strEventClassID; WCHAR szQuery[MAX_QUERY_SIZE]; BSTR bstrEventClassID; BSTR bstrInterfaceID; BSTR bstrPublisherID; BSTR bstrSubscriptionID; BSTR bstrSubscriptionName; BSTR bstrSubscriberCLSID; BSTR bstrMethodName; BSTR bstrPublisherPropertyName; BSTR bstrPublisherPropertyValue; VARIANT variantPublisherPropertyValue; BSTR bstrPROGID_EventSubscription; IEventSubscription *pIEventSubscription; hr = S_OK; strGuid = NULL; errorIndex = 0; strEventClassID = NULL; bstrEventClassID = NULL; bstrInterfaceID = NULL; bstrPublisherID = NULL; strSubscriptionID = NULL; bstrSubscriptionID = NULL; bstrSubscriberCLSID = NULL; bstrSubscriptionName = NULL; bstrMethodName = NULL; bstrPublisherPropertyName = NULL; bstrPublisherPropertyValue = NULL; bstrPROGID_EventSubscription = NULL; pIEventSubscription = NULL; AllocateBstrFromGuid(bstrPublisherID, SENSGUID_PUBLISHER); AllocateBstrFromGuid(bstrSubscriberCLSID, SENSGUID_SUBSCRIBER_LCE); AllocateBstrFromString(bstrPROGID_EventSubscription, PROGID_EventSubscription); for (i = 0; i < SENS_SUBSCRIPTIONS_COUNT; i++) { if (bUnregister) { // Form the query wcscpy(szQuery, SENS_BSTR("SubscriptionID")); wcscat(szQuery, SENS_BSTR("=")); AllocateStrFromGuid(strSubscriptionID, *(gSensSubscriptions[i].pSubscriptionID)); wcscat(szQuery, strSubscriptionID); hr = gpIEventSystem->Remove( PROGID_EventSubscription, szQuery, &errorIndex ); FreeStr(strSubscriptionID); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "RegisterSensSubscriptionis(%d) failed to Remove" " - hr = <%x>\n", i, hr)); goto Cleanup; } continue; } // Get a new IEventSubscription object to play with. hr = CoCreateInstance( CLSID_CEventSubscription, NULL, CLSCTX_SERVER, IID_IEventSubscription, (LPVOID *) &pIEventSubscription ); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "RegisterSensSubscriptions(%d) failed to create " "IEventSubscriptions - hr = <%x>\n", i, hr)); goto Cleanup; } AllocateBstrFromGuid(bstrSubscriptionID, *(gSensSubscriptions[i].pSubscriptionID)); hr = pIEventSubscription->put_SubscriptionID(bstrSubscriptionID); ASSERT(SUCCEEDED(hr)); hr = pIEventSubscription->put_PublisherID(bstrPublisherID); ASSERT(SUCCEEDED(hr)); hr = pIEventSubscription->put_SubscriberCLSID(bstrSubscriberCLSID); ASSERT(SUCCEEDED(hr)); AllocateBstrFromString(bstrSubscriptionName, gSensSubscriptions[i].strSubscriptionName); hr = pIEventSubscription->put_SubscriptionName(bstrSubscriptionName); ASSERT(SUCCEEDED(hr)); AllocateBstrFromString(bstrMethodName, gSensSubscriptions[i].strMethodName); hr = pIEventSubscription->put_MethodName(bstrMethodName); ASSERT(SUCCEEDED(hr)); AllocateBstrFromGuid(bstrEventClassID, *(gSensSubscriptions[i].pEventClassID)); hr = pIEventSubscription->put_EventClassID(bstrEventClassID); ASSERT(SUCCEEDED(hr)); AllocateBstrFromGuid(bstrInterfaceID, *(gSensSubscriptions[i].pInterfaceID)); hr = pIEventSubscription->put_InterfaceID(bstrInterfaceID); ASSERT(SUCCEEDED(hr)); if (gSensSubscriptions[i].bPublisherPropertyPresent == TRUE) { if (NULL != (gSensSubscriptions[i].pPropertyEventClassIDValue)) { // Create the Query string. wcscpy(szQuery, gSensSubscriptions[i].strPropertyEventClassID); wcscat(szQuery, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, *(gSensSubscriptions[i].pPropertyEventClassIDValue)); wcscat(szQuery, strEventClassID); wcscat(szQuery, SENS_BSTR(" AND ")); wcscat(szQuery, gSensSubscriptions[i].strPropertyMethodName); wcscat(szQuery, SENS_BSTR("=\'")); wcscat(szQuery, gSensSubscriptions[i].strPropertyMethodNameValue); wcscat(szQuery, SENS_BSTR("\'")); AllocateBstrFromString(bstrPublisherPropertyName, SENS_BSTR("Criteria")); AllocateBstrFromString(bstrPublisherPropertyValue, szQuery); InitializeBstrVariant(&variantPublisherPropertyValue, bstrPublisherPropertyValue); hr = pIEventSubscription->PutPublisherProperty( bstrPublisherPropertyName, &variantPublisherPropertyValue ); ASSERT(SUCCEEDED(hr)); SensPrintA(SENS_INFO, (SENS_SETUP "PutPublisherProperty(Criteria) returned 0x%x\n", hr)); FreeStr(strEventClassID); FreeBstr(bstrPublisherPropertyName); FreeBstr(bstrPublisherPropertyValue); } else { // // We are dealing with the "ANY" subscription of SENS. // // Create the Query string. wcscpy(szQuery, gSensSubscriptions[i].strPropertyEventClassID); wcscat(szQuery, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, SENSGUID_EVENTCLASS_NETWORK); wcscat(szQuery, strEventClassID); wcscat(szQuery, SENS_BSTR(" OR ")); FreeStr(strEventClassID); wcscat(szQuery, gSensSubscriptions[i].strPropertyEventClassID); wcscat(szQuery, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, SENSGUID_EVENTCLASS_LOGON); wcscat(szQuery, strEventClassID); wcscat(szQuery, SENS_BSTR(" OR ")); FreeStr(strEventClassID); wcscat(szQuery, gSensSubscriptions[i].strPropertyEventClassID); wcscat(szQuery, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, SENSGUID_EVENTCLASS_ONNOW); wcscat(szQuery, strEventClassID); FreeStr(strEventClassID); AllocateBstrFromString(bstrPublisherPropertyName, SENS_BSTR("Criteria")); AllocateBstrFromString(bstrPublisherPropertyValue, szQuery); InitializeBstrVariant(&variantPublisherPropertyValue, bstrPublisherPropertyValue); hr = pIEventSubscription->PutPublisherProperty( bstrPublisherPropertyName, &variantPublisherPropertyValue ); ASSERT(SUCCEEDED(hr)); SensPrintA(SENS_INFO, (SENS_SETUP "PutPublisherProperty(Criteria) returned 0x%x\n", hr)); FreeBstr(bstrPublisherPropertyName); FreeBstr(bstrPublisherPropertyValue); } } FreeBstr(bstrSubscriptionID); FreeBstr(bstrSubscriptionName); FreeBstr(bstrMethodName); FreeBstr(bstrEventClassID); FreeBstr(bstrInterfaceID); hr = gpIEventSystem->Store(bstrPROGID_EventSubscription, pIEventSubscription); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "RegisterSensSubscriptions(%d) failed to Store" " - hr = <%x>\n", i, hr)); goto Cleanup; } pIEventSubscription->Release(); pIEventSubscription = NULL; } // for loop Cleanup: // // Cleanup // if (pIEventSubscription) { pIEventSubscription->Release(); } FreeBstr(bstrPublisherID); FreeBstr(bstrSubscriberCLSID); FreeBstr(bstrPROGID_EventSubscription); FreeStr(strGuid); return (hr); } HRESULT RegisterSensTypeLibraries( BOOL bUnregister ) /*++ Routine Description: Register/Unregister the Type Libraries of SENS. Arguments: bUnregister - If TRUE, then unregister all subscriptions of SENS. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; UINT uiLength; TCHAR buffer[MAX_PATH+1+sizeof(SENS_BINARYA)+1]; // +1 for '\' WCHAR *bufferW; hr = S_OK; uiLength = 0; bufferW = NULL; // // Get the Full path name to the SENS TLB (which is a resource in SENS.EXE) // uiLength = GetSystemDirectory( buffer, MAX_PATH ); if (uiLength == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrintA(SENS_ERR, (SENS_SETUP "GetSystemDirectory(%s) failed - hr = <%x>\n", SENS_TLBA, hr)); goto Cleanup; } _tcscat(buffer, SENS_STRING("\\")); _tcscat(buffer, SENS_TLB); // // Convert the string to UNICODE, if necessary // #if !defined(SENS_CHICAGO) bufferW = buffer; #else // SENS_CHICAGO bufferW = SensAnsiStringToUnicode(buffer); if (NULL == bufferW) { goto Cleanup; } #endif // SENS_CHICAGO hr = LoadTypeLibEx( bufferW, REGKIND_NONE, &gpITypeLib ); if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "LoadTypeLib(%s) failed " " - hr = <%x>\n", SENS_TLBA, hr)); goto Cleanup; } // // Ensure that the TypeLib is (un)registered // if (bUnregister) { hr = UnRegisterTypeLib( LIBID_SensEvents, MAJOR_VER, MINOR_VER, DEFAULT_LCID, SYS_WIN32 ); } else { hr = RegisterTypeLib( gpITypeLib, bufferW, NULL ); } if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "%sRegisterTypeLib(%s) failed " " - hr = <%x>\n", (bUnregister ? "Un" : ""), SENS_TLBA, hr)); } Cleanup: // // Cleanup // #if defined(SENS_CHICAGO) if (bufferW != NULL) { delete bufferW; } #endif // SENS_CHICAGO return (hr); } HRESULT RegisterSensCLSID( REFIID clsid, TCHAR* strSubscriberName, BOOL bUnregister ) /*++ Routine Description: Register/Unregister the CLSID of SENS. Arguments: clsid - CLSID of the Subscriber for LCE events. strSubscriberName - Name of the Subscriber. bUnregister - If TRUE, then unregister the CLSID of SENS. Notes: This function also registers SENS to receive IE5's WININET events. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; HMODULE hModule; HKEY appidKey; HKEY clsidKey; HKEY serverKey; WCHAR *szCLSID; WCHAR *szCLSID2; WCHAR *szLIBID; TCHAR *szCLSID_t; TCHAR *szCLSID2_t; TCHAR *szLIBID_t; TCHAR *szFriendlyName; TCHAR szPath[MAX_PATH+1+sizeof(SENS_BINARYA)+1]; // +1 for '\' UINT uiLength; DWORD dwDisposition; LONG lResult; hr = S_OK; appidKey = NULL; clsidKey = NULL; serverKey = NULL; szCLSID = NULL; szCLSID2 = NULL; szLIBID = NULL; szCLSID_t = NULL; szCLSID2_t = NULL; szLIBID_t = NULL; uiLength = 0; dwDisposition = 0x0; szFriendlyName = strSubscriberName; // // Get the Full path name to the SENS executable // uiLength = GetSystemDirectory( szPath, MAX_PATH ); if (uiLength == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrintA(SENS_ERR, (SENS_SETUP "GetSystemDirectory(%s) failed - hr = <%x>\n", SENS_BINARYA, hr)); goto Cleanup; } _tcscat(szPath, SENS_STRING("\\")); _tcscat(szPath, SENS_BINARY); // // Convert the CLSID into a WCHAR. // hr = StringFromCLSID(clsid, &szCLSID); if (FAILED(hr)) { goto Cleanup; } if (bUnregister == FALSE) { hr = StringFromCLSID(LIBID_SensEvents, &szLIBID); if (FAILED(hr)) { goto Cleanup; } } // // Convert UNICODE strings into ANSI, if necessary // #if !defined(SENS_CHICAGO) szCLSID_t = szCLSID; szLIBID_t = szLIBID; #else // SENS_CHICAGO szCLSID_t = SensUnicodeStringToAnsi(szCLSID); szLIBID_t = SensUnicodeStringToAnsi(szLIBID); if ( (NULL == szCLSID_t) || (NULL == szLIBID_t)) { goto Cleanup; } #endif // SENS_CHICAGO // Build the key CLSID\\{clsid} TCHAR clsidKeyName[sizeof "CLSID\\{12345678-1234-1234-1234-123456789012}"]; _tcscpy(clsidKeyName, SENS_STRING("CLSID\\")); _tcscat(clsidKeyName, szCLSID_t); // Build the key AppID\\{clsid} TCHAR appidKeyName[sizeof "AppID\\{12345678-1234-1234-1234-123456789012}"]; _tcscpy(appidKeyName, SENS_STRING("AppID\\")); _tcscat(appidKeyName, szCLSID_t); if (bUnregister) { hr = RecursiveDeleteKey(HKEY_CLASSES_ROOT, clsidKeyName); if (FAILED(hr)) { goto Cleanup; } hr = RecursiveDeleteKey(HKEY_CLASSES_ROOT, appidKeyName); goto Cleanup; } // Create the CLSID\\{clsid} key hr = CreateKey( HKEY_CLASSES_ROOT, clsidKeyName, szFriendlyName, &clsidKey ); if (FAILED(hr)) { goto Cleanup; } // // Under the CLSID\\{clsid} key, create a named value // AppID = {clsid} hr = CreateNamedValue(clsidKey, SENS_STRING("AppID"), szCLSID_t); if (FAILED(hr)) { goto Cleanup; } // // Create the appropriate server key beneath the clsid key. // For servers, this is CLSID\\{clsid}\\LocalServer32. // In both cases, the default value is the module path name. // hr = CreateKey( clsidKey, SENS_STRING("LocalServer32"), szPath, &serverKey ); if (FAILED(hr)) { goto Cleanup; } RegCloseKey(serverKey); // // Create CLSID\\{clsid}\\TypeLib subkey with a default value of // the LIBID of the TypeLib // hr = CreateKey( clsidKey, SENS_STRING("TypeLib"), szLIBID_t, &serverKey ); if (FAILED(hr)) { goto Cleanup; } RegCloseKey(serverKey); // Register APPID. hr = CreateKey( HKEY_CLASSES_ROOT, appidKeyName, szFriendlyName, &appidKey ); if (FAILED(hr)) { goto Cleanup; } #if !defined(SENS_CHICAGO) // Under AppId\{clsid} key, create a named value [LocalService = "SENS"] hr = CreateNamedValue(appidKey, SENS_STRING("LocalService"), SENS_STRING("SENS")); if (FAILED(hr)) { goto Cleanup; } #else // SENS_CHICAGO // Under AppId\{clsid} key, create a named value [RunAs = "Interactive User"] hr = CreateNamedValue(appidKey, SENS_STRING("RunAs"), SENS_STRING("Interactive User")); if (FAILED(hr)) { goto Cleanup; } #endif // SENS_CHICAGO Cleanup: // // Cleanup // CoTaskMemFree(szCLSID); CoTaskMemFree(szLIBID); if (clsidKey != NULL) { RegCloseKey(clsidKey); } if (appidKey != NULL) { RegCloseKey(appidKey); } #if defined(SENS_CHICAGO) if (szCLSID_t != NULL) { delete szCLSID_t; } if (szLIBID_t != NULL) { delete szLIBID_t; } #endif // SENS_CHICAGO return hr; } #if defined(SENS_NT4) HRESULT RegisterSensAsService( BOOL bUnregister ) /*++ Routine Description: Configure SENS as a Win32 System service. Arguments: bUnregister - If TRUE, then unregister SENS as a service. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; hr = S_OK; if (bUnregister) { hr = RemoveService(); } else { hr = InstallService(); } return hr; } HRESULT InstallService( void ) /*++ Routine Description: Install SENS as a service with the Service Control Manager. Arguments: None. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; TCHAR szPath[MAX_PATH+1+sizeof(SENS_BINARYA)+1]; // +1 for '\' LPTSTR pFilePart; UINT uiLength; SC_HANDLE hSCM; SC_HANDLE hSens; hr = S_OK; pFilePart = NULL; uiLength = 0; hSCM = NULL; hSens = NULL; // // Get the Full path name to the SENS executable // uiLength = GetSystemDirectory( szPath, MAX_PATH ); if (uiLength == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrintA(SENS_ERR, (SENS_SETUP "GetSystemDirectory(%s) failed - hr = <%x>\n", SENS_BINARYA, hr)); goto Cleanup; } _tcscat(szPath, SENS_STRING("\\")); _tcscat(szPath, SENS_BINARY); // // Register ourselves with the SCM // // Open the SCM for the local machine. hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if (NULL == hSCM) { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("OpenSCManager(%s) failed - hr = <%x>\n"), SENS_SERVICE, hr)); goto Cleanup; } hSens = CreateService( hSCM, // Handle to SCM SENS_SERVICE, // Name of the service executable SENS_DISPLAY_NAME, // Service Display name SERVICE_ALL_ACCESS, // Access to the service SERVICE_WIN32_OWN_PROCESS, // Type of the service SERVICE_DEMAND_START, // Start type of the service SERVICE_ERROR_NORMAL, // Severity of the error during startup szPath, // Binary path name SENS_SERVICE_GROUP, // Load ordering group NULL, // No tag identifier SENS_STRING("EventSystem\0"), // Dependencies NULL, // LocalSystem account NULL // No password ); if (NULL == hSens) { if (GetLastError() != ERROR_SERVICE_EXISTS) { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("CreateService(%s) failed - hr = <%x>\n"), SENS_SERVICE, hr)); } else { SensPrint(SENS_WARN, (SENS_SETUPW SENS_STRING("SENS service is already installed.\n"))); BOOL bRetValue; // // Get a handle to SCM // hSens = OpenService( hSCM, SENS_SERVICE, SERVICE_ALL_ACCESS ); if (NULL == hSens) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Cleanup; } // // Mark the service to demand-start by default. // NULL parameter implies no change. // bRetValue = ChangeServiceConfig( hSens, // Handle to service SERVICE_NO_CHANGE, // Type of service SERVICE_DEMAND_START, // When to start service SERVICE_NO_CHANGE, // Severity if service fails to start NULL, // Pointer to service binary file name NULL, // Pointer to load ordering group name NULL, // Pointer to variable to get tag identifier NULL, // Pointer to array of dependency names NULL, // Pointer to account name of service NULL, // Pointer to password for service account NULL // Pointer to display name ); if (FALSE == bRetValue) { hr = HRESULT_FROM_WIN32(GetLastError()); } SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("ChangeServiceConfig(%s)") SENS_STRING(" returned hr - <%x>\n"), SENS_SERVICE, hr)); } goto Cleanup; } SensPrint(SENS_INFO, (SENS_SETUPW SENS_STRING("SENS service successfully installed.\n"))); Cleanup: // // Cleanup // if (hSens != NULL) { // // Give everyone the ability to start the service. // hr = SetServiceWorldAccessMask(hSens, SERVICE_START); SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("SerServiceWorldAccessMask(%s)") SENS_STRING(" returned hr - <%x>\n"), SENS_SERVICE, hr)); CloseServiceHandle(hSens); } if (hSCM != NULL) { CloseServiceHandle(hSCM); } return hr; } HRESULT RemoveService( void ) /*++ Routine Description: Remove SENS as a service. Arguments: None. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; SC_HANDLE hSCM; SC_HANDLE hSens; BOOL bSuccess; SERVICE_STATUS SvcStatus; hr = S_OK; hSCM = NULL; hSens = NULL; bSuccess = FALSE; // // Unregister ourselves from the SCM // // Open the SCM for the local machine. hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if (NULL == hSCM) { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("OpenSCManager() failed - hr = <%x>\n"), hr)); goto Cleanup; } hSens = OpenService( hSCM, SENS_SERVICE, SERVICE_ALL_ACCESS ); if (NULL == hSens) { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("OpenService(%s) failed - hr = <%x>\n"), SENS_SERVICE, hr)); goto Cleanup; } // // Try to stop the service // bSuccess = ControlService( hSens, SERVICE_CONTROL_STOP, &SvcStatus ); if (bSuccess == TRUE) { SensPrint(SENS_INFO, (SENS_SETUPW SENS_STRING("Stopping %s."), SENS_SERVICE)); do { Sleep(1000); if (SvcStatus.dwCurrentState == SERVICE_STOP_PENDING) { SensPrint(SENS_INFO, (SENS_STRING("."))); } else { SensPrint(SENS_INFO, (SENS_STRING("\n"))); break; } } while (QueryServiceStatus(hSens, &SvcStatus)); if (SvcStatus.dwCurrentState == SERVICE_STOPPED) { SensPrint(SENS_INFO, (SENS_SETUPW SENS_STRING("\n%s stopped.\n"), SENS_SERVICE)); } else { SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("\n%s failed to stop.\n"), SENS_SERVICE)); } } // // Now, remove the service // if (DeleteService(hSens)) { SensPrint(SENS_INFO, (SENS_SETUPW SENS_STRING("%s removed.\n"), SENS_SERVICE)); } else { hr = HRESULT_FROM_WIN32(GetLastError()); SensPrint(SENS_ERR, (SENS_SETUPW SENS_STRING("%s removal failed.\n"), SENS_SERVICE)); } Cleanup: // // Cleanup // if (hSens != NULL) { CloseServiceHandle(hSens); } if (hSCM != NULL) { CloseServiceHandle(hSCM); } return hr; } HRESULT SetServiceWorldAccessMask( SC_HANDLE hService, DWORD dwAccessMask ) /*++ Routine Description: Add the access rights specified in the dwAccessMask to Everyone (World) with respect to this service. This was written to add SERVICE_START right to Everyone wrt SENS. Arguments: hService - The service in question. dwAccessMask - The desired access rights to be set. Notes: a. This code assumes that the WorldSid is present in the DACL of SENS service. This is true for NT4. b. This a security hole. This security hole is not going to be plugged in future Service Packs of NT4 since some applications will break. c. This code needs to be modified to make it work on NT5. Return Value: S_OK, if successful. HRESULT, on failure. --*/ { int i; PSID pWorldSid; SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY; DWORD dwError; DWORD dwSize; PSECURITY_DESCRIPTOR pSD; PACL pDacl; BOOL bStatus; BOOL bDaclPresent; BOOL bDaclDefaulted; PACCESS_ALLOWED_ACE pAce; i = 0; pWorldSid = NULL; pSD = NULL; pDacl = NULL; dwSize = 0x0; dwError = ERROR_SUCCESS; bStatus = FALSE; bDaclPresent = FALSE; bDaclDefaulted = FALSE; pAce = NULL; // // Allocate WorldSid // bStatus = AllocateAndInitializeSid( &WorldAuthority, // Pointer to identifier authority 1, // Count of subauthority SECURITY_WORLD_RID, // Subauthority 0 0, // Subauthority 1 0, // Subauthority 2 0, // Subauthority 3 0, // Subauthority 4 0, // Subauthority 5 0, // Subauthority 6 0, // Subauthority 7 &pWorldSid // pointer to pointer to SID ); if (FALSE == bStatus) { dwError = GetLastError(); SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): AllocateAndInitiali" "zeSid() failed with %d.\n", dwError)); goto Cleanup; } // // Figure out how much buffer is needed for holding the service's // Security Descriptor (SD). // // NOTE: We pass &pSD instead of pSD because this parameter should // not be NULL. For this call to QueryServiceObjectSecurity() // we just need to pass some non-zero and valid buffer. // bStatus = QueryServiceObjectSecurity( hService, // Handle of the service DACL_SECURITY_INFORMATION, // Type of info requested &pSD, // Address of Security descriptor 0, // Size of SD buffer &dwSize // Size of buffer needed ); if ( (TRUE == bStatus) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { dwError = GetLastError(); SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): QueryServiceObject" "Security() returned unexpected result - %d.\n", dwError)); goto Cleanup; } // // Allocate the SD // pSD = (PSECURITY_DESCRIPTOR) new char[dwSize]; if (NULL == pSD) { dwError = ERROR_OUTOFMEMORY; SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): Failed to allocate" "memory for a Security Descriptor.\n")); goto Cleanup; } // // Now, we are ready to get the service's SD. // bStatus = QueryServiceObjectSecurity( hService, // Handle of the service DACL_SECURITY_INFORMATION, // Type of info requested pSD, // Address of Security descriptor dwSize, // Size of SD buffer &dwSize // Size of buffer needed ); if (FALSE == bStatus) { dwError = GetLastError(); ASSERT(dwError != ERROR_INSUFFICIENT_BUFFER); SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): QueryServiceObject" "Security() failed with %d.\n", dwError)); goto Cleanup; } // // Get the DACL from SD, if present. // bStatus = GetSecurityDescriptorDacl( pSD, // Address of SD &bDaclPresent, // Address of flag for presence of DACL &pDacl, // Address of pointer to DACL &bDaclDefaulted // Address of flag that indicates if ); // DACL was defaulted. if (FALSE == bStatus) { dwError = GetLastError(); SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): GetSecurityDescriptor" "Dacl() failed with %d.\n", dwError)); goto Cleanup; } // // For a service, we always expect to see a DACL. // ASSERT(bDaclPresent && (pDacl != NULL)); if ( (FALSE == bDaclPresent) || (NULL == pDacl)) { dwError = E_UNEXPECTED; SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): DACL is not present" "or DACL is NULL. Returning %d.\n", dwError)); goto Cleanup; } // // Find the WorldSid ACE in the ACL and update it's Mask. // for (i = 0; i < pDacl->AceCount; i++) { bStatus = GetAce( pDacl, // pointer to ACL i, // index of ACE to retrieve (LPVOID*) &pAce // pointer to pointer to ACE ); if (FALSE == bStatus) { dwError = GetLastError(); SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): GetAce()" "failed with %d.\n", dwError)); goto Cleanup; } if (EqualSid(pWorldSid, &(pAce->SidStart))) { pAce->Mask |= dwAccessMask; } } // for () // // Set the new SD on the service handle // bStatus = SetServiceObjectSecurity( hService, // Handle to the service. DACL_SECURITY_INFORMATION, // Type of info being set pSD // Address of the new SD ); if (FALSE == bStatus) { dwError = GetLastError(); SensPrintA(SENS_ERR, ("SetServiceWorldAccessMask(): SetServiceObject" "Security() failed with %d.\n", dwError)); goto Cleanup; } Cleanup: // // Cleanup // if (NULL != pWorldSid) { FreeSid(pWorldSid); } if (NULL != pSD) { delete pSD; } return HRESULT_FROM_WIN32(dwError); } void CALLBACK MarkSensAsDemandStart( HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow ) /*++ Routine Description: A function compatible with RunDll32 that will mark SENS as manual start. Arguments: hwnd - Window handle that should be used as the owner window for any windows this DLL creates. hinst - This DLL's instance handle lpszCmdLine - ASCII command line the DLL should parse nCmdShow - Describes how the DLL's windows should be displayed Return Value: None. --*/ { SC_HANDLE hSCM; SC_HANDLE hSens; BOOL bStatus; DWORD dwError; SERVICE_STATUS ServiceStatus; bStatus = FALSE; dwError = ERROR_SUCCESS; #ifdef DBG EnableDebugOutputIfNecessary(); #endif // DBG hSCM = OpenSCManager( NULL, // Local machine NULL, // Default database - SERVICES_ACTIVE_DATABASE SC_MANAGER_ALL_ACCESS // NT4 NOTE: Only for Administrators. ); if (NULL == hSCM) { dwError = GetLastError(); SensPrintA(SENS_ERR, (SENS_SETUP "OpenSCManager() failed with 0x%x\n", dwError)); goto Cleanup; } // // Get a handle to SCM // hSens = OpenService( hSCM, // Handle to SCM database SENS_SERVICE, // Name of the service in question SERVICE_ALL_ACCESS // Type of access requested to the service ); if (NULL == hSens) { dwError = GetLastError(); SensPrintA(SENS_ERR, (SENS_SETUP "OpenService() failed with 0x%x\n", dwError)); goto Cleanup; } // // Mark the service to Manual. NULL parameter implies no change. // bStatus = ChangeServiceConfig( hSens, // Handle to service SERVICE_NO_CHANGE, // Type of service SERVICE_DEMAND_START, // When to start service SERVICE_NO_CHANGE, // Severity if service fails to start NULL, // Pointer to service binary file name NULL, // Pointer to load ordering group name NULL, // Pointer to variable to get tag identifier NULL, // Pointer to array of dependency names NULL, // Pointer to account name of service NULL, // Pointer to password for service account NULL // Pointer to display name ); if (FALSE == bStatus) { dwError = GetLastError(); SensPrintA(SENS_ERR, (SENS_SETUP "ChangeServiceConfig() failed with 0x%x\n", dwError)); goto Cleanup; } SensPrintA(SENS_ERR, (SENS_SETUP "SENS now marked as DEMAND START\n\n")); Cleanup: // // Cleanup // if (NULL != hSCM) { CloseServiceHandle(hSCM); } if (NULL != hSens) { CloseServiceHandle(hSens); } } #endif // SENS_NT4 HRESULT CreateKey( HKEY hParentKey, const TCHAR* KeyName, const TCHAR* defaultValue, HKEY* hKey ) /*++ Routine Description: Create a key (with an optional default value). The handle to the key is returned as an [out] parameter. If NULL is passed as the key parameter, the key is created in the registry, then closed. Arguments: hParentKey - Handle to the parent Key. KeyName - Name of the key to create. defaultValue - The default value for the key to create. hKey - OUT Handle to key that was created. Return Value: S_OK, if successful hr, otherwise --*/ { HKEY hTempKey; LONG lResult; hTempKey = NULL; lResult = RegCreateKeyEx( hParentKey, // Handle to open key KeyName, // Subkey name 0, // Reserved NULL, // Class string REG_OPTION_NON_VOLATILE, // Options Flag KEY_ALL_ACCESS, // Desired Security access NULL, // Pointer to Security Attributes structure &hTempKey, // Handle of the opened/created key NULL // Disposition value ); if (lResult != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lResult); } // Set the default value for the key if (defaultValue != NULL) { lResult = RegSetValueEx( hTempKey, // Key to set Value for. NULL, // Value to set 0, // Reserved REG_SZ, // Value Type (BYTE*) defaultValue, // Address of Value data sizeof(TCHAR) * (_tcslen(defaultValue)+1) // Size of Value ); if (lResult != ERROR_SUCCESS) { RegCloseKey(hTempKey); return HRESULT_FROM_WIN32(lResult); } } if (hKey == NULL) { RegCloseKey(hTempKey); } else { *hKey = hTempKey; } return S_OK; } HRESULT CreateNamedValue( HKEY hKey, const TCHAR* title, const TCHAR* value ) /*++ Routine Description: Create a named value under a key Arguments: hKey - Handle to the parent Key. title - Name of the Value to create. value - The data for the Value under the Key. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; LONG lResult; hr = S_OK; lResult = RegSetValueEx( hKey, // Key to set Value for. title, // Value to set 0, // Reserved REG_SZ, // Value Type (BYTE*) value, // Address of Value data sizeof(TCHAR) * (_tcslen(value)+1) // Size of Value ); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); } return hr; } HRESULT CreateNamedDwordValue( HKEY hKey, const TCHAR* title, DWORD dwValue ) /*++ Routine Description: Create a named DWORD value under a key Arguments: hKey - Handle to the parent Key. title - Name of the Value to create. dwValue - The data for the Value under the Key. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; LONG lResult; hr = S_OK; lResult = RegSetValueEx( hKey, // Key to set Value for. title, // Value to set 0, // Reserved REG_DWORD, // Value Type (BYTE*) &dwValue, // Address of Value data sizeof(DWORD) // Size of Value ); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); } return hr; } HRESULT RecursiveDeleteKey( HKEY hKeyParent, const TCHAR* lpszKeyChild ) /*++ Routine Description: Delete a key and all of its descendents. Arguments: hKeyParent - Handle to the parent Key. lpszKeyChild - The data for the Value under the Key. Return Value: S_OK, if successful hr, otherwise --*/ { HKEY hKeyChild; LONG lResult; // // Open the child. // lResult = RegOpenKeyEx( hKeyParent, // Handle to the Parent lpszKeyChild, // Name of the child key 0, // Reserved KEY_ALL_ACCESS, // Security Access Mask &hKeyChild // Handle to the opened key ); if (lResult != ERROR_SUCCESS) { return HRESULT_FROM_WIN32(lResult); } // // Enumerate all of the decendents of this child. // FILETIME time; TCHAR szBuffer[MAX_PATH+1]; const DWORD bufSize = sizeof szBuffer / sizeof szBuffer[0]; DWORD dwSize = bufSize; while (TRUE) { lResult = RegEnumKeyEx( hKeyChild, // Handle of the key to enumerate 0, // Index of the subkey to retrieve szBuffer, // OUT Name of the subkey &dwSize, // OUT Size of the buffer for name of subkey NULL, // Reserved NULL, // OUT Class of the enumerated subkey NULL, // OUT Size of the class of the subkey &time // OUT Last time the subkey was written to ); if (lResult != ERROR_SUCCESS) { break; } // Delete the decendents of this child. lResult = RecursiveDeleteKey(hKeyChild, szBuffer); if (lResult != ERROR_SUCCESS) { // Cleanup before exiting. RegCloseKey(hKeyChild); return HRESULT_FROM_WIN32(lResult); } dwSize = bufSize; } // while // Close the child. RegCloseKey(hKeyChild); // Delete this child. lResult = RegDeleteKey(hKeyParent, lpszKeyChild); return HRESULT_FROM_WIN32(lResult); } HRESULT SensConfigureEventSystem( BOOL bUnregister ) /*++ Routine Description: As of NTbuild 1750, EventSystem is not auto-configured. So, SENS does the work of configuring EventSystem. Arguments: bUnregister - If TRUE, then install EventSystem. Notes: o This is a dummy call on NT4 because we don't need to configure EventSystem on NT4. IE5 setup (Webcheck.dll) configures LCE. Return Value: S_OK, if successful hr, otherwise --*/ { return S_OK; } HRESULT SensUpdateVersion( BOOL bUnregister ) /*++ Routine Description: Update the version of SENS in the registry. Arguments: bUnregister - usual. Return Value: S_OK, if successful hr, otherwise --*/ { HRESULT hr; HKEY hKeySens; LONG RegStatus; DWORD dwConfigured; hr = S_OK; hKeySens = NULL; RegStatus = ERROR_SUCCESS; RegStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, // Handle of the key SENS_REGISTRY_KEY, // String which represents the sub-key to open 0, // Reserved (MBZ) KEY_ALL_ACCESS, // Security Access mask &hKeySens // Returned HKEY ); if (RegStatus != ERROR_SUCCESS) { SensPrintA(SENS_ERR, (SENS_SETUP "RegOpenKeyEx(Sens) returned %d.\n", RegStatus)); hr = HRESULT_FROM_WIN32(RegStatus); goto Cleanup; } if (TRUE == bUnregister) { dwConfigured = CONFIG_VERSION_NONE; } else { dwConfigured = CONFIG_VERSION_CURRENT; } // Update registry to reflect that SENS is now configured. RegStatus = RegSetValueEx( hKeySens, // Key to set Value for. IS_SENS_CONFIGURED, // Value to set 0, // Reserved REG_DWORD, // Value Type (BYTE*) &dwConfigured,// Address of Value data sizeof(DWORD) // Size of Value ); if (RegStatus != ERROR_SUCCESS) { SensPrintA(SENS_ERR, (SENS_SETUP "RegSetValueEx(IS_SENS_CONFIGURED) failed with 0x%x\n", RegStatus)); hr = HRESULT_FROM_WIN32(RegStatus); goto Cleanup; } SensPrintA(SENS_INFO, (SENS_SETUP "SENS is now configured successfully. " "Registry updated to 0x%x.\n", dwConfigured)); Cleanup: // // Cleanup // if (hKeySens) { RegCloseKey(hKeySens); } return hr; } #if defined(SENS_CHICAGO) extern "C" int APIENTRY DllMain( IN HINSTANCE hInstance, IN DWORD dwReason, IN LPVOID lpvReserved ) /*++ Routine Description: This routine will get called either when a process attaches to this dll or when a process detaches from this dll. Return Value: TRUE - Initialization successfully occurred. FALSE - Insufficient memory is available for the process to attach to this dll. --*/ { BOOL bSuccess; switch (dwReason) { case DLL_PROCESS_ATTACH: // Disable Thread attach/detach calls bSuccess = DisableThreadLibraryCalls(hInstance); ASSERT(bSuccess == TRUE); break; case DLL_PROCESS_DETACH: break; } return(TRUE); } #endif // SENS_CHICAGO