/*++ Copyright (c) 1995 Microsoft Corporation Module Name: setup.c Abstract: This module contains code for migrating WinSock 1.1 setup information to the new WinSock 2.0 structure. The basic strategy keeps a private copy of the Winsock 1.1 protocol data off to the side and compares this saved data with the current data when necessary. MigrateWinsockConfiguration() is invoked by NT Setup immediately after binding review, and at an appropriate point during the upgrade process. MigrateWinsockConfiguration() uses the following registry structure: HKEY_LOCAL_MACHINE System CurrentControlSet Services WinSock Setup Migration Setup Version = REG_DWORD {...} Provider List = REG_MULTI_SZ "provider1 provider2..." Known Static Providers = REG_MULTI_SZ "provider1 provider2..." Providers provider1 WinSock 1.1 Provider Data = REG_BINARY {...} WinSock 2.0 Provider ID = REG_BINARY {...} provider2 WinSock 1.1 Provider Data = REG_BINARY {...} WinSock 2.0 Provider ID = REG_BINARY {...} ... Well Known Guids provider1 = REG_BINARY {...} provider2 = REG_BINARY {...} ... Where: Setup Version - Contains a version number of the migration code. This exists for forward compatibility. If future versions of the migration code have a differing registry layout, they can key off this version number and optionally blow away the entire Setup Migration tree. Provider List - Contains a copy of the WinSock\Parameters\Transports value from a previous invocation of MigrateWinsockConfiguration(). Keeping a copy of this data allows us to quickly determine which transports have been added or deleted. Known Static Providers - Some transports (such as NetBIOS) are LANA based, and therefore change their supported triples depending on installed hardware. To reduce registry space, and to also reduce thrashing of WinSock 1.1 providers and avoid calling WSHEnumProtocols() unnecessarily, this value keeps a list of providers that are known to not change their supported triples based on installed hardware. Examples of providers eligible for this list are Tcpip, NwlnkIpx, and NwlnkSpx. TP4 and XNS are probably eligible as well. Providers - This subkey contains a catalog of installed WinSock 1.1 providers. Each installed provider has an individual subkey beneath this key. WinSock 1.1 Provider Data - Contains the raw binary data returned by the provider's WSHEnumProtocols() entrypoint. This data is stored in self-relative form (embedded pointers are mapped to structure offsets before writing the data to the registry). This value does not exist for known static providers. WinSock 2.0 Provider ID - Contains the provider GUID identifying the provider. This value has three possible sources: 1. The provider's helper DLL, if the WSHGetProviderGuid() entrypoint is supported. 2. A hard-coded list of "well known" GUIDs for select providers. 3. Created on-the-fly. Well Known Guids - A catalog of well known provider GUIDs. We'd really like a given provider to always have the same GUID on all machines. For providers in which we have control over the helper DLL, we'll add the WSHGetProviderGuid() entrypoint. For known providers in which we do not have control over the helper DLL, we'll create a GUID for the provider and add it to this catalog. All other providers (basically, anything unknown) will have a GUID created on-the-fly and added to this catalog. These providers will not have the same GUID on all machines, but at least they will have the same GUID if removed & reinstalled on a particular machine. Author: Keith Moore (keithmo) 31-Oct-1995 Revision History: --*/ #define UNICODE #define _UNICODE #include "winsockp.h" #include #include #include #include // // Private constants. // #define ALLOC_MEM(cb) ALLOCATE_HEAP(cb) // These macros isolate #define FREE_MEM(p) FREE_HEAP(p) // this module from #define DBG_ASSERT(exp) WS_ASSERT(exp) // WSOCK32.DLL, in case #define DBG_PRINT WS_PRINT // this is moved to #define IF_DEBUG_SETUP IF_DEBUG( SETUP ) // a separate DLL. #define WINSOCK_SETUP_VERSION 0x1009 // Update for major setup changes! #define WINSOCK_SPI_VERSION 2 #define MAX_REGISTRY_NAME 256 #define DEFAULT_PROVIDER_PATH TEXT("%SystemRoot%\\system32\\msafd.dll") #define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services") #define WINSOCK_SUBKEY TEXT("WinSock") #define MIGRATION_SUBKEY TEXT("Setup Migration") #define PROVIDERS_SUBKEY TEXT("Providers") #define PARAMETERS_SUBKEY TEXT("Parameters") #define SERVICE_PARAMS_SUBKEY TEXT("Parameters\\WinSock") #define WELL_KNOWN_GUIDS_SUBKEY TEXT("Well Known Guids") #define SETUP_VERSION_VALUE TEXT("Setup Version") #define TRANSPORTS_VALUE TEXT("Transports") #define MAPPING_VALUE TEXT("Mapping") #define PROVIDER_LIST_VALUE TEXT("Provider List") #define KNOWN_STATIC_VALUE TEXT("Known Static Providers") #define WINSOCK_1_1_DATA_VALUE TEXT("WinSock 1.1 Provider Data") #define WINSOCK_2_0_ID_VALUE TEXT("WinSock 2.0 Provider ID") #define HELPER_DLL_NAME_VALUE TEXT("HelperDllName") #define COMMON_SERVICE_FLAGS ( XP_CONNECTIONLESS | \ XP_GUARANTEED_DELIVERY | \ XP_GUARANTEED_ORDER | \ XP_MESSAGE_ORIENTED | \ XP_PSEUDO_STREAM | \ XP_GRACEFUL_CLOSE | \ XP_EXPEDITED_DATA | \ XP_CONNECT_DATA | \ XP_DISCONNECT_DATA | \ XP_SUPPORTS_BROADCAST | \ XP_SUPPORTS_MULTICAST | \ XP_BANDWIDTH_ALLOCATION ) #define FORCED_SERVICE_FLAGS XP1_IFS_HANDLES // // The following macro makes invoking the user's callback a little // prettier. The macro makes the following assumptions: // // 1. The callback parameter is named "Callback". // // 2. The context parameter is named "Context". // // 3. A label for premature exit exists and is named "exit". // #define INVOKE_CALLBACK(op,p) \ if( Callback != NULL ) { \ if( !(*Callback)( \ (op), \ (p), \ Context \ ) ) { \ goto exit; \ } \ } else // // Private types. // typedef struct _NAME_GUID_PAIR { LPTSTR Name; GUID Guid; } NAME_GUID_PAIR, *LPNAME_GUID_PAIR; // // Private globals. // HMODULE Winsock2DllHandle = NULL; LPWSCDEINSTALLPROVIDER WSCDeinstallProviderProc = NULL; LPWSCINSTALLPROVIDER WSCInstallProviderProc = NULL; DWORD DefaultSetupVersion = WINSOCK_SETUP_VERSION; TCHAR DefaultProviderList[] = TEXT(""); TCHAR DefaultKnownStaticProviders[] = TEXT("Tcpip\0") TEXT("NwlnkIpx\0") TEXT("NwlnkSpx\0") TEXT("AppleTalk\0") TEXT("IsoTp\0"); NAME_GUID_PAIR DefaultWellKnownGuids[] = { { TEXT("IsoTp"), { /* 89e4cbb0-b9c1-11cf-95c8-00805f48a192 */ 0x89e4cbb0, 0xb9c1, 0x11cf, {0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92} } }, { TEXT("McsXns"), { /* 89e4cbb1-b9c1-11cf-95c8-00805f48a192 */ 0x89e4cbb1, 0xb9c1, 0x11cf, {0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92} } }, { TEXT("AppleTalk"), { /* 2c3b17a0-c6df-11cf-95c8-00805f48a192 */ 0x2c3b17a0, 0xc6df, 0x11cf, {0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92} } } }; #define NUM_DEFAULT_WELL_KNOWN_GUIDS \ (sizeof(DefaultWellKnownGuids) / sizeof(DefaultWellKnownGuids[0])) // // Private prototypes. // DWORD InitializeSetup( VOID ); VOID TerminateSetup( VOID ); BOOL IsStringInMultiSz( LPTSTR MultiSz, LPTSTR String ); DWORD ReadDword( HKEY RootKey, LPTSTR ValueName, LPDWORD Value ); DWORD ReadMultiSz( HKEY RootKey, LPTSTR ValueName, LPTSTR FAR * Value ); DWORD ReadBinary( HKEY RootKey, LPTSTR ValueName, LPVOID FAR * Value, LPDWORD ValueLength ); DWORD ReadString( HKEY RootKey, LPTSTR ValueName, LPTSTR FAR * Value ); DWORD ReadGuid( HKEY RootKey, LPTSTR ValueName, LPGUID Value ); DWORD WriteDword( HKEY RootKey, LPTSTR ValueName, DWORD Value ); DWORD WriteMultiSz( HKEY RootKey, LPTSTR ValueName, LPTSTR Value ); DWORD WriteBinary( HKEY RootKey, LPTSTR ValueName, LPVOID Value, DWORD ValueLength ); DWORD WriteString( HKEY RootKey, LPTSTR ValueName, LPTSTR Value ); DWORD WriteGuid( HKEY RootKey, LPTSTR ValueName, LPGUID Value ); DWORD OpenServicesRoot( PHKEY ServicesKey ); DWORD OpenWinsockRoot( HKEY ServicesKey, PHKEY WinsockKey ); DWORD OpenSetupMigrationRoot( HKEY WinsockKey, PHKEY MigrationKey, PHKEY ProvidersKey, PHKEY WellKnownGuidsKey ); DWORD ReadNewProviderList( HKEY WinsockKey, LPTSTR FAR * NewProviderList ); DWORD ReadOldProviderList( HKEY MigrationKey, LPTSTR FAR * OldProviderList ); DWORD ReadKnownStaticProviderList( HKEY MigrationKey, LPTSTR FAR * KnownStaticProviderList ); DWORD ReadProviderId( HKEY ProvidersKey, LPTSTR ProviderName, LPGUID ProviderId ); DWORD CreateDefaultSetupMigrationTree( HKEY WinsockKey, PHKEY MigrationKey, PHKEY ProvidersKey, PHKEY WellKnownGuidsKey ); DWORD RecursivelyDeleteRegistryTree( HKEY RootKey, LPTSTR TargetKeyName ); DWORD RemoveProviderByName( HKEY ProvidersKey, LPTSTR ProviderName ); DWORD ReadProtocolDataFromRegistry( HKEY ProvidersKey, LPTSTR ProviderName, LPPROTOCOL_INFO FAR * RegistryInfo11, LPDWORD RegistryInfo11Length ); DWORD ReadProtocolDataFromProvider( HKEY ServicesKey, LPTSTR ProviderName, LPTSTR ProviderDllPath, LPPROTOCOL_INFO FAR * ProtocolInfo11, LPDWORD ProtocolInfo11Length, LPDWORD ProtocolInfo11Entries ); DWORD ReadProviderSupportedProtocolsFromRegistry( HKEY ParametersKey, LPDWORD FAR * ProtocolList ); VOID MapProtocolInfoToSelfRelative( LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Entries ); VOID MapProtocolInfoToAbsolute( LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Entries ); DWORD BuildWinsock2ProtocolList( LPTSTR ProviderName, LPTSTR ProviderDllPath, LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Entries, LPWSAPROTOCOL_INFO FAR * ProtocolInfo2, LPDWORD ProtocolInfo2Entries ); VOID BuildNewProtocolName( LPTSTR ProviderName, LPPROTOCOL_INFO ProtocolInfo11, LPTSTR NewProtocolName ); DWORD InstallNewProvider( HKEY WellKnownGuidsKey, HKEY ProvidersKey, LPTSTR ProviderName, LPTSTR ProviderDllPath, BOOL IsKnownStaticProvider, LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Length, DWORD ProtocolInfo11Entries ); DWORD CreateMigrationRegistryForProvider( HKEY ProvidersKey, LPTSTR ProviderName, BOOL IsKnownStaticProvider, LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Length, LPGUID ProviderId ); DWORD CreateProtocolCatalogMutex( LPHANDLE Handle ); DWORD AcquireProtocolCatalogMutex( HANDLE Handle ); DWORD ReleaseProtocolCatalogMutex( HANDLE Handle ); DWORD RemoveAllInstalledProviders( HKEY ProvidersKey ); DWORD AppendStringToMultiSz( LPTSTR * MultiSz, LPTSTR String ); DWORD SanitizeWinsock2ConfigForProvider( LPGUID ProviderId ); DWORD DetermineGuidForProvider( HKEY WellKnownGuidsKey, LPTSTR ProviderName, LPTSTR ProviderDllPath, LPGUID ProviderId ); // // Public functions. // DWORD MigrateWinsockConfiguration( LPWSA_SETUP_DISPOSITION Disposition, LPFN_WSA_SETUP_CALLBACK Callback OPTIONAL, DWORD Context OPTIONAL ) /*++ Routine Description: This entrypoint is called by NT Setup whenever WinSock 1.1 setup changes might need to be migrated to WinSock 2.0. This entrypoint is typically called immediately after binding review, and at an appropriate point during system upgrade. Arguments: Disposition - Points to a WSA_SETUP_DISPOSITION value that allows this routine to indicate to the caller the scope of any changes made. If this function is successful, then this enum will receive one of the following values: WsaSetupNoChangesMade - There were no changes made to the existing WinSock 2.0 configuration. WsaSetupChangesMadeRebootNotNecessary - There were changes made to the WinSock 2.0 configuration, and a reboot of the system is not necessary. WsaSetupChangesMadeRebootRequired - There were changes made to the WinSock 2.0 configuration, and a reboot of the system is required. Callback - An optional pointer to a callback function invoked at strategic points in the migration process. The callback function has the following prototype: BOOL CALLBACK WsaSetupCallback( WSA_SETUP_OPCODE Opcode, LPVOID Parameter, Context ); Where: Opcode - Specifies the type of indication being made. This may be one of the following values: WsaSetupInstallingProvider - A new provider is being installed. Parameter points to the name of the new provider. WsaSetupRemovingProvider - An existing provider is being removed. Parameter points to the name of the existing provider. WsaSetupValidatingProvider - An existing provider is being validated to determine if it needs to be updated. Parameter points to the name of the existing provider. WsaSetupUpdatingProvider - An existing provider is being updated. Parameter points to the name of the existing proivder. Parameter - A generic parameter whose value depends upon the current Opcode (see above). Context - The context value passed into the migration function. The callback should return TRUE if the migration process is to continue, FALSE if it should be immediately terminated. Context - An uninterpreted context value to be passed to the callback function. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HKEY servicesKey; HKEY winsockKey; HKEY migrationKey; HKEY providersKey; HKEY wellKnownGuidsKey; LPTSTR oldProviders; LPTSTR newProviders; LPTSTR knownStaticProviders; LPTSTR providerName; LPTSTR updatedProviderList; INT result; LPPROTOCOL_INFO protocolInfo11; DWORD protocolInfo11Length; DWORD protocolInfo11Entries; LPPROTOCOL_INFO registryInfo11; DWORD registryInfo11Length; WSA_SETUP_DISPOSITION disposition; HANDLE mutexHandle; BOOL mutexOwned; TCHAR providerDllPath[MAX_PATH]; // // Sanity check. // DBG_ASSERT( Disposition != NULL ); // // Setup locals so we know how to cleanup on exit. // mutexHandle = NULL; mutexOwned = FALSE; servicesKey = NULL; winsockKey = NULL; migrationKey = NULL; providersKey = NULL; wellKnownGuidsKey = NULL; oldProviders = NULL; newProviders = NULL; updatedProviderList = NULL; knownStaticProviders = NULL; protocolInfo11 = NULL; registryInfo11 = NULL; // // Assume no changes will be made. // disposition = WsaSetupNoChangesMade; // // Initialize things. // error = InitializeSetup(); if( error != NO_ERROR ) { goto exit; } // // Create/open the protocol catalog mutex. // error = CreateProtocolCatalogMutex( &mutexHandle ); if( error != NO_ERROR ) { goto exit; } // // Acquire the protocol catalog mutex. // error = AcquireProtocolCatalogMutex( mutexHandle ); if( error != NO_ERROR ) { goto exit; } mutexOwned = TRUE; // // Open the necessary registry keys. // error = OpenServicesRoot( &servicesKey ); if( error != NO_ERROR ) { goto exit; } error = OpenWinsockRoot( servicesKey, &winsockKey ); if( error != NO_ERROR ) { if( error == ERROR_FILE_NOT_FOUND ) { error = NO_ERROR; } goto exit; } error = OpenSetupMigrationRoot( winsockKey, &migrationKey, &providersKey, &wellKnownGuidsKey ); if( error != NO_ERROR ) { goto exit; } // // Read the new & old provider lists. // error = ReadNewProviderList( winsockKey, &newProviders ); if( error != NO_ERROR ) { goto exit; } error = ReadOldProviderList( migrationKey, &oldProviders ); if( error != NO_ERROR ) { goto exit; } error = ReadKnownStaticProviderList( migrationKey, &knownStaticProviders ); if( error != NO_ERROR ) { goto exit; } // // Scan the old provider list, and remove any providers that are // not in the new provider list. // for( providerName = oldProviders ; *providerName != TEXT('\0') ; providerName += _tcslen( providerName ) + 1 ) { if( !IsStringInMultiSz( newProviders, providerName ) ) { INVOKE_CALLBACK( WsaSetupRemovingProvider, providerName ); error = RemoveProviderByName( providersKey, providerName ); if( error != NO_ERROR ) { goto exit; } disposition = WsaSetupChangesMadeRebootNotNecessary; } } // // Scan the new provider list, and add any providers that are not // in the old provider list. // for( providerName = newProviders ; *providerName != TEXT('\0') ; providerName += _tcslen( providerName ) + 1 ) { if( !IsStringInMultiSz( oldProviders, providerName ) ) { INVOKE_CALLBACK( WsaSetupInstallingProvider, providerName ); error = ReadProtocolDataFromProvider( servicesKey, providerName, providerDllPath, &protocolInfo11, &protocolInfo11Length, &protocolInfo11Entries ); if( error != NO_ERROR ) { goto exit; } if( protocolInfo11 == NULL ) { DBG_PRINT(( "%ls returned zero protocol entries!?!\n", providerName )); DBG_ASSERT( protocolInfo11Length == 0 ); DBG_ASSERT( protocolInfo11Entries == 0 ); continue; } error = InstallNewProvider( wellKnownGuidsKey, providersKey, providerName, providerDllPath, IsStringInMultiSz( knownStaticProviders, providerName ), protocolInfo11, protocolInfo11Length, protocolInfo11Entries ); if( error == NO_ERROR ) { error = AppendStringToMultiSz( &updatedProviderList, providerName ); if( error != NO_ERROR ) { goto exit; } } else { DBG_PRINT(( "cannot install %ls, error %d, skipping\n", providerName, error )); error = NO_ERROR; } FREE_MEM( protocolInfo11 ); protocolInfo11 = NULL; disposition = WsaSetupChangesMadeRebootNotNecessary; } } // // Finally, scan for dynamic entries that need to be updated. We'll // determine if a provider needs to be updated by reading the protocol // data stored in the registry, and also retrieving the protocol data // directly from the provider. If these two blocks of data do not // EXACTLY match, then we'll remove the old provider & reinstall it // using the protocol data retrieved from the provider. // for( providerName = newProviders ; *providerName != TEXT('\0') ; providerName += _tcslen( providerName ) + 1 ) { if( IsStringInMultiSz( oldProviders, providerName ) ) { if( IsStringInMultiSz( knownStaticProviders, providerName ) ) { error = AppendStringToMultiSz( &updatedProviderList, providerName ); if( error != NO_ERROR ) { goto exit; } continue; } INVOKE_CALLBACK( WsaSetupValidatingProvider, providerName ); error = ReadProtocolDataFromRegistry( providersKey, providerName, ®istryInfo11, ®istryInfo11Length ); if( error == ERROR_FILE_NOT_FOUND ) { DBG_PRINT(( "no registry data for %ls?!?\n", providerName )); error = NO_ERROR; registryInfo11 = NULL; registryInfo11Length = 0; } if( error != NO_ERROR ) { DBG_PRINT(( "cannot read registry data for %ls, error %lu\n", providerName, error )); goto exit; } error = ReadProtocolDataFromProvider( servicesKey, providerName, providerDllPath, &protocolInfo11, &protocolInfo11Length, &protocolInfo11Entries ); if( error != NO_ERROR ) { goto exit; } if( protocolInfo11 == NULL ) { if( registryInfo11 != NULL ) { FREE_MEM( registryInfo11 ); registryInfo11 = NULL; } DBG_PRINT(( "%ls returned zero protocol entries!?!\n", providerName )); DBG_ASSERT( protocolInfo11Length == 0 ); DBG_ASSERT( protocolInfo11Entries == 0 ); continue; } MapProtocolInfoToSelfRelative( protocolInfo11, protocolInfo11Entries ); if( registryInfo11Length == protocolInfo11Length && RtlEqualMemory( registryInfo11, protocolInfo11, protocolInfo11Length ) ) { // // They match, so add the provider to the list. // error = AppendStringToMultiSz( &updatedProviderList, providerName ); if( error != NO_ERROR ) { goto exit; } } else { // // They don't match, so remove the provider & reinstall // using the protocol information read from the provider. // INVOKE_CALLBACK( WsaSetupUpdatingProvider, providerName ); error = RemoveProviderByName( providersKey, providerName ); if( error != NO_ERROR ) { goto exit; } MapProtocolInfoToAbsolute( protocolInfo11, protocolInfo11Entries ); error = InstallNewProvider( wellKnownGuidsKey, providersKey, providerName, providerDllPath, FALSE, protocolInfo11, protocolInfo11Length, protocolInfo11Entries ); if( error == NO_ERROR ) { error = AppendStringToMultiSz( &updatedProviderList, providerName ); if( error != NO_ERROR ) { goto exit; } } else { DBG_PRINT(( "cannot install %ls, error %d, skipping\n", providerName, error )); error = NO_ERROR; } disposition = WsaSetupChangesMadeRebootNotNecessary; } if( protocolInfo11 != NULL ) { FREE_MEM( protocolInfo11 ); protocolInfo11 = NULL; } if( registryInfo11 != NULL ) { FREE_MEM( registryInfo11 ); registryInfo11 = NULL; } } } // // Update the provider list if necessary. // if( disposition != WsaSetupNoChangesMade ) { error = WriteMultiSz( migrationKey, PROVIDER_LIST_VALUE, updatedProviderList ); if( error != NO_ERROR ) { goto exit; } } exit: if( servicesKey != NULL ) { (VOID)RegCloseKey( servicesKey ); } if( winsockKey != NULL ) { (VOID)RegCloseKey( winsockKey ); } if( migrationKey != NULL ) { (VOID)RegCloseKey( migrationKey ); } if( providersKey != NULL ) { (VOID)RegCloseKey( providersKey ); } if( wellKnownGuidsKey != NULL ) { (VOID)RegCloseKey( wellKnownGuidsKey ); } if( oldProviders != NULL ) { FREE_MEM( oldProviders ); } if( newProviders != NULL ) { FREE_MEM( newProviders ); } if( updatedProviderList != NULL ) { FREE_MEM( updatedProviderList ); } if( knownStaticProviders != NULL ) { FREE_MEM( knownStaticProviders ); } if( protocolInfo11 != NULL ) { FREE_MEM( protocolInfo11 ); } if( registryInfo11 != NULL ) { FREE_MEM( registryInfo11 ); } if( mutexOwned ) { (VOID)ReleaseProtocolCatalogMutex( mutexHandle ); } if( mutexHandle != NULL ) { CloseHandle( mutexHandle ); } TerminateSetup(); *Disposition = disposition; return error; } // MigrateWinsockConfiguration // // Private functions. // DWORD InitializeSetup( VOID ) /*++ Routine Description: Performs any global initialization necessary for this module. Arguments: None. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Load the WinSock 2.0 DLL. // Winsock2DllHandle = LoadLibrary( TEXT("WS2_32.DLL") ); if( Winsock2DllHandle == NULL ) { error = GetLastError(); goto exit; } // // Find the entrypoints. // WSCDeinstallProviderProc = (PVOID)GetProcAddress( Winsock2DllHandle, "WSCDeinstallProvider" ); if( WSCDeinstallProviderProc == NULL ) { error = GetLastError(); goto exit; } WSCInstallProviderProc = (PVOID)GetProcAddress( Winsock2DllHandle, "WSCInstallProvider" ); if( WSCInstallProviderProc == NULL ) { error = GetLastError(); goto exit; } // // Success! // error = NO_ERROR; exit: if( error != NO_ERROR ) { TerminateSetup(); } return error; } // InitializeSetup VOID TerminateSetup( VOID ) /*++ Routine Description: Performs any global cleanup necessary for this module. Arguments: None. Return Value: None. --*/ { if( Winsock2DllHandle != NULL ) { FreeLibrary( Winsock2DllHandle ); Winsock2DllHandle = NULL; } WSCDeinstallProviderProc = NULL; WSCInstallProviderProc = NULL; } // TerminateSetup BOOL IsStringInMultiSz( LPTSTR MultiSz, LPTSTR String ) /*++ Routine Description: Searches a REG_MULTI_SZ value for the specified string. Arguments: MultiSz - The REG_MULTI_SZ value to search. String - The string to search for. Return Value: BOOL - TRUE if the string was found, FALSE otherwise. --*/ { // // Sanity check. // DBG_ASSERT( MultiSz != NULL ); DBG_ASSERT( String != NULL ); DBG_ASSERT( *String != TEXT('\0') ); // // Scan it. // while( *MultiSz != TEXT('\0') ) { if( _tcsicmp( MultiSz, String ) == 0 ) { return TRUE; } MultiSz += _tcslen( MultiSz ) + 1; } return FALSE; } // IsStringInMultiSz DWORD ReadDword( HKEY RootKey, LPTSTR ValueName, LPDWORD Value ) /*++ Routine Description: Reads a DWORD value from the registry. Arguments: RootKey - The root key containing the value to read. ValueName - The name of the value to read. Value - Will receive the read DWORD if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; DWORD valueType; DWORD valueLength; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); DBG_ASSERT( Value != NULL ); // // Read the data. // valueLength = sizeof(*Value); error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, (LPBYTE)Value, &valueLength ); if( error != NO_ERROR ) { goto exit; } // // If the type is not REG_DWORD, then fail the request. // if( valueType != REG_DWORD ) { error = ERROR_INVALID_DATATYPE; goto exit; } // // Success! // exit: return error; } // ReadDword DWORD ReadMultiSz( HKEY RootKey, LPTSTR ValueName, LPTSTR FAR * Value ) /*++ Routine Description: Reads a MULTI_SZ value from the registry. Arguments: RootKey - The root key containing the value to read. ValueName - The name of the value to read. Value - Will receive a pointer to the read MULTI_SZ if successful. Note that it is the caller's responsibility to free this memory. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; LPTSTR valueBuffer; DWORD valueBufferLength; DWORD valueType; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); DBG_ASSERT( Value != NULL ); // // Setup locals so we know how to cleanup on exit. // valueBuffer = NULL; valueBufferLength = 0; // // Determine the value length. // error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, (LPBYTE)valueBuffer, &valueBufferLength ); if( error != NO_ERROR ) { goto exit; } // // Allocate a buffer for the value. // valueBuffer = ALLOC_MEM( valueBufferLength ); if( valueBuffer == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto exit; } // // And now read the data. // error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, (LPBYTE)valueBuffer, &valueBufferLength ); if( error != NO_ERROR ) { goto exit; } // // If the type is not REG_MULTI_SZ, then fail the request. // if( valueType != REG_MULTI_SZ ) { error = ERROR_INVALID_DATATYPE; goto exit; } // // Success! // *Value = valueBuffer; exit: if( error != NO_ERROR && valueBuffer != NULL ) { FREE_MEM( valueBuffer ); } return error; } // ReadMultiSz DWORD ReadString( HKEY RootKey, LPTSTR ValueName, LPTSTR FAR * Value ) /*++ Routine Description: Reads a string value from the registry. Arguments: RootKey - The root key containing the value to read. ValueName - The name of the value to read. Value - Will receive a pointer to the read string if successful. Note that it is the caller's responsibility to free this memory. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; LPTSTR valueBuffer; DWORD valueBufferLength; DWORD valueType; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); DBG_ASSERT( Value != NULL ); // // Setup locals so we know how to cleanup on exit. // valueBuffer = NULL; valueBufferLength = 0; // // Determine the value length. // error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, (LPBYTE)valueBuffer, &valueBufferLength ); if( error != NO_ERROR ) { goto exit; } // // Allocate a buffer for the value. // valueBuffer = ALLOC_MEM( valueBufferLength ); if( valueBuffer == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto exit; } // // And now read the data. // error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, (LPBYTE)valueBuffer, &valueBufferLength ); if( error != NO_ERROR ) { goto exit; } // // If the type is not REG_SZ or REG_EXPAND_SZ, then fail the request. // if( valueType != REG_SZ && valueType != REG_EXPAND_SZ ) { error = ERROR_INVALID_DATATYPE; goto exit; } // // Success! // *Value = valueBuffer; exit: if( error != NO_ERROR && valueBuffer != NULL ) { FREE_MEM( valueBuffer ); } return error; } // ReadString DWORD ReadBinary( HKEY RootKey, LPTSTR ValueName, LPVOID FAR * Value, LPDWORD ValueLength ) /*++ Routine Description: Reads a raw binary value from the registry. Arguments: RootKey - The root key containing the value to read. ValueName - The name of the value to read. Value - Will receive a pointer to the read binary data if successful. Note that it is the caller's responsibility to free this memory. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; LPVOID valueBuffer; DWORD valueBufferLength; DWORD valueType; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); DBG_ASSERT( Value != NULL ); DBG_ASSERT( ValueLength != NULL ); // // Setup locals so we know how to cleanup on exit. // valueBuffer = NULL; valueBufferLength = 0; // // Determine the value length. // error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, valueBuffer, &valueBufferLength ); if( error != NO_ERROR ) { goto exit; } // // Allocate a buffer for the value. // valueBuffer = ALLOC_MEM( valueBufferLength ); if( valueBuffer == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto exit; } // // And now read the data. // error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, valueBuffer, &valueBufferLength ); if( error != NO_ERROR ) { goto exit; } // // If the type is not REG_BINARY, then fail the request. // if( valueType != REG_BINARY ) { error = ERROR_INVALID_DATATYPE; goto exit; } // // Success! // *Value = valueBuffer; *ValueLength = valueBufferLength; exit: if( error != NO_ERROR && valueBuffer != NULL ) { FREE_MEM( valueBuffer ); } return error; } // ReadBinary DWORD ReadGuid( HKEY RootKey, LPTSTR ValueName, LPGUID Value ) /*++ Routine Description: Reads a GUID value from the registry. Arguments: RootKey - The root key containing the value to read. ValueName - The name of the value to read. Value - Will receive the read GUID if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; DWORD valueType; DWORD valueLength; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); DBG_ASSERT( Value != NULL ); // // Read the data. // valueLength = sizeof(*Value); error = RegQueryValueEx( RootKey, ValueName, NULL, &valueType, (LPBYTE)Value, &valueLength ); if( error != NO_ERROR ) { goto exit; } // // If the type is not REG_BINARY, then fail the request. // if( valueType != REG_BINARY ) { error = ERROR_INVALID_DATATYPE; goto exit; } // // Success! // exit: return error; } // ReadGuid DWORD WriteDword( HKEY RootKey, LPTSTR ValueName, DWORD Value ) /*++ Routine Description: Writes a DWORD value to the registry. Arguments: RootKey - The root key containing the value to write. ValueName - The name of the value to write. Value - The DWORD to write. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); // // Write it. // error = RegSetValueEx( RootKey, ValueName, 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value) ); return error; } // WriteDword DWORD WriteMultiSz( HKEY RootKey, LPTSTR ValueName, LPTSTR Value ) /*++ Routine Description: Writes a MULTI_SZ value to the registry. Arguments: RootKey - The root key containing the value to write. ValueName - The name of the value to write. Value - Points to the MULTI_SZ to write. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; LPTSTR valueScan; DWORD scanLength; DWORD valueLength; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); // // Compute the length of the MULTI_SZ, including the final // terminating '\0'. // valueLength = 0; if( Value == NULL ) { Value = TEXT(""); } else { valueScan = Value; while( *valueScan != TEXT('\0') ) { scanLength = (DWORD)_tcslen( valueScan ) + 1; valueLength += scanLength; valueScan += scanLength; } } valueLength++; // // Write it. // error = RegSetValueEx( RootKey, ValueName, 0, REG_MULTI_SZ, (LPBYTE)Value, valueLength * sizeof(TCHAR) ); return error; } // WriteMultiSz DWORD WriteBinary( HKEY RootKey, LPTSTR ValueName, LPVOID Value, DWORD ValueLength ) /*++ Routine Description: Writes a raw binary value to the registry. Arguments: RootKey - The root key containing the value to write. ValueName - The name of the value to write. Value - Points to the raw binary data to write. ValueLength - The length (in BYTEs) of the data to write. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); DBG_ASSERT( Value != NULL ); // // Write it. // error = RegSetValueEx( RootKey, ValueName, 0, REG_BINARY, (LPBYTE)Value, ValueLength ); return error; } // WriteBinary DWORD WriteString( HKEY RootKey, LPTSTR ValueName, LPTSTR Value ) /*++ Routine Description: Writes a string value to the registry. Arguments: RootKey - The root key containing the value to write. ValueName - The name of the value to write. Value - Points to the string to write. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); DBG_ASSERT( Value != NULL ); // // Write it. // error = RegSetValueEx( RootKey, ValueName, 0, REG_SZ, (LPBYTE)Value, (DWORD)_tcslen( Value ) + sizeof(TCHAR) ); return error; } // WriteString DWORD WriteGuid( HKEY RootKey, LPTSTR ValueName, LPGUID Value ) /*++ Routine Description: Writes a GUID value to the registry. Arguments: RootKey - The root key containing the value to write. ValueName - The name of the value to write. Value - The GUID to write. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( ValueName != NULL ); // // Write it. // error = RegSetValueEx( RootKey, ValueName, 0, REG_BINARY, (LPBYTE)Value, sizeof(*Value) ); return error; } // WriteGuid DWORD OpenServicesRoot( PHKEY ServicesKey ) /*++ Routine Description: Opens the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services registry key. Arguments: ServicesKey - Will receive a handle to the registry key if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( ServicesKey != NULL ); // // Open the key. // IF_DEBUG_SETUP { DBG_PRINT(( "OpenServicesRoot(): opening %lx\\%s\n", HKEY_LOCAL_MACHINE, SERVICES_KEY )); } error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, SERVICES_KEY, 0, KEY_ALL_ACCESS, ServicesKey ); if( error != NO_ERROR ) { goto exit; } IF_DEBUG_SETUP { DBG_PRINT(( "OpenServicesRoot(): handle %lx\n", *ServicesKey )); } // // Success! // exit: return error; } // OpenServicesRoot DWORD OpenWinsockRoot( HKEY ServicesKey, PHKEY WinsockKey ) /*++ Routine Description: Opens the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\WinSock registry key. Arguments: ServicesKey - The handle to the ...\Services key. WinsockKey - Will receive a handle to the WinSock key if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( ServicesKey != NULL ); DBG_ASSERT( WinsockKey != NULL ); // // Open the WinSock key. // IF_DEBUG_SETUP { DBG_PRINT(( "OpenWinsockRoot(): opening %lx\\%s\n", ServicesKey, WINSOCK_SUBKEY )); } error = RegOpenKeyEx( ServicesKey, WINSOCK_SUBKEY, 0, KEY_ALL_ACCESS, WinsockKey ); if( error != NO_ERROR ) { goto exit; } IF_DEBUG_SETUP { DBG_PRINT(( "OpenWinsockRoot(): handle %lx\n", *WinsockKey )); } // // Success! // exit: return error; } // OpenWinsockRoot DWORD OpenSetupMigrationRoot( HKEY WinsockKey, PHKEY MigrationKey, PHKEY ProvidersKey, PHKEY WellKnownGuidsKey ) /*++ Routine Description: Opens the ...\WinSock\Setup Migration, ...\Setup Migration\Providers, and ...\Setup Migration\Well Known Guids registry keys. If the Setup Migration key is not present, it is created and initialized with default values. If it contains an invalid setup version number, the entire Setup Migration tree is deleted and recreated from scratch with default values. Arguments: WinsockKey - The handle to the ...\WinSock key. MigrationKey - Will receive a handle to the Setup Migration key if successful. ProvidersKey - Will receive a handle to the Setup Migration\Providers key if successful. WellKnownGuidsKey - Will receive a handle to the Setup Migration\Well Known Guids key if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HKEY migrationKey; HKEY providersKey; HKEY wellKnownGuidsKey; DWORD setupVersion; // // Sanity check. // DBG_ASSERT( WinsockKey != NULL ); DBG_ASSERT( MigrationKey != NULL ); DBG_ASSERT( ProvidersKey != NULL ); DBG_ASSERT( WellKnownGuidsKey != NULL ); // // Setup locals so we know how to cleanup on exit. // migrationKey = NULL; providersKey = NULL; wellKnownGuidsKey = NULL; // // Open the migration key. // IF_DEBUG_SETUP { DBG_PRINT(( "OpenSetupMigrationRoot(): opening %lx\\%s\n", WinsockKey, MIGRATION_SUBKEY )); } error = RegOpenKeyEx( WinsockKey, MIGRATION_SUBKEY, 0, KEY_ALL_ACCESS, &migrationKey ); if( error != NO_ERROR && error != ERROR_FILE_NOT_FOUND ) { goto exit; } IF_DEBUG_SETUP { if( error == NO_ERROR ) { DBG_PRINT(( "OpenSetupMigrationRoot(): handle %lx\n", migrationKey )); } else { DBG_PRINT(( "OpenSetupMigrationRoot(): not found\n" )); } } // // Open the providers key. // if( error == NO_ERROR ) { IF_DEBUG_SETUP { DBG_PRINT(( "OpenSetupMigrationRoot(): opening %lx\\%s\n", migrationKey, PROVIDERS_SUBKEY )); } error = RegOpenKeyEx( migrationKey, PROVIDERS_SUBKEY, 0, KEY_ALL_ACCESS, &providersKey ); if( error != NO_ERROR && error != ERROR_FILE_NOT_FOUND ) { goto exit; } IF_DEBUG_SETUP { if( error == NO_ERROR ) { DBG_PRINT(( "OpenSetupMigrationRoot(): handle %lx\n", providersKey )); } else { DBG_PRINT(( "OpenSetupMigrationRoot(): not found\n" )); } } } // // Open the well known guids key. // if( error == NO_ERROR ) { IF_DEBUG_SETUP { DBG_PRINT(( "OpenSetupMigrationRoot(): opening %lx\\%s\n", migrationKey, WELL_KNOWN_GUIDS_SUBKEY )); } error = RegOpenKeyEx( migrationKey, WELL_KNOWN_GUIDS_SUBKEY, 0, KEY_ALL_ACCESS, &wellKnownGuidsKey ); if( error != NO_ERROR && error != ERROR_FILE_NOT_FOUND ) { goto exit; } IF_DEBUG_SETUP { if( error == NO_ERROR ) { DBG_PRINT(( "OpenSetupMigrationRoot(): handle %lx\n", wellKnownGuidsKey )); } else { DBG_PRINT(( "OpenSetupMigrationRoot(): not found\n" )); } } } // // If we managed to open the migration key, then try to read the // version number. If we can read it, and it matches our version // number, then all is well. Otherwise (either we can't read it or // it doesn't match) then close the migration key, blow away the // current migration registry tree, and start from scratch. // if( error == NO_ERROR ) { error = ReadDword( migrationKey, SETUP_VERSION_VALUE, &setupVersion ); if( error == NO_ERROR ) { IF_DEBUG_SETUP { DBG_PRINT(( "OpenSetupMigrationRoot(): setup version %lu\n", setupVersion )); } if( setupVersion == WINSOCK_SETUP_VERSION ) { // // Good news. // *MigrationKey = migrationKey; *ProvidersKey = providersKey; *WellKnownGuidsKey = wellKnownGuidsKey; goto exit; } } } // // We'll only make it here if either a) the migration key could not // be opened, b) the migration key was opened, but the providers key // could not be opened, c) the migration key was opened, but the well // known guids key could not be opened, d) the migration key was opened, // but the setup version number could not be read, or e) the version // number was read but did not match our version number. We'll close the // registry keys if we managed to open then, blow away the existing // migration registry tree, and create a new one from scratch. // IF_DEBUG_SETUP { DBG_PRINT(( "OpenSetupMigrationRoot(): starting over from scratch\n" )); } if( migrationKey != NULL ) { (VOID)RegCloseKey( migrationKey ); migrationKey = NULL; } if( providersKey != NULL ) { // // Remove all installed providers. // error = RemoveAllInstalledProviders( providersKey ); if( error != NO_ERROR ) { goto exit; } (VOID)RegCloseKey( providersKey ); providersKey = NULL; } if( wellKnownGuidsKey != NULL ) { (VOID)RegCloseKey( wellKnownGuidsKey ); wellKnownGuidsKey = NULL; } error = RecursivelyDeleteRegistryTree( WinsockKey, MIGRATION_SUBKEY ); if( error != NO_ERROR ) { goto exit; } error = CreateDefaultSetupMigrationTree( WinsockKey, &migrationKey, &providersKey, &wellKnownGuidsKey ); if( error != NO_ERROR ) { goto exit; } // // Success! // *MigrationKey = migrationKey; *ProvidersKey = providersKey; *WellKnownGuidsKey = wellKnownGuidsKey; exit: if( error != NO_ERROR ) { if( migrationKey != NULL ) { (VOID)RegCloseKey( migrationKey ); } if( providersKey != NULL ) { (VOID)RegCloseKey( providersKey ); } if( wellKnownGuidsKey != NULL ) { (VOID)RegCloseKey( wellKnownGuidsKey ); } *MigrationKey = NULL; *ProvidersKey = NULL; *WellKnownGuidsKey = NULL; } return error; } // OpenSetupMigrationRoot DWORD ReadNewProviderList( HKEY WinsockKey, LPTSTR FAR * NewProviderList ) /*++ Routine Description: Reads the list of current WinSock 1.1 providers (helper DLLs). Arguments: WinsockKey - A handle to the ...\Services\WinSock registry key. NewProviderList - Will receive a pointer to the MULTI_SZ for the provider list. Note that it is the caller's responsibility to free this memory. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HKEY parametersKey; // // Sanity check. // DBG_ASSERT( WinsockKey != NULL ); DBG_ASSERT( NewProviderList != NULL ); // // Setup locals so we know how to cleanup on exit. // parametersKey = NULL; // // Open the Parameters key. // IF_DEBUG_SETUP { DBG_PRINT(( "ReadNewProviderList(): opening %lx\\%s\n", WinsockKey, PARAMETERS_SUBKEY )); } error = RegOpenKeyEx( WinsockKey, PARAMETERS_SUBKEY, 0, KEY_ALL_ACCESS, ¶metersKey ); if( error != NO_ERROR ) { goto exit; } IF_DEBUG_SETUP { DBG_PRINT(( "ReadNewProviderList(): handle %lx\n", parametersKey )); } // // Read the new provider list. // IF_DEBUG_SETUP { DBG_PRINT(( "ReadNewProviderList(): reading %lx\\%s\n", parametersKey, TRANSPORTS_VALUE )); } error = ReadMultiSz( parametersKey, TRANSPORTS_VALUE, NewProviderList ); if( error != NO_ERROR ) { goto exit; } // // Success! // exit: if( parametersKey != NULL ) { (VOID)RegCloseKey( parametersKey ); } return error; } // ReadNewProviderList DWORD ReadOldProviderList( HKEY MigrationKey, LPTSTR FAR * OldProviderList ) /*++ Routine Description: Reads the list of currently migrated providers. Arguments: MigrationKey - A handle to the ...\WinSock\Setup Migration registry key. OldProviderList - Will receive a pointer to the MULTI_SZ for the currently migrated providers. Note that it is the caller's responsibility to free this memory. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( MigrationKey != NULL ); DBG_ASSERT( OldProviderList != NULL ); // // Read the old provider list. // error = ReadMultiSz( MigrationKey, PROVIDER_LIST_VALUE, OldProviderList ); return error; } // ReadOldProviderList DWORD ReadKnownStaticProviderList( HKEY MigrationKey, LPTSTR FAR * KnownStaticProviderList ) /*++ Routine Description: Reads the list of known static provider names. Arguments: MigrationKey - A handle to the ...\WinSock\Setup Migration registry key. KnownStaticProviderList - Will receive a pointer to the MULTI_SZ for the known static providers. Note that it is the caller's responsibility to free this memory. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; // // Sanity check. // DBG_ASSERT( MigrationKey != NULL ); DBG_ASSERT( KnownStaticProviderList != NULL ); // // Read the known static provider list. // error = ReadMultiSz( MigrationKey, KNOWN_STATIC_VALUE, KnownStaticProviderList ); return error; } // ReadKnownStaticProviderList DWORD ReadProviderId( HKEY ProvidersKey, LPTSTR ProviderName, LPGUID ProviderId ) /*++ Routine Description: Reads a migrated provider's WinSock 2.0 provider ID from the registry. Arguments: ProvidersKey - A handle to the ...\Setup Migration\Providers registry key. ProviderName - The name of the provider whose ID is to be queried. ProviderId - Will receive the provider's ID value. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HKEY providerKey; // // Sanity check. // DBG_ASSERT( ProvidersKey != NULL ); DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( ProviderId != NULL ); // // Setup locals so we know how to cleanup on exit. // providerKey = NULL; // // Open the provider // error = RegOpenKeyEx( ProvidersKey, ProviderName, 0, KEY_ALL_ACCESS, &providerKey ); if( error != NO_ERROR ) { goto exit; } // // Read the provider ID. // error = ReadGuid( providerKey, WINSOCK_2_0_ID_VALUE, ProviderId ); if( error != NO_ERROR ) { goto exit; } // // Success! // exit: if( providerKey != NULL ) { (VOID)RegCloseKey( providerKey ); } return error; } // ReadProviderId DWORD CreateDefaultSetupMigrationTree( HKEY WinsockKey, PHKEY MigrationKey, PHKEY ProvidersKey, PHKEY WellKnownGuidsKey ) /*++ Routine Description: Creates the default ...\WinSock\Setup Migration registry tree, using default values. Arguments: WinsockKey - A handle to the ...\Services\WinSock registry key. MigratonKey - Will receive a handle to the ...\WinSock\Setup Migration registry key if successful. ProvidersKey - Will receive a handle to the ...\Setup Migration\Providers registry key if successful. WellKnownGuidsKey - Will receive a handle to the Setup Migration\Well Known Guids key if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; DWORD disposition; DWORD i; HKEY migrationKey; HKEY providersKey; HKEY wellKnownGuidsKey; // // Sanity check. // DBG_ASSERT( WinsockKey != NULL ); DBG_ASSERT( MigrationKey != NULL ); DBG_ASSERT( ProvidersKey != NULL ); DBG_ASSERT( WellKnownGuidsKey != NULL ); // // Setup locals so we know how to cleanup on exit. // migrationKey = NULL; providersKey = NULL; wellKnownGuidsKey = NULL; // // Create the Setup Migration key. // error = RegCreateKeyEx( WinsockKey, MIGRATION_SUBKEY, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &migrationKey, &disposition ); if( error != NO_ERROR ) { goto exit; } DBG_ASSERT( disposition == REG_CREATED_NEW_KEY ); // // Create the default values. // error = WriteDword( migrationKey, SETUP_VERSION_VALUE, DefaultSetupVersion ); if( error != NO_ERROR ) { goto exit; } error = WriteMultiSz( migrationKey, PROVIDER_LIST_VALUE, DefaultProviderList ); if( error != NO_ERROR ) { goto exit; } error = WriteMultiSz( migrationKey, KNOWN_STATIC_VALUE, DefaultKnownStaticProviders ); if( error != NO_ERROR ) { goto exit; } // // Create the Providers key. // error = RegCreateKeyEx( migrationKey, PROVIDERS_SUBKEY, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &providersKey, &disposition ); if( error != NO_ERROR ) { goto exit; } DBG_ASSERT( disposition == REG_CREATED_NEW_KEY ); // // Create the Well Known Guids key. // error = RegCreateKeyEx( migrationKey, WELL_KNOWN_GUIDS_SUBKEY, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &wellKnownGuidsKey, &disposition ); if( error != NO_ERROR ) { goto exit; } DBG_ASSERT( disposition == REG_CREATED_NEW_KEY ); // // Create the default values. // for( i = 0 ; i < NUM_DEFAULT_WELL_KNOWN_GUIDS ; i++ ) { error = WriteGuid( wellKnownGuidsKey, DefaultWellKnownGuids[i].Name, &DefaultWellKnownGuids[i].Guid ); if( error != NO_ERROR ) { goto exit; } } // // Success! // *MigrationKey = migrationKey; *ProvidersKey = providersKey; *WellKnownGuidsKey = wellKnownGuidsKey; exit: if( error != NO_ERROR ) { if( migrationKey != NULL ) { (VOID)RegCloseKey( migrationKey ); } if( providersKey != NULL ) { (VOID)RegCloseKey( providersKey ); } if( wellKnownGuidsKey != NULL ) { (VOID)RegCloseKey( wellKnownGuidsKey ); } *MigrationKey = NULL; *ProvidersKey = NULL; *WellKnownGuidsKey = NULL; } return error; } // CreateDefaultSetupMigrationTree DWORD RecursivelyDeleteRegistryTree( HKEY RootKey, LPTSTR TargetKeyName ) /*++ Routine Description: Deletes the specified registry key and all subkeys. Arguments: RootKey - A handle to the registry key containing the key to delete. TargetKeyName - The name of the key to delete. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HKEY targetKey; FILETIME lastWriteTime; DWORD subkeyIndex; DWORD subkeyNameLength; TCHAR subkeyName[MAX_REGISTRY_NAME]; // // Sanity check. // DBG_ASSERT( RootKey != NULL ); DBG_ASSERT( TargetKeyName != NULL ); // // Setup locals so we know how to cleanup on exit. // targetKey = NULL; // // Open the target key. // error = RegOpenKeyEx( RootKey, TargetKeyName, 0, KEY_ALL_ACCESS, &targetKey ); if( error == ERROR_FILE_NOT_FOUND ) { error = NO_ERROR; goto exit; } else if( error != NO_ERROR ) { goto exit; } // // Enumerate & recursively delete the subkeys. // subkeyIndex = 0; for( ; ; ) { subkeyNameLength = sizeof(subkeyName); error = RegEnumKeyEx( targetKey, subkeyIndex, subkeyName, &subkeyNameLength, NULL, NULL, NULL, &lastWriteTime ); if( error != NO_ERROR ) { break; } error = RecursivelyDeleteRegistryTree( targetKey, subkeyName ); if( error != NO_ERROR ) { break; } // // Note that since we just totally blew away the current subkey // in the enumeration, we do not want to increment the subkey // index. // } if( error != ERROR_NO_MORE_ITEMS ) { goto exit; } // // Close the target key. // error = RegCloseKey( targetKey ); targetKey = NULL; if( error != NO_ERROR ) { goto exit; } // // Delete the target key. // error = RegDeleteKey( RootKey, TargetKeyName ); if( error != NO_ERROR ) { goto exit; } // // Success! // exit: if( targetKey != NULL ) { (VOID)RegCloseKey( targetKey ); } return error; } // RecursivelyDeleteRegistryTree DWORD RemoveProviderByName( HKEY ProvidersKey, LPTSTR ProviderName ) /*++ Routine Description: Removes the specified provider by deinstalling it from the WinSock 2.0 configuration database and deleting its migration registry tree. Arguments: ProvidersKey - A handle to the ...\Setup Migration\Providers registry key. ProviderName - The name of the provider to remove. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; INT result; GUID providerId; // // Sanity check. // DBG_ASSERT( ProvidersKey != NULL ); DBG_ASSERT( ProviderName != NULL ); // // Get the provider's WinSock 2.0 ID code. // error = ReadProviderId( ProvidersKey, ProviderName, &providerId ); if( error == NO_ERROR ) { // // Uninstall it from WinSock 2.0. // result = (WSCDeinstallProviderProc)( &providerId, (LPINT)&error ); if( result == SOCKET_ERROR ) { if( error == WSAEFAULT ) { // // WSCDeinstallProvider returns WSAEFAULT if it could // not find the provider. We'll just ignore this and // press on regardless. // error = NO_ERROR; } else { DBG_ASSERT( error != NO_ERROR ); goto exit; } } } // // Nuke its registry tree. // error = RecursivelyDeleteRegistryTree( ProvidersKey, ProviderName ); if( error != NO_ERROR ) { goto exit; } // // Success! // exit: return error; } // RemoveProviderByName DWORD ReadProtocolDataFromRegistry( HKEY ProvidersKey, LPTSTR ProviderName, LPPROTOCOL_INFO FAR * RegistryInfo11, LPDWORD RegistryInfo11Length ) /*++ Routine Description: Reads the WinSock 1.1 protocol data stored in the provider's migration registry tree. Arguments: ProvidersKey - A handle to the ...\Setup Migration\Providers registry key. ProviderName - The name of the provider to remove. RegistryInfo11 - Will receive a pointer to the provider's protocol information as read from the registry. Note that it is the caller's responsibility to free this memory. RegistryInfo11Length - Will receive the length (in BYTEs) of the provider's protocol information. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HKEY providerKey; LPVOID registryData; DWORD registryDataLength; // // Sanity check. // DBG_ASSERT( ProvidersKey != NULL ); DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( RegistryInfo11 != NULL ); DBG_ASSERT( RegistryInfo11Length != NULL ); // // Setup locals so we know how to cleanup on exit. // providerKey = NULL; registryData = NULL; // // Open the provider // error = RegOpenKeyEx( ProvidersKey, ProviderName, 0, KEY_ALL_ACCESS, &providerKey ); if( error != NO_ERROR ) { goto exit; } // // Read the provider data. // error = ReadBinary( providerKey, WINSOCK_1_1_DATA_VALUE, ®istryData, ®istryDataLength ); if( error != NO_ERROR ) { goto exit; } // // Success! // *RegistryInfo11 = registryData; *RegistryInfo11Length = registryDataLength; exit: if( providerKey != NULL ) { (VOID)RegCloseKey( providerKey ); } if( error != NO_ERROR ) { if( registryData != NULL ) { FREE_MEM( registryData ); } *RegistryInfo11 = NULL; *RegistryInfo11Length = 0; } return error; } // ReadProtocolDataFromRegistry DWORD ReadProtocolDataFromProvider( HKEY ServicesKey, LPTSTR ProviderName, LPTSTR ProviderDllPath, LPPROTOCOL_INFO FAR * ProtocolInfo11, LPDWORD ProtocolInfo11Length, LPDWORD ProtocolInfo11Entries ) /*++ Routine Description: Reads the WinSock 1.1 protocol data stored from the provider's helper DLL. This is done by loading the helper DLL and invoking it's WSHEnumProtocols() entrypoint. Arguments: ServicesKey - A handle to the ...\CurrentControlSet\Services registry key. ProviderName - The name of the provider to remove. ProviderDllPath - Will receive the fully expanded path to the provider's helper DLL. This is assumed to point to an array of TCHARs at least MAX_PATH in length. ProtocolInfo11 - Will receive a pointer to the provider's protocol information as returned by WSHEnumProtocols(). Note that it is the caller's responsibility to free this memory. ProtocolInfo11Length - Will receive the length (in BYTEs) of the provider's protocol information. ProtocolInfo11Entries - Will receive the number of entries in the provider's protocol information. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. Notes: In general, this routine is overly tolerant of errors regarding registry layout. This keeps the migration process running, even if there is garbage in the registry. --*/ { DWORD error; HKEY serviceKey; HKEY parametersKey; LPTSTR helperDllPath; DWORD expandedLength; HMODULE helperDllHandle; PWSH_ENUM_PROTOCOLS enumProtocols; INT numEntries; LPPROTOCOL_INFO protocolInfo11; DWORD protocolInfo11Length; LPDWORD protocolList; INT i; LPWSTR unicodeProviderName; #if !defined(UNICODE) WCHAR unicodeProviderNameBuffer[MAX_PATH]; #endif // // Sanity check. // DBG_ASSERT( ServicesKey != NULL ); DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( ProviderDllPath != NULL ); DBG_ASSERT( ProtocolInfo11 != NULL ); DBG_ASSERT( ProtocolInfo11Length != NULL ); DBG_ASSERT( ProtocolInfo11Entries != NULL ); // // Setup locals so we know how to cleanup on exit. // serviceKey = NULL; parametersKey = NULL; protocolList = NULL; helperDllPath = NULL; helperDllHandle = NULL; numEntries = 0; *ProtocolInfo11 = NULL; *ProtocolInfo11Length = 0; *ProtocolInfo11Entries = 0; #if defined(UNICODE) unicodeProviderName = ProviderName; #else // // Map the provider name to UNICODE so we can pass it down. // wsprintfW( unicodeProviderNameBuffer, L"%hs", ProviderName ); unicodeProviderName = unicodeProviderNameBuffer; #endif // // Open the service key. // error = RegOpenKeyEx( ServicesKey, ProviderName, 0, KEY_ALL_ACCESS, &serviceKey ); if( error != NO_ERROR ) { error = NO_ERROR; // Press on regardless. goto exit; } // // Open the parameters key. // error = RegOpenKeyEx( serviceKey, SERVICE_PARAMS_SUBKEY, 0, KEY_ALL_ACCESS, ¶metersKey ); if( error != NO_ERROR ) { error = NO_ERROR; // Press on regardless. goto exit; } // // Read the supported protocols. // // HACK: Skip for NetBIOS, as its helper DLL will fail if any // protocols are passed in. // if( _tcsicmp( ProviderName, TEXT("NetBIOS") ) != 0 ) { error = ReadProviderSupportedProtocolsFromRegistry( parametersKey, &protocolList ); if( error != NO_ERROR ) { error = NO_ERROR; // Press on regardless. goto exit; } } // // Read the Helper DLL path. // error = ReadString( parametersKey, HELPER_DLL_NAME_VALUE, &helperDllPath ); if( error != NO_ERROR ) { error = NO_ERROR; // Press on regardless. goto exit; } // // Expand any embedded environment strings. // expandedLength = ExpandEnvironmentStrings( helperDllPath, ProviderDllPath, MAX_PATH ); if( expandedLength > MAX_PATH ) { error = ERROR_NOT_ENOUGH_MEMORY; goto exit; } if( expandedLength == 0 ) { error = GetLastError(); goto exit; } // // Load the DLL and find the entrypoint. // helperDllHandle = LoadLibrary( ProviderDllPath ); if( helperDllHandle == NULL ) { DBG_ASSERT( error == NO_ERROR ); goto exit; } enumProtocols = (PVOID)GetProcAddress( helperDllHandle, "WSHEnumProtocols" ); if( enumProtocols == NULL ) { DBG_ASSERT( error == NO_ERROR ); goto exit; } // // Determine the required buffer size. // protocolInfo11 = NULL; protocolInfo11Length = 0; try { numEntries = enumProtocols( protocolList, (LPTSTR)unicodeProviderName, protocolInfo11, &protocolInfo11Length ); } except( EXCEPTION_EXECUTE_HANDLER ) { numEntries = 0; DBG_PRINT(( "%s!WSHEnumProtocols raised exception %08lX, skipping\n", helperDllPath, GetExceptionCode() )); } if( numEntries == 0 ) { DBG_ASSERT( error == NO_ERROR ); goto exit; } DBG_ASSERT( numEntries == -1 ); DBG_ASSERT( protocolInfo11Length > 0 ); // // Allocate a buffer. // protocolInfo11 = ALLOC_MEM( protocolInfo11Length ); if( protocolInfo11 == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto exit; } RtlZeroMemory( protocolInfo11, protocolInfo11Length ); // // And now really read the data. // try { numEntries = enumProtocols( protocolList, (LPTSTR)unicodeProviderName, protocolInfo11, &protocolInfo11Length ); } except( EXCEPTION_EXECUTE_HANDLER ) { numEntries = 0; DBG_PRINT(( "%s!WSHEnumProtocols raised exception %08lX, skipping\n", helperDllPath, GetExceptionCode() )); } if( numEntries == -1 ) { error = ERROR_GEN_FAILURE; goto exit; } if( numEntries == 0 ) { DBG_ASSERT( error == NO_ERROR ); DBG_ASSERT( protocolInfo11 != NULL ); FREE_MEM( protocolInfo11 ); protocolInfo11 = NULL; goto exit; } #if !defined(UNICODE) // // Map the UNICODE strings to ANSI. // for( i = 0 ; i < numEntries ; i++ ) { wsprintfA( protocolInfo11[i].lpProtocol, "%ls", protocolInfo11[i].lpProtocol ); } #endif // // Success! // *ProtocolInfo11 = protocolInfo11; *ProtocolInfo11Length = protocolInfo11Length; *ProtocolInfo11Entries = (DWORD)numEntries; exit: if( serviceKey != NULL ) { (VOID)RegCloseKey( serviceKey ); } if( parametersKey != NULL ) { (VOID)RegCloseKey( parametersKey ); } if( protocolList != NULL ) { FREE_MEM( protocolList ); } if( helperDllPath != NULL ) { FREE_MEM( helperDllPath ); } if( helperDllHandle != NULL ) { FreeLibrary( helperDllHandle ); } return error; } // ReadProtocolDataFromProvider DWORD ReadProviderSupportedProtocolsFromRegistry( HKEY ParametersKey, LPDWORD FAR * ProtocolList ) /*++ Routine Description: Reads a list of supported protocol values from the WinSock 1.1 mapping data stored in the registry. Arguments: ParametersKey - A handle to the ...\{provider}\Parameters\WinSock registry key. ProtocolList - Will receive a pointer to an array of DWORD values, one for each supported protocol. Note that this list will be NULL if there are no non-zero protocols in the provider's mapping data. This is OK, as some providers (such as NetBIOS) are stored this way. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; PWINSOCK_MAPPING mapping; DWORD mappingLength; DWORD mappingRows; LPDWORD protocolList; DWORD protocolCount; DWORD currentProtocol; DWORD i, j; // // Sanity check. // DBG_ASSERT( ParametersKey != NULL ); DBG_ASSERT( ProtocolList != NULL ); // // Setup locals so we know how to cleanup on exit. // mapping = NULL; // // Read the mapping data. // error = ReadBinary( ParametersKey, MAPPING_VALUE, &mapping, &mappingLength ); if( error != NO_ERROR ) { goto exit; } mappingRows = mapping->Rows; if( mappingLength < sizeof(*mapping) || mappingRows == 0 || mapping->Columns != 3 ) { error = ERROR_GEN_FAILURE; goto exit; } // // Build the list of unique supported protocols. We'll do this in // place on top of the raw mapping data. This is a little wasteful // in terms of space, but the memory is only allocated temporarily, // and it avoids an additional allocation. // protocolList = (LPDWORD)mapping; protocolCount = 0; for( i = 0 ; i < mappingRows ; i++ ) { currentProtocol = mapping->Mapping[i].Protocol; if( currentProtocol == 0 ) { continue; } for( j = 0 ; j < protocolCount ; j++ ) { if( protocolList[j] == currentProtocol ) { break; } } if( j >= protocolCount ) { protocolList[protocolCount++] = currentProtocol; } } protocolList[protocolCount] = 0; // // If there were no non-zero providers in the list, then just // return NULL. This is OK. // if( protocolCount == 0 ) { FREE_MEM( protocolList ); protocolList = NULL; } // // Success! // *ProtocolList = protocolList; exit: if( error != NO_ERROR && mapping != NULL ) { FREE_MEM( mapping ); } return error; } // ReadProviderSupportedProtocolsFromRegistry VOID MapProtocolInfoToSelfRelative( LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Entries ) /*++ Routine Description: Maps the embedded pointers in the WinSock 1.1 protocol information from absolute form to self-relative form. Arguments: ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information. ProtocolInfo11Entries - The number of entries in the protocol information. Return Value: None. --*/ { LPPROTOCOL_INFO protocolInfo11Start; // // Sanity check. // DBG_ASSERT( ProtocolInfo11 != NULL ); DBG_ASSERT( ProtocolInfo11Entries > 0 ); // // Do it. // protocolInfo11Start = ProtocolInfo11; while( ProtocolInfo11Entries-- > 0 ) { DBG_ASSERT( (DWORD)ProtocolInfo11->lpProtocol > (DWORD)protocolInfo11Start ); ProtocolInfo11->lpProtocol = (LPVOID)( (DWORD)ProtocolInfo11->lpProtocol - (DWORD)protocolInfo11Start ); ProtocolInfo11++; } } // MapProtocolInfoToSelfRelative VOID MapProtocolInfoToAbsolute( LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Entries ) /*++ Routine Description: Maps the embedded pointers in the WinSock 1.1 protocol information from self-relative form to absolute form. Arguments: ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information. ProtocolInfo11Entries - The number of entries in the protocol information. Return Value: None. --*/ { LPPROTOCOL_INFO protocolInfo11Start; // // Sanity check. // DBG_ASSERT( ProtocolInfo11 != NULL ); DBG_ASSERT( ProtocolInfo11Entries > 0 ); // // Do it. // protocolInfo11Start = ProtocolInfo11; while( ProtocolInfo11Entries-- > 0 ) { ProtocolInfo11->lpProtocol = (LPVOID)( (DWORD)ProtocolInfo11->lpProtocol + (DWORD)protocolInfo11Start ); ProtocolInfo11++; } } // MapProtocolInfoToAbsolute DWORD BuildWinsock2ProtocolList( LPTSTR ProviderName, LPTSTR ProviderDllPath, LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Entries, LPWSAPROTOCOL_INFO FAR * ProtocolInfo2, LPDWORD ProtocolInfo2Entries ) /*++ Routine Description: Scans WinSock 1.1 protocol information and creates corresponding WinSock 2.0 protocol information. Arguments: ProviderName - The name of the current provider. ProviderDllPath - The fully expanded path to the provider's helper DLL. ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information. ProtocolInfo11Entries - The number of entries in the protocol information. ProtocolInfo2 - Will receive a pointer to the WinSock 2.0 protocol information if successful. Note that it is the caller's responsibility to free this memory. ProtocolInfo2Entries - Will receive the number of entries in the WinSock 2.0 protocol information. Note that this may be greater than ProtocolInfo11Entries. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; LPWSAPROTOCOL_INFO protocolInfo2; LPWSAPROTOCOL_INFO tmpProtocolInfo2; DWORD protocolInfo2Entries; DWORD protocolInfo2Length; DWORD i, j; INT addressFamily; INT socketType; INT protocol; HMODULE helperDllHandle; PWSH_GET_WSAPROTOCOL_INFO getWSAProtocolInfo; // // Sanity check. // DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( ProviderDllPath != NULL ); DBG_ASSERT( ProtocolInfo11 != NULL ); DBG_ASSERT( ProtocolInfo11Entries > 0 ); DBG_ASSERT( ProtocolInfo2 != NULL ); DBG_ASSERT( ProtocolInfo2Entries != NULL ); // // Setup locals so we know how to cleanup on exit. // error = NO_ERROR; protocolInfo2 = NULL; helperDllHandle = NULL; // // Determine if this helper DLL supports the new WSHGetWSAProtocolInfo // entrypoint. If so, we'll just use it to build the WinSock 2.0 // protocol info. If not, we'll build it ourselves using the WinSock 1.1 // data. // helperDllHandle = LoadLibrary( ProviderDllPath ); if( helperDllHandle != NULL ) { getWSAProtocolInfo = (PVOID)GetProcAddress( helperDllHandle, "WSHGetWSAProtocolInfo" ); if( getWSAProtocolInfo != NULL ) { IF_DEBUG_SETUP { DBG_PRINT(( "Calling %ls!WSHGetWSAProtocolInfo\n", ProviderDllPath )); } // // The new entrypoint is exported by the helper DLL. Call // it to get the WSAPROTOCOL_INFO supported by this provider. // tmpProtocolInfo2 = NULL; protocolInfo2Entries = 0; try { error = (DWORD)getWSAProtocolInfo( ProviderName, &tmpProtocolInfo2, &protocolInfo2Entries ); } except( EXCEPTION_EXECUTE_HANDLER ) { error = GetExceptionCode(); } if( error == NO_ERROR && tmpProtocolInfo2 != NULL && protocolInfo2Entries > 0 ) { // // We got the data. Allocate a new buffer for the data // and make a copy of it. If the allocation fails, we're // screwed. // protocolInfo2Length = protocolInfo2Entries * sizeof(WSAPROTOCOL_INFO); protocolInfo2 = ALLOC_MEM( protocolInfo2Length ); if( protocolInfo2 == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto exit; } // // Protect ourselves just in case the helper DLL returns // really stupid data. // try { RtlCopyMemory( protocolInfo2, tmpProtocolInfo2, protocolInfo2Length ); error = NO_ERROR; } except( EXCEPTION_EXECUTE_HANDLER ) { error = GetExceptionCode(); } if( error == NO_ERROR ) { IF_DEBUG_SETUP { DBG_PRINT(( "BuildWinsock2ProtocolList returning %lu entries from %ls\n", protocolInfo2Entries, ProviderDllPath )); } *ProtocolInfo2 = protocolInfo2; *ProtocolInfo2Entries = protocolInfo2Entries; goto exit; } } } // // If we made it this far, then either a) we couldn't load the // helper DLL, b) the helper DLL doesn't export the new entrypoint, // c) the entrypoint failed to return the required info, or d) the // entrypoint returned bogus data causing us to throw an exception // when we tried to copy it. In any case, just proceed and construct // the new data ourselves. // // Note that the common cleanup code at the end of this routine // is responsible for freeing the helper DLL if was successfully // loaded. // } // // Determine the required size of the WinSock 2.0 protocol // info buffer. We know we'll need at least as many entries // as in the 1.1 list, maybe more (for pseudo-stream protocols). // protocolInfo2Entries = ProtocolInfo11Entries; // // Determine the number of WinSock 2.0 entries required. // for( i = 0 ; i < ProtocolInfo11Entries ; i++ ) { if( ProtocolInfo11[i].dwServiceFlags & XP_PSEUDO_STREAM ) { protocolInfo2Entries++; } } // // If this is for TCP/IP, then add another entry for RAW sockets. // if( _tcsicmp( ProviderName, TEXT("TcpIp") ) == 0 ) { protocolInfo2Entries++; } // // Create the buffer. // protocolInfo2Length = protocolInfo2Entries * sizeof(WSAPROTOCOL_INFO); protocolInfo2 = ALLOC_MEM( protocolInfo2Length ); if( protocolInfo2 == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto exit; } RtlZeroMemory( protocolInfo2, protocolInfo2Length ); // // Now map the 1.1 entries to 2.0. // for( i = 0, j = 0 ; i < ProtocolInfo11Entries ; i++, j++ ) { DBG_ASSERT( j < protocolInfo2Entries ); addressFamily = ProtocolInfo11[i].iAddressFamily; socketType = ProtocolInfo11[i].iSocketType; protocol = ProtocolInfo11[i].iProtocol; protocolInfo2[j].iVersion = WINSOCK_SPI_VERSION; protocolInfo2[j].iAddressFamily = addressFamily; protocolInfo2[j].iMaxSockAddr = ProtocolInfo11[i].iMaxSockAddr; protocolInfo2[j].iMinSockAddr = ProtocolInfo11[i].iMinSockAddr; protocolInfo2[j].iSocketType = socketType; protocolInfo2[j].iProtocol = protocol; protocolInfo2[j].iProtocolMaxOffset = 0; protocolInfo2[j].iNetworkByteOrder = BIGENDIAN; protocolInfo2[j].iSecurityScheme = SECURITY_PROTOCOL_NONE; protocolInfo2[j].dwMessageSize = ProtocolInfo11[i].dwMessageSize; protocolInfo2[j].dwProviderFlags = 0; protocolInfo2[j].dwServiceFlags1 = ( ProtocolInfo11[i].dwServiceFlags & COMMON_SERVICE_FLAGS ) | FORCED_SERVICE_FLAGS; protocolInfo2[j].dwServiceFlags2 = 0; protocolInfo2[j].dwServiceFlags3 = 0; protocolInfo2[j].dwServiceFlags4 = 0; protocolInfo2[j].ProtocolChain.ChainLen = BASE_PROTOCOL; if( addressFamily == AF_INET ) { protocolInfo2[j].dwProviderFlags |= PFL_MATCHES_PROTOCOL_ZERO; } else if( addressFamily == AF_IPX && socketType == SOCK_DGRAM ) { protocolInfo2[j].iProtocolMaxOffset = 255; } else if( addressFamily == AF_APPLETALK && socketType == SOCK_DGRAM ) { protocolInfo2[j].iProtocolMaxOffset = 255; } else if( addressFamily == AF_NETBIOS && ( protocol == 0 || protocol == 0x80000000 ) ) { protocolInfo2[j].iProtocol = 0x80000000; protocolInfo2[j].dwProviderFlags |= PFL_MATCHES_PROTOCOL_ZERO; } else if( addressFamily == AF_ISO ) { protocolInfo2[j].dwServiceFlags1 |= XP1_CONNECT_DATA | XP1_DISCONNECT_DATA; protocolInfo2[j].dwProviderFlags |= PFL_MATCHES_PROTOCOL_ZERO; } // // The dwProviderReserved field MUST be zero for WSPDuplicateSocket() // to function properly. // DBG_ASSERT( protocolInfo2[j].dwProviderReserved == 0 ); if( ProtocolInfo11[i].dwServiceFlags & XP_PSEUDO_STREAM ) { protocolInfo2[j].dwProviderFlags |= PFL_MULTIPLE_PROTO_ENTRIES | PFL_RECOMMENDED_PROTO_ENTRY; BuildNewProtocolName( ProviderName, &ProtocolInfo11[i], protocolInfo2[j].szProtocol ); j++; protocolInfo2[j] = protocolInfo2[j-1]; protocolInfo2[j].dwProviderFlags &= ~PFL_RECOMMENDED_PROTO_ENTRY; protocolInfo2[j].iSocketType = SOCK_STREAM; protocolInfo2[j].dwMessageSize = 0; BuildNewProtocolName( ProviderName, &ProtocolInfo11[i], protocolInfo2[j].szProtocol ); _tcscat( protocolInfo2[j].szProtocol, TEXT(" [Pseudo Stream]") ); } else { BuildNewProtocolName( ProviderName, &ProtocolInfo11[i], protocolInfo2[j].szProtocol ); } } // // Hand build the RAW IP entry if necessary. // if( _tcsicmp( ProviderName, TEXT("TcpIp") ) == 0 ) { protocolInfo2[j].iVersion = WINSOCK_SPI_VERSION; protocolInfo2[j].iAddressFamily = AF_INET; protocolInfo2[j].iMaxSockAddr = sizeof(SOCKADDR_IN); protocolInfo2[j].iMinSockAddr = sizeof(SOCKADDR_IN); protocolInfo2[j].iSocketType = SOCK_RAW; protocolInfo2[j].iProtocol = IPPROTO_IP; protocolInfo2[j].iProtocolMaxOffset = 255; protocolInfo2[j].iNetworkByteOrder = BIGENDIAN; protocolInfo2[j].iSecurityScheme = SECURITY_PROTOCOL_NONE; protocolInfo2[j].dwMessageSize = 65467; protocolInfo2[j].dwProviderFlags = PFL_HIDDEN | PFL_MATCHES_PROTOCOL_ZERO; protocolInfo2[j].dwServiceFlags1 = FORCED_SERVICE_FLAGS | XP1_CONNECTIONLESS | XP1_MESSAGE_ORIENTED | XP1_SUPPORT_BROADCAST | XP1_SUPPORT_MULTIPOINT; protocolInfo2[j].dwServiceFlags2 = 0; protocolInfo2[j].dwServiceFlags3 = 0; protocolInfo2[j].dwServiceFlags4 = 0; protocolInfo2[j].ProtocolChain.ChainLen = BASE_PROTOCOL; wsprintf( protocolInfo2[j].szProtocol, TEXT("MSAFD %s [%s]"), ProviderName, TEXT("RAW/IP") ); // // The dwProviderReserved field MUST be zero for WSPDuplicateSocket() // to function properly. // DBG_ASSERT( protocolInfo2[j].dwProviderReserved == 0 ); } // // Success! // *ProtocolInfo2 = protocolInfo2; *ProtocolInfo2Entries = protocolInfo2Entries; exit: if( error != NO_ERROR && protocolInfo2 != NULL ) { FREE_MEM( protocolInfo2 ); } if( helperDllHandle != NULL ) { FreeLibrary( helperDllHandle ); } return error; } // BuildWinsock2ProtocolList VOID BuildNewProtocolName( LPTSTR ProviderName, LPPROTOCOL_INFO ProtocolInfo11, LPTSTR NewProtocolName ) /*++ Routine Description: Constructs a protocol name for the given protocol, as supported by the given provider. Arguments: ProviderName - The name of the current provider. ProtocolInfo11 - A pointer to the WinSock 1.1 protocol information describing a single protocol. NewProtocolName - Will receive the name for the new protocol. Return Value: None. --*/ { WCHAR socketType[16]; INT lanaNumber; // // Sanity check. // DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( ProtocolInfo11 != NULL ); DBG_ASSERT( NewProtocolName != NULL ); // // Build the name. // if( _tcsnicmp( ProtocolInfo11->lpProtocol, TEXT("\\device\\"), 8 ) == 0 ) { // // The old protocol name was of the form \Device\FooBar, so // we'll need to construct a new name that contains the LANA // number and socket type so that the names remain unique. // lanaNumber = ProtocolInfo11->iProtocol; if( lanaNumber == 0x80000000 ) { lanaNumber = 0; } else if( lanaNumber < 0 ) { lanaNumber = -lanaNumber; } switch( ProtocolInfo11->iSocketType ) { case SOCK_STREAM : _tcscpy( socketType, TEXT("STREAM") ); break; case SOCK_DGRAM : _tcscpy( socketType, TEXT("DATAGRAM") ); break; case SOCK_RAW : _tcscpy( socketType, TEXT("RAW") ); break; case SOCK_RDM : _tcscpy( socketType, TEXT("RDM") ); break; case SOCK_SEQPACKET : _tcscpy( socketType, TEXT("SEQPACKET") ); break; default : wsprintf( socketType, TEXT("%d"), ProtocolInfo11->iSocketType ); break; } wsprintf( NewProtocolName, TEXT("MSAFD %s [%s] %s %d"), ProviderName, ProtocolInfo11->lpProtocol, socketType, lanaNumber ); } else { wsprintf( NewProtocolName, TEXT("MSAFD %s [%s]"), ProviderName, ProtocolInfo11->lpProtocol ); } } // BuildNewProtocolName DWORD InstallNewProvider( HKEY WellKnownGuidsKey, HKEY ProvidersKey, LPTSTR ProviderName, LPTSTR ProviderDllPath, BOOL IsKnownStaticProvider, LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Length, DWORD ProtocolInfo11Entries ) /*++ Routine Description: Takes the WinSock 1.1 protocol information, maps it to WinSock 2.0 protocol information, installs the provider by invoking the WSCInstallProvider() entrypoint, and creates the provider's subtree of the ...\Setup Migration\Providers registry tree. Arguments: WellKnownGuidsKey - A handle to the ...\Setup Migration\Well Known Guids registry key. ProvidersKey - A handle to the ...\Setup Migration\Providers registry tree. ProviderName - The name of the provider being installed. ProviderDllPath - The fully expanded path to the provider's helper DLL. IsKnownStaticProvider - This will be TRUE if we know this is a static provider that doesn't change its supported triples at random. If this is TRUE, then we don't bother writing the WinSock 1.1 protocol information to the registry. ProtocolInfo11 - A pointer to the provider's WinSock 1.1 protocol information. ProtocolInfo11Length - The length (in BYTEs) of the WinSock 1.1 protocol information. ProtocolInfo11Entries - The number of entries in the WinSock 1.1 protocol information. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; DWORD error2; LPWSAPROTOCOL_INFO protocolInfo2; DWORD protocolInfo2Entries; INT result; INT dummy; GUID providerId; BOOL providerInstalled; // // Sanity check. // DBG_ASSERT( WellKnownGuidsKey != NULL ); DBG_ASSERT( ProvidersKey != NULL ); DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( ProviderDllPath != NULL ); DBG_ASSERT( ProtocolInfo11 != NULL ); DBG_ASSERT( ProtocolInfo11Length > 0 ); DBG_ASSERT( ProtocolInfo11Entries > 0 ); // // Setup locals so we know how to cleanup on exit. // protocolInfo2 = NULL; providerInstalled = FALSE; // // Map the old (WinSock 1.1 RNR) protocol info to the new & improved // (WinSock 2.0) protocol info. // error = BuildWinsock2ProtocolList( ProviderName, ProviderDllPath, ProtocolInfo11, ProtocolInfo11Entries, &protocolInfo2, &protocolInfo2Entries ); if( error != NO_ERROR ) { goto exit; } // // Determine/create/whatever a GUID for this provider. // error = DetermineGuidForProvider( WellKnownGuidsKey, ProviderName, ProviderDllPath, &providerId ); if( error != NO_ERROR ) { goto exit; } // // Install it. // result = (WSCInstallProviderProc)( &providerId, DEFAULT_PROVIDER_PATH, protocolInfo2, protocolInfo2Entries, (LPINT)&error ); if( result == SOCKET_ERROR ) { // // Bummer, could not install the provider. This could possibly // be due to bogus registry information. So, we'll try to clean // the configuration for this provider, then reattempt the install. // error2 = SanitizeWinsock2ConfigForProvider( &providerId ); if( error2 == NO_ERROR ) { DBG_PRINT(( "error %d, retrying\n", error )); result = (WSCInstallProviderProc)( &providerId, DEFAULT_PROVIDER_PATH, protocolInfo2, protocolInfo2Entries, (LPINT)&error ); if( result == SOCKET_ERROR ) { DBG_ASSERT( error != NO_ERROR ); goto exit; } } // // If we made it this far, then the we successfully santizied // the configuration & installed the provider on the second // attempt. // error = NO_ERROR; } providerInstalled = TRUE; // // Create the registry info. // MapProtocolInfoToSelfRelative( ProtocolInfo11, ProtocolInfo11Entries ); error = CreateMigrationRegistryForProvider( ProvidersKey, ProviderName, IsKnownStaticProvider, ProtocolInfo11, ProtocolInfo11Length, &providerId ); MapProtocolInfoToAbsolute( ProtocolInfo11, ProtocolInfo11Entries ); if( error != NO_ERROR ) { goto exit; } // // Success! // exit: if( protocolInfo2 != NULL ) { FREE_MEM( protocolInfo2 ); } if( error != NO_ERROR && providerInstalled ) { (VOID)(WSCDeinstallProviderProc)( &providerId, &dummy ); } return error; } // InstallNewProvider DWORD CreateMigrationRegistryForProvider( HKEY ProvidersKey, LPTSTR ProviderName, BOOL IsKnownStaticProvider, LPPROTOCOL_INFO ProtocolInfo11, DWORD ProtocolInfo11Length, LPGUID ProviderId ) /*++ Routine Description: Creates the ...\WinSock\Setup Migration\Providers\{provider} registry tree for the specified provider. Arguments: ProvidersKey - A handle to the ...\Setup Migration\Providers registry key. ProviderName - The name of the provider being installed. IsKnownStaticProvider - This will be TRUE if we know this is a static provider that doesn't change its supported triples at random. If this is TRUE, then we don't bother writing the WinSock 1.1 protocol information to the registry. ProtocolInfo11 - A pointer to the provider's WinSock 1.1 protocol information. ProtocolInfo11Length - The length (in BYTEs) of the WinSock 1.1 protocol information. ProviderId - The provider's GUID. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HKEY providerKey; DWORD disposition; // // Sanity check. // DBG_ASSERT( ProvidersKey != NULL ); DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( ProtocolInfo11 != NULL ); DBG_ASSERT( ProtocolInfo11Length > 0 ); DBG_ASSERT( ProviderId != NULL ); // // Setup locals so we know how to cleanup on exit. // providerKey = NULL; // // Create the provider's key. // error = RegCreateKeyEx( ProvidersKey, ProviderName, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &providerKey, &disposition ); if( error != NO_ERROR ) { goto exit; } // // Create the values. // if( !IsKnownStaticProvider ) { error = WriteBinary( providerKey, WINSOCK_1_1_DATA_VALUE, ProtocolInfo11, ProtocolInfo11Length ); if( error != NO_ERROR ) { goto exit; } } error = WriteGuid( providerKey, WINSOCK_2_0_ID_VALUE, ProviderId ); if( error != NO_ERROR ) { goto exit; } // // Success! // exit: if( providerKey != NULL ) { (VOID)RegCloseKey( providerKey ); } if( error != NO_ERROR ) { (VOID)RecursivelyDeleteRegistryTree( ProvidersKey, ProviderName ); } return error; } // CreateMigrationRegistryForProvider DWORD CreateProtocolCatalogMutex( LPHANDLE Handle ) /*++ Routine Description: Creates the named, shared mutex that protects the protocol catalog in the system registry. Arguments: Handle - Will receive a handle to the protocol catalog mutex if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { PSECURITY_DESCRIPTOR securityDescriptor; SECURITY_ATTRIBUTES securityAttributes; BOOL result; BYTE securityDescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH]; // // Sanity check. // DBG_ASSERT( Handle != NULL ); // // Initialize the security descriptor. // securityDescriptor = (PSECURITY_DESCRIPTOR)securityDescriptorBuffer; result = InitializeSecurityDescriptor( securityDescriptor, SECURITY_DESCRIPTOR_REVISION ); if( !result ) { return GetLastError(); } // // Add a NULL DACL to the security descriptor. // result = SetSecurityDescriptorDacl( securityDescriptor, // psd TRUE, // fDaclPresent NULL, // pAcl FALSE // pDaclDefaulted ); if( !result ) { return GetLastError(); } // // Create the mutex. // securityAttributes.nLength = sizeof(securityAttributes); securityAttributes.lpSecurityDescriptor = securityDescriptor; securityAttributes.bInheritHandle = FALSE; *Handle = CreateMutexA( &securityAttributes, // lpMutexAttributes FALSE, // bInitialOwner CATALOG_MUTEX_NAME // lpName ); if( *Handle == NULL ) { return GetLastError(); } // // Success! // return NO_ERROR; } // CreateProtocolCatalogMutex DWORD AcquireProtocolCatalogMutex( HANDLE Handle ) /*++ Routine Description: Acquires ownership of the mutex protecting the protocol catalog. Arguments: Handle - A handle to the protocol catalog mutex. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD result; // // Sanity check. // DBG_ASSERT( Handle != NULL ); // // Wait for ownership of the mutex. // result = WaitForSingleObject( Handle, INFINITE ); if( result == WAIT_FAILED ){ return GetLastError(); } // // Success! // return NO_ERROR; } // AcquireProtocolCatalogMutex DWORD ReleaseProtocolCatalogMutex( HANDLE Handle ) /*++ Routine Description: Relinquishes ownership of the mutex protecting the protocol catalog. Arguments: Handle - A handle to the protocol catalog mutex. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { BOOL result; // // Sanity check. // DBG_ASSERT( Handle != NULL ); // // Relinquish ownership of the mutex. // result = ReleaseMutex( Handle ); if( !result ) { return GetLastError(); } // // Success! // return NO_ERROR; } // ReleaseProtocolCatalogMutex DWORD RemoveAllInstalledProviders( HKEY ProvidersKey ) /*++ Routine Description: Removes all installed providers. This is used to cleanup everything after a setup version update has been detected. Arguments: ProvidersKey - A handle to the ...\Setup Migration\Providers registry key. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; FILETIME lastWriteTime; DWORD subkeyIndex; DWORD subkeyNameLength; WCHAR subkeyName[MAX_REGISTRY_NAME]; // // Sanity check. // DBG_ASSERT( ProvidersKey != NULL ); // // Enumerate & remove the providers. // subkeyIndex = 0; for( ; ; ) { subkeyNameLength = sizeof(subkeyName); error = RegEnumKeyEx( ProvidersKey, subkeyIndex, subkeyName, &subkeyNameLength, NULL, NULL, NULL, &lastWriteTime ); if( error != NO_ERROR ) { break; } error = RemoveProviderByName( ProvidersKey, subkeyName ); if( error != NO_ERROR ) { break; } // // Note that since we just totally blew away the current subkey // in the enumeration, we do not want to increment the subkey // index. // } if( error != ERROR_NO_MORE_ITEMS ) { goto exit; } // // Success! // error = NO_ERROR; exit: return error; } // RemoveAllInstalledProviders DWORD AppendStringToMultiSz( LPTSTR * MultiSz, LPTSTR String ) /*++ Routine Description: Appends a string to a MULTI_SZ. If this is the first attempt, then the MULTI_SZ is created. Arguments: MultiSz - Points to a pointer to the MULTI_SZ. MutliSz may never be NULL, but *MultiSz may be NULL if this routine is to create a new MULTI_SZ. String - The string to append. key. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { LPTSTR scan; LPTSTR newMultiSz; DWORD stringLength; // // Sanity check. // DBG_ASSERT( MultiSz != NULL ); DBG_ASSERT( String != NULL ); // // Calculate the length of the new string. // stringLength = _tcslen( String ) + 1; // // If this is the first append, then create a new MULTI_SZ. // Otherwise, calculate the new MULTI_SZ length, allocate another // buffer, and copy the old string into the new buffer. // if( *MultiSz == NULL ) { newMultiSz = ALLOC_MEM( ( stringLength + 1 ) * sizeof(TCHAR) ); scan = newMultiSz; } else { for( scan = *MultiSz ; *scan != TEXT('\0') ; scan += _tcslen( scan ) + 1 ) { // Empty. } newMultiSz = ALLOC_MEM( ( ( scan - *MultiSz ) + stringLength + 1 ) * sizeof(TCHAR) ); if( newMultiSz != NULL ) { RtlCopyMemory( newMultiSz, *MultiSz, ( scan - *MultiSz ) * sizeof(TCHAR) ); scan = newMultiSz + ( scan - *MultiSz ); } } // // Bail if the allocation failed. // if( newMultiSz == NULL ) { return ERROR_NOT_ENOUGH_MEMORY; } // // Free the old MULTI_SZ. // if( *MultiSz != NULL ) { FREE_MEM( *MultiSz ); } // // Append the new string onto the new MULTI_SZ. // _tcscpy( scan, String ); scan[stringLength] = TEXT('\0'); // // Success! // *MultiSz = newMultiSz; return NO_ERROR; } // AppendStringToMultiSz DWORD SanitizeWinsock2ConfigForProvider( LPGUID ProviderId ) /*++ Routine Description: Attempts to "sanitize" the Winsock 2 configuration for a specific provider after an installation attempt for that provider fails unexpectedly. Arguments: ProviderId - Identifies the provider. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { INT result; INT error; // // Since we're using GUIDs instead of those goofy WS2_32.DLL-generated // DWORDs to identify providers, the only thing we need to do to // sanitize the configuration is attempt to remove the provider. If that // fails, we're probably screwed, but we'll press on regardless. // result = (WSCDeinstallProviderProc)( ProviderId, &error ); if( result == SOCKET_ERROR ) { if( error == WSAEFAULT ) { // // This just means that the provider didn't really // exist, so we won't even whine about this one. // } else { DBG_PRINT(( "Cannot sanitize, error %d, ignoring\n", error )); } error = NO_ERROR; } // // Press on regardless. // DBG_ASSERT( error == NO_ERROR ); return error; } // SanitizeWinsock2ConfigForProvider DWORD DetermineGuidForProvider( HKEY WellKnownGuidsKey, LPTSTR ProviderName, LPTSTR ProviderDllPath, LPGUID ProviderId ) /*++ Routine Description: Determines the appropriate GUID for the specified provider. If the provider's helper DLL supports the WSHGetProviderGuid() entrypoint, we'll call it to get the GUID. Otherwise, we'll look it up in the Well Known Guids catalog. If that fails, we'll create one from scratch and add it to the catalog. Arguments: WellKnownGuidsKey - A handle to the ...\Setup Migration\Well Known Guids registry key. ProviderName - The name of the provider being installed. ProviderDllPath - The fully expanded path to the provider's helper DLL. ProviderId - Will receive the provider's GUID if successful. Return Value: DWORD - A Win32 status code, 0 if successful, !0 otherwise. --*/ { DWORD error; HMODULE helperDllHandle; PWSH_GET_PROVIDER_GUID getProviderGuid; // // Sanity check. // DBG_ASSERT( WellKnownGuidsKey != NULL ); DBG_ASSERT( ProviderName != NULL ); DBG_ASSERT( ProviderDllPath != NULL ); DBG_ASSERT( ProviderId != NULL ); // // Load the DLL and find the entrypoint. // helperDllHandle = LoadLibrary( ProviderDllPath ); if( helperDllHandle != NULL ) { getProviderGuid = (PVOID)GetProcAddress( helperDllHandle, "WSHGetProviderGuid" ); if( getProviderGuid != NULL ) { // // Protect ourselves in case the helper DLL does something // stupid. // try { // // Call it to get the GUID. // error = (DWORD)getProviderGuid( ProviderName, ProviderId ); } except( EXCEPTION_EXECUTE_HANDLER ) { error = GetExceptionCode(); } if( error == NO_ERROR ) { // // Success! // FreeLibrary( helperDllHandle ); return NO_ERROR; } } FreeLibrary( helperDllHandle ); } DBG_PRINT(( "DetermineGuidForProvider: cannot get GUID from %ls for %ls\n", ProviderDllPath, ProviderName )); // // If we made it this far, then either the helper DLL doesn't support // the WSHGetProviderGuid() entrypoint, or it threw an exception when // we called it. In any case, see if the provider has an entry in the // well known GUIDs catalog. // error = ReadGuid( WellKnownGuidsKey, ProviderName, ProviderId ); if( error == NO_ERROR ) { // // Success! // return NO_ERROR; } // // Bummer. We'll need to create a GUID from scratch and add it to the // catalog. // error = UuidCreate( ProviderId ); if( error == NO_ERROR ) { error = WriteGuid( WellKnownGuidsKey, ProviderName, ProviderId ); } else { // // Total bummer, UuidCreate() failed. // DBG_PRINT(( "DetermineGuidForProvider: UuidCreate() failed, error %d\n", error )); } return error; } // DetermineGuidForProvider