/*++ 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 // // 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")); } // // 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)); // // 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")); } // // 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 StringCchCopy(szQuery, MAX_QUERY_SIZE, SENS_BSTR("EventClassID=")); AllocateStrFromGuid(strEventClassID, *(gSensEventClasses[i].pEventClassID)); StringCchCat(szQuery, MAX_QUERY_SIZE, strEventClassID); 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 StringCchCopy(szQuery, MAX_QUERY_SIZE, SENS_BSTR("SubscriptionID=")); AllocateStrFromGuid(strSubscriptionID, *(gSensSubscriptions[i].pSubscriptionID)); StringCchCat(szQuery, MAX_QUERY_SIZE, 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. StringCchCopy(szQuery, MAX_QUERY_SIZE, gSensSubscriptions[i].strPropertyEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, *(gSensSubscriptions[i].pPropertyEventClassIDValue)); StringCchCat(szQuery, MAX_QUERY_SIZE, strEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR(" AND ")); StringCchCat(szQuery, MAX_QUERY_SIZE, gSensSubscriptions[i].strPropertyMethodName); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR("=\'")); StringCchCat(szQuery, MAX_QUERY_SIZE, gSensSubscriptions[i].strPropertyMethodNameValue); StringCchCat(szQuery, MAX_QUERY_SIZE, 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. StringCchCopy(szQuery, MAX_QUERY_SIZE, gSensSubscriptions[i].strPropertyEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, SENSGUID_EVENTCLASS_NETWORK); StringCchCat(szQuery, MAX_QUERY_SIZE, strEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR(" OR ")); FreeStr(strEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, gSensSubscriptions[i].strPropertyEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, SENSGUID_EVENTCLASS_LOGON); StringCchCat(szQuery, MAX_QUERY_SIZE, strEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR(" OR ")); FreeStr(strEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, gSensSubscriptions[i].strPropertyEventClassID); StringCchCat(szQuery, MAX_QUERY_SIZE, SENS_BSTR("=")); AllocateStrFromGuid(strEventClassID, SENSGUID_EVENTCLASS_ONNOW); StringCchCat(szQuery, MAX_QUERY_SIZE, 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 '\' hr = S_OK; uiLength = 0; // // 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; } StringCbCat(buffer, sizeof(buffer), SENS_STRING("\\") SENS_TLB); hr = LoadTypeLibEx( buffer, 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, buffer, NULL ); } if (FAILED(hr)) { SensPrintA(SENS_ERR, (SENS_SETUP "%sRegisterTypeLib(%s) failed " " - hr = <%x>\n", (bUnregister ? "Un" : ""), SENS_TLBA, hr)); } Cleanup: // // Cleanup // 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; } StringCbCat(szPath, sizeof(szPath), SENS_STRING("\\") 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; } } szCLSID_t = szCLSID; szLIBID_t = szLIBID; // Build the key CLSID\\{clsid} TCHAR clsidKeyName[sizeof "CLSID\\{12345678-1234-1234-1234-123456789012}"]; StringCbCopy(clsidKeyName, sizeof(clsidKeyName), SENS_STRING("CLSID\\")); StringCbCat(clsidKeyName, sizeof(clsidKeyName), szCLSID_t); // Build the key AppID\\{clsid} TCHAR appidKeyName[sizeof "AppID\\{12345678-1234-1234-1234-123456789012}"]; StringCbCopy(appidKeyName, sizeof(appidKeyName), SENS_STRING("AppID\\")); StringCbCat(appidKeyName, sizeof(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; } // Under AppId\{clsid} key, create a named value [LocalService = "SENS"] hr = CreateNamedValue(appidKey, SENS_STRING("LocalService"), SENS_STRING("SENS")); if (FAILED(hr)) { goto Cleanup; } Cleanup: // // Cleanup // CoTaskMemFree(szCLSID); CoTaskMemFree(szLIBID); if (clsidKey != NULL) { RegCloseKey(clsidKey); } if (appidKey != NULL) { RegCloseKey(appidKey); } return hr; } 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; }