/*\r
* Copyright (c) 2005 SilverStorm Technologies. All rights reserved.\r
+ * Portions Copyright (c) 2008 Microsoft Corporation. All rights reserved.\r
*\r
* This software is available to you under the OpenIB.org BSD license\r
* below:\r
\r
/*\r
* Module Name: installsp.c\r
- * Description: This module installs/removes a winsock service provider for infiniband. \r
+ * Description: This module installs/removes the NetworkDirect provider for infiniband.\r
* execute:\r
* To install the service provider\r
- * installsp -i \r
+ * installsp -i\r
* To remove the service provider\r
* installsp -r\r
*/\r
#include <winsock2.h>\r
#include <ws2spi.h>\r
#include <stdio.h>\r
-#include <stdlib.h>\r
\r
+#ifndef PFL_NETWORKDIRECT_PROVIDER\r
+#define PFL_NETWORKDIRECT_PROVIDER 0x00000010\r
+#endif\r
\r
/* Initialize the LSP's provider path for Infiband Service Provider dll */\r
-static const WCHAR provider_path[] = L"%SYSTEMROOT%\\system32\\ibwsd.dll";\r
-static const WCHAR provider_prefix[] =L" Winsock Direct for InfiniBand"; //includes one whitespace\r
-static const char provider_name[] = VER_PROVIDER ;//L"%VER_PROVIDER% Winsock Direct for InfiniBand"; //(VER_PROVIDER ## WINDIR);\r
-static const char winsock_key_path[] =\r
- "System\\CurrentControlSet\\Services\\Winsock\\Parameters\\TCP on SAN";\r
-static const char openib_key_name[] = IB_COMPANYNAME;\r
+static const WCHAR provider_path[] = L"%SYSTEMROOT%\\system32\\ibndprov.dll";\r
+static const WCHAR provider_name[] = L"OpenFabrics Network Direct Provider";\r
+static const char openib_key_name[] = "OpenFabrics Alliance";\r
\r
/* Unique provider GUID generated with "uuidgen -s" */\r
static GUID provider_guid = {\r
- /* c943654d-2c84-4db7-af3e-fdf1c5322458 */\r
- 0xc943654d, 0x2c84, 0x4db7,\r
- { 0xaf, 0x3e, 0xfd, 0xf1, 0xc5, 0x32, 0x24, 0x58 }\r
+ /* {52CDAA00-29D0-46be-8FC6-E51D7075C338} */\r
+ 0x52CDAA00, 0x29D0, 0x46be,\r
+ { 0x8f, 0xc6, 0xe5, 0x1d, 0x70, 0x75, 0xc3, 0x38 }\r
};\r
\r
#ifdef _WIN64\r
#define WSCInstallProvider WSCInstallProvider64_32\r
#endif /* _WIN64 */\r
\r
-#ifdef PERFMON_ENABLED\r
-#include <Loadperf.h>\r
-#include "wsd/ibsp_regpath.h"\r
-\r
-\r
-typedef struct _pm_symbol_def\r
-{\r
- DWORD name_def;\r
- CHAR name_str[40];\r
- CHAR name_desc[40];\r
- CHAR help_desc[256];\r
-\r
-} pm_symbol_def_t;\r
-\r
-static pm_symbol_def_t _pm_symbols[]=\r
-{\r
- { IBSP_PM_OBJ,\r
- "IBSP_PM_OBJ",\r
- "IB Winsock Direct",\r
- "InfiniBand Windows Sockets Direct Provider."\r
- },\r
- { IBSP_PM_COUNTER(BYTES_SEND),\r
- "IBSP_PM_BYTES_TX_SEC",\r
- "Send bytes/sec",\r
- "Send bytes/second, excluding RDMA Write."\r
- },\r
- { IBSP_PM_COUNTER(BYTES_RECV),\r
- "IBSP_PM_BYTES_RX_SEC",\r
- "Recv bytes/sec",\r
- "Receive bytes/second, excluding RDMA Read."\r
- },\r
- { IBSP_PM_COUNTER(BYTES_WRITE),\r
- "IBSP_PM_RDMA_WR_SEC",\r
- "RDMA Write bytes/sec",\r
- "RDMA Write bytes/second."\r
- },\r
- { IBSP_PM_COUNTER(BYTES_READ),\r
- "IBSP_PM_RDMA_RD_SEC",\r
- "RDMA Read bytes/sec",\r
- "RDMA Read bytes/second."\r
- },\r
- { IBSP_PM_COUNTER(BYTES_TOTAL),\r
- "IBSP_PM_BYTES_SEC",\r
- "Total bytes/sec",\r
- "Total bytes transmitted per second, including send, "\r
- "receive, RDMA Write, and RDMA Read."\r
- },\r
- { IBSP_PM_COUNTER(COMP_SEND),\r
- "IBSP_PM_SEND_COMPLETIONS_SEC",\r
- "Send Completions/sec",\r
- "Send and RDMA Write Completions/sec."\r
- },\r
- { IBSP_PM_COUNTER(COMP_RECV),\r
- "IBSP_PM_RECV_COMPLETIONS_SEC",\r
- "Recv Completions/sec",\r
- "Recv and RDMA Read Completions/sec."\r
- },\r
- { IBSP_PM_COUNTER(COMP_TOTAL),\r
- "IBSP_PM_COMPLETIONS_SEC",\r
- "Total Completions/sec",\r
- "Total Completions processed per second."\r
- },\r
- { IBSP_PM_COUNTER(INTR_TOTAL),\r
- "IBSP_PM_COMPLETIONS_INTR",\r
- "Total Interrupts/sec",\r
- "Completion Queue events per second."\r
- }\r
-};\r
-\r
-#define IBSP_PM_NUM_SYMBOLS (sizeof(_pm_symbols)/sizeof(pm_symbol_def_t))\r
-#define IBSP_PM_LANGUAGE "009" /* good for English */\r
-\r
-static CHAR *\r
-_IBSPGenerateFileName(char *header, char *file )\r
-{\r
- DWORD size1, size;\r
- CHAR *full_file_name;\r
- int header_len = header == NULL ? 0 : strlen(header);\r
-\r
- size = GetTempPath(0, NULL);\r
- if (size == 0)\r
- {\r
- fprintf( stderr, "GetTempPath failed\n" );\r
- return NULL;\r
- }\r
- size1 = size + strlen(file) + header_len;\r
- full_file_name = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, size1);\r
- if ( full_file_name == NULL )\r
- {\r
- fprintf( stderr, "GetTempPath failed\n" );\r
- return NULL;\r
- }\r
- size1 = GetTempPath(size, full_file_name + header_len);\r
- if (size != size1 + 1) \r
- {\r
- fprintf( stderr, "Very strange, GetTempPath returned something different\n" );\r
- HeapFree (GetProcessHeap (), 0, full_file_name);\r
- return NULL;\r
- }\r
- if (header_len != 0)\r
- {\r
- memcpy(full_file_name, header, header_len);\r
- }\r
- strcat(full_file_name, file);\r
- return full_file_name;\r
-}\r
-\r
-\r
-static DWORD\r
-_IBSPPerfmonIniFilesGenerate( void )\r
-{\r
- FILE *f_handle;\r
- DWORD num;\r
- DWORD ret = ERROR_SUCCESS;\r
- char *ibsp_pm_sym_file = NULL;\r
- char *ibsp_pm_ini_file = NULL;\r
-\r
- /* create ".h" file first */\r
- ibsp_pm_sym_file = _IBSPGenerateFileName(NULL, IBSP_PM_SYM_H_FILE);\r
- if( !ibsp_pm_sym_file )\r
- {\r
- fprintf( stderr, "_IBSPGenerateFileName failed\n" );\r
- ret = ERROR_NOT_ENOUGH_MEMORY;\r
- goto Cleanup;\r
- }\r
-\r
- f_handle = fopen( ibsp_pm_sym_file, "w+" );\r
-\r
- if( !f_handle )\r
- {\r
- fprintf( stderr, "Create Header file %s failed\n", ibsp_pm_sym_file );\r
- ret = ERROR_FILE_INVALID;\r
- goto Cleanup;\r
- }\r
-\r
- fprintf(\r
- f_handle, "/* %s Generated by program */ \r\n", ibsp_pm_sym_file );\r
- \r
- \r
- for( num = 0; num < IBSP_PM_NUM_SYMBOLS; num++ )\r
- {\r
- fprintf( f_handle, "#define\t%s\t%d\r\n",\r
- _pm_symbols[num].name_str, _pm_symbols[num].name_def );\r
- }\r
-\r
- fflush( f_handle );\r
- fclose( f_handle );\r
-\r
- /* create 'ini' file next */\r
- ibsp_pm_ini_file = _IBSPGenerateFileName(NULL, IBSP_PM_INI_FILE);\r
- if( !ibsp_pm_sym_file )\r
- {\r
- fprintf( stderr, "_IBSPGenerateFileName failed\n" );\r
- ret = ERROR_NOT_ENOUGH_MEMORY;\r
- goto Cleanup;\r
- }\r
- f_handle = fopen( ibsp_pm_ini_file, "w+" );\r
-\r
- if( !f_handle )\r
- {\r
- fprintf( stderr, "Create INI file %s failed\n", ibsp_pm_ini_file );\r
- ret = ERROR_FILE_INVALID;\r
- goto Cleanup;\r
- }\r
- \r
- fprintf( f_handle, "[info]\r\ndrivername=" IBSP_PM_SUBKEY_NAME\r
- "\r\nsymbolfile=%s\r\n\r\n", ibsp_pm_sym_file );\r
- fprintf( f_handle,"[languages]\r\n" IBSP_PM_LANGUAGE\r
- "=language" IBSP_PM_LANGUAGE "\r\n\r\n" );\r
-\r
- fprintf( f_handle, \r
- "[objects]\r\n%s_" IBSP_PM_LANGUAGE "_NAME=%s\r\n\r\n[text]\r\n",\r
- _pm_symbols[0].name_str, _pm_symbols[0].name_desc );\r
- \r
- for( num = 0; num < IBSP_PM_NUM_SYMBOLS; num++ )\r
- {\r
- fprintf( f_handle,"%s_" IBSP_PM_LANGUAGE "_NAME=%s\r\n",\r
- _pm_symbols[num].name_str, _pm_symbols[num].name_desc );\r
- fprintf( f_handle,"%s_" IBSP_PM_LANGUAGE "_HELP=%s\r\n",\r
- _pm_symbols[num].name_str, _pm_symbols[num].help_desc );\r
- }\r
-\r
- fflush( f_handle );\r
- fclose( f_handle );\r
-\r
-Cleanup:\r
- if ( ibsp_pm_sym_file )\r
- {\r
- HeapFree (GetProcessHeap (), 0, ibsp_pm_sym_file);\r
- }\r
- if ( ibsp_pm_ini_file )\r
- {\r
- HeapFree (GetProcessHeap (), 0, ibsp_pm_ini_file);\r
- }\r
- return ret;\r
-}\r
-\r
-\r
-static void\r
-_IBSPPerfmonIniFilesRemove( void )\r
-{\r
- char *ibsp_pm_sym_file = NULL;\r
- char *ibsp_pm_ini_file = NULL;\r
-\r
- ibsp_pm_sym_file = _IBSPGenerateFileName(NULL, IBSP_PM_SYM_H_FILE);\r
- if( !ibsp_pm_sym_file )\r
- {\r
- fprintf( stderr, "_IBSPGenerateFileName failed\n" );\r
- goto Cleanup;\r
- }\r
-\r
- ibsp_pm_ini_file = _IBSPGenerateFileName(NULL, IBSP_PM_INI_FILE);\r
- if( !ibsp_pm_sym_file )\r
- {\r
- fprintf( stderr, "_IBSPGenerateFileName failed\n" );\r
- goto Cleanup;\r
- }\r
-\r
- if( !DeleteFile( ibsp_pm_ini_file ) )\r
- {\r
- fprintf( stderr, "Delete file %s failed status %d\n",\r
- ibsp_pm_ini_file, GetLastError() );\r
- }\r
- if( !DeleteFile( ibsp_pm_sym_file ) )\r
- {\r
- fprintf( stderr,"Delete file %s failed status %d\n",\r
- ibsp_pm_sym_file, GetLastError() );\r
- }\r
-\r
-Cleanup: \r
- if ( ibsp_pm_sym_file )\r
- {\r
- HeapFree (GetProcessHeap (), 0, ibsp_pm_sym_file);\r
- }\r
- if ( ibsp_pm_ini_file )\r
- {\r
- HeapFree (GetProcessHeap (), 0, ibsp_pm_ini_file);\r
- }\r
- \r
-}\r
-\r
-\r
-/* Try to create IB WSD Performance Register Keys */\r
-static LONG\r
-_IBSPPerfmonRegisterKeys( void )\r
-{\r
- LONG reg_status;\r
- HKEY pm_hkey;\r
- DWORD typesSupp = 7;\r
-\r
- reg_status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,\r
- IBSP_PM_REGISTRY_PATH IBSP_PM_SUBKEY_PERF, 0, NULL,\r
- REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &pm_hkey, NULL );\r
-\r
- if( reg_status != ERROR_SUCCESS )\r
- {\r
- fprintf( stderr,\r
- "_IBSPPerfmonRegisterKeys Create Key %s failed with %d\n",\r
- IBSP_PM_REGISTRY_PATH IBSP_PM_SUBKEY_PERF, reg_status );\r
- return reg_status;\r
- }\r
-\r
- /* create/assign values to the key */\r
- RegSetValueExW( pm_hkey, L"Library", 0, REG_EXPAND_SZ,\r
- (LPBYTE)provider_path, sizeof(provider_path) );\r
-\r
- RegSetValueEx( pm_hkey, TEXT("Open"), 0, REG_SZ,\r
- (LPBYTE)TEXT("IBSPPmOpen"), sizeof(TEXT("IBSPPmOpen")) );\r
-\r
- RegSetValueEx( pm_hkey, TEXT("Collect"), 0, REG_SZ,\r
- (LPBYTE)TEXT("IBSPPmCollectData"), sizeof(TEXT("IBSPPmCollectData")) );\r
-\r
- RegSetValueEx( pm_hkey, TEXT("Close"), 0, REG_SZ,\r
- (LPBYTE)TEXT("IBSPPmClose"), sizeof(TEXT("IBSPPmClose")) );\r
-\r
- RegFlushKey( pm_hkey );\r
- RegCloseKey( pm_hkey );\r
-\r
- reg_status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,\r
- IBSP_PM_EVENTLOG_PATH, 0, NULL,\r
- REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &pm_hkey, NULL );\r
-\r
- if( reg_status != ERROR_SUCCESS )\r
- {\r
- fprintf(stderr, "Create EventLog Key failed with %d\n", reg_status );\r
- return reg_status;\r
- }\r
-\r
- /* create/assign values to the key */\r
- RegSetValueExW( pm_hkey, L"EventMessageFile", 0, REG_EXPAND_SZ,\\r
- (LPBYTE)provider_path, sizeof(provider_path) );\r
-\r
- RegSetValueEx( pm_hkey, TEXT("TypesSupported"), 0, REG_DWORD,\r
- (LPBYTE)&typesSupp, sizeof(typesSupp) );\r
-\r
- RegFlushKey( pm_hkey );\r
- RegCloseKey( pm_hkey );\r
-\r
- return reg_status;\r
-}\r
-\r
-\r
-/* Try to destroy IB WSD Performance Register Keys */\r
-static LONG\r
-_IBSPPerfmonDeregisterKeys( void )\r
-{\r
- LONG reg_status;\r
-\r
- reg_status = RegDeleteKeyEx( HKEY_LOCAL_MACHINE,\r
- IBSP_PM_REGISTRY_PATH IBSP_PM_SUBKEY_PERF,\r
- (KEY_WOW64_32KEY | KEY_WOW64_64KEY), 0 );\r
-\r
- if( reg_status != ERROR_SUCCESS )\r
- {\r
- fprintf( stderr,\r
- "_IBSPPerfmonRegisterKeys Remove SubKey failed with %d\n",\r
- GetLastError() );\r
- }\r
-\r
- reg_status = RegDeleteKeyEx( HKEY_LOCAL_MACHINE,\r
- IBSP_PM_REGISTRY_PATH, (KEY_WOW64_32KEY | KEY_WOW64_64KEY), 0 );\r
-\r
- if( reg_status != ERROR_SUCCESS )\r
- {\r
- fprintf( stderr,\r
- "_IBSPPerfmonRegisterKeys Remove SubKey failed with %d\n",\r
- GetLastError() );\r
- }\r
-\r
- reg_status = RegDeleteKeyEx( HKEY_LOCAL_MACHINE,\r
- IBSP_PM_EVENTLOG_PATH, (KEY_WOW64_32KEY | KEY_WOW64_64KEY), 0 );\r
-\r
- if( reg_status != ERROR_SUCCESS )\r
- {\r
- fprintf( stderr,\r
- "_IBSPPerfmonRegisterKeys Remove SubKey failed with %d\n",\r
- GetLastError() );\r
- }\r
-\r
- return reg_status;\r
-}\r
-\r
-\r
-/*\r
- * functions will try to register performance counters\r
- * definitions with PerfMon application.\r
- * API externally called by lodctr.exe/unlodctr.exe utilities.\r
- */\r
-static DWORD\r
-_IBSPPerfmonRegisterCounters( void )\r
-{\r
- DWORD status;\r
- char *ibsp_pm_ini_file = NULL;\r
-\r
- ibsp_pm_ini_file = _IBSPGenerateFileName("unused ", IBSP_PM_INI_FILE);\r
- if( !ibsp_pm_ini_file )\r
- {\r
- fprintf( stderr, "_IBSPGenerateFileName failed\n" );\r
- status = ERROR_NOT_ENOUGH_MEMORY;\r
- goto Cleanup;\r
- }\r
-\r
- /*\r
- * format commandline string, as per SDK :\r
- * Pointer to a null-terminated string that consists of one or more \r
- * arbitrary letters, a space, and then the name of the initialization\r
- * file.\r
- */\r
- status = LoadPerfCounterTextStrings( ibsp_pm_ini_file, TRUE );\r
- if( status != ERROR_SUCCESS )\r
- {\r
- status = GetLastError();\r
- fprintf( stderr,\r
- "IBSPPerfmonRegisterCounters install failed status %d\n", status );\r
- }\r
-Cleanup: \r
- if ( ibsp_pm_ini_file )\r
- {\r
- HeapFree (GetProcessHeap (), 0, ibsp_pm_ini_file);\r
- }\r
-\r
- return status;\r
-}\r
-\r
-\r
-/*\r
- * functions will try to unregister performance counters\r
- * definitions with PerfMon application.\r
- * API externally called by lodctr.exe/unlodctr.exe utilities.\r
- */\r
-static DWORD\r
-_IBSPPerfmonDeregisterCounters( void )\r
-{\r
- DWORD status;\r
-\r
- /*\r
- * format commandline string, as per SDK :\r
- * Pointer to a null-terminated string that consists of one or more \r
- * arbitrary letters, a space, and then the name of the initialization\r
- * file.\r
- */\r
- status = UnloadPerfCounterTextStrings(\r
- TEXT("unused ") TEXT(IBSP_PM_SUBKEY_NAME), TRUE );\r
- if( status != ERROR_SUCCESS )\r
- {\r
- fprintf( stderr,\r
- "IBSPPerfmonDeregisterCounters remove failed status %d\n",\r
- status );\r
- }\r
- return status;\r
-}\r
-\r
-#endif /* PERFMON_ENABLED */\r
-\r
-\r
/*\r
* Function: usage\r
* Description: Prints usage information.\r
usage (char *progname)\r
{\r
printf ("usage: %s [-i/-r [-p]]\n", progname);\r
- printf (" -i Install the service provider\n"\r
- " -r Remove the %s service provider\n"\r
+ printf (" -i Install the OpenFabrics NetworkDirect service provider\n"\r
+ " -r Remove the OpenFabrics NetworkDirect service provider\n"\r
" -r <name> Remove the specified service provider\n"\r
- " -l List service providers\n",VER_PROVIDER);\r
+ " -l List service providers\n");\r
}\r
\r
\r
LONG reg_error;\r
WSAPROTOCOL_INFOW provider;\r
HKEY hkey;\r
- size_t res;\r
- size_t st_len;\r
-\r
- /* Now setup the key. */\r
- reg_error = RegCreateKeyExA( HKEY_LOCAL_MACHINE, winsock_key_path,\r
- 0, NULL, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_READ), NULL,\r
- &hkey, NULL );\r
- if( reg_error == ERROR_SUCCESS )\r
- {\r
- reg_error = RegSetValueExA( hkey, openib_key_name, 0, REG_BINARY,\r
- (PBYTE)&provider_guid, sizeof(GUID) );\r
- if( reg_error == ERROR_SUCCESS )\r
- {\r
- /* Force the system to write the new key now. */\r
- RegFlushKey(hkey);\r
- }\r
- else\r
- {\r
- fprintf(stderr, "RegSetValueEx failed with %d\n", GetLastError());\r
- }\r
-\r
- RegCloseKey(hkey);\r
- }\r
- else\r
- {\r
- fprintf(stderr, "Could not get a handle on Winsock registry (%d)\n", GetLastError());\r
- }\r
\r
/* Setup the values in PROTOCOL_INFO */\r
provider.dwServiceFlags1 = \r
XP1_GUARANTEED_DELIVERY | \r
XP1_GUARANTEED_ORDER | \r
XP1_MESSAGE_ORIENTED |\r
- XP1_GRACEFUL_CLOSE;\r
+ XP1_CONNECT_DATA; /*XP1_GRACEFUL_CLOSE;*/\r
provider.dwServiceFlags2 = 0; /* Reserved */\r
provider.dwServiceFlags3 = 0; /* Reserved */\r
provider.dwServiceFlags4 = 0; /* Reserved */\r
- provider.dwProviderFlags = PFL_HIDDEN;\r
+ provider.dwProviderFlags = PFL_HIDDEN | PFL_NETWORKDIRECT_PROVIDER;\r
provider.ProviderId = provider_guid; /* Service Provider ID provided by vendor. Need to be changed later */\r
provider.dwCatalogEntryId = 0;\r
provider.ProtocolChain.ChainLen = 1; /* Base Protocol Service Provider */\r
- provider.iVersion = 2; /* don't know what it is */\r
+ provider.iVersion = 1;\r
provider.iAddressFamily = AF_INET;\r
provider.iMaxSockAddr = 16;\r
provider.iMinSockAddr = 16;\r
- provider.iSocketType = SOCK_STREAM;\r
- provider.iProtocol = IPPROTO_TCP;\r
+ provider.iSocketType = -1;\r
+ provider.iProtocol = 0;\r
provider.iProtocolMaxOffset = 0;\r
provider.iNetworkByteOrder = BIGENDIAN;\r
provider.iSecurityScheme = SECURITY_PROTOCOL_NONE;\r
provider.dwMessageSize = 0xFFFFFFFF; /* IB supports 32-bit lengths for data transfers on RC */\r
provider.dwProviderReserved = 0;\r
-\r
- st_len = strlen(provider_name);\r
- rc = mbstowcs(provider.szProtocol, provider_name,st_len); //do not count \0\r
- // We can't use there mbstowcs_s \r
- //rc = mbstowcs_s(&convertedChars, provider.szProtocol, sizeof(provider_name), provider_name, );\r
- if (rc != st_len) {\r
- printf("<install_provider> Can't convert string %s to WCHAR\n",provider_name);\r
- printf("Converted %d from %d\n", rc, st_len);\r
- }\r
- wcscpy( provider.szProtocol + st_len, provider_prefix);\r
- //wprintf(L"provider.szProtocol = %s\n",provider.szProtocol);\r
+ wcscpy( provider.szProtocol, provider_name );\r
\r
rc = WSCInstallProvider(\r
&provider_guid, provider_path, &provider, 1, &err_no );\r
LONG reg_error;\r
HKEY hkey;\r
\r
- /* Remove our key */\r
- reg_error = RegOpenKeyExA(HKEY_LOCAL_MACHINE,\r
- winsock_key_path,\r
- 0,\r
- (KEY_WRITE | KEY_READ),\r
- &hkey);\r
- if (reg_error == ERROR_SUCCESS) {\r
-\r
- reg_error = RegDeleteValueA(hkey, provider_name);\r
- if (reg_error == ERROR_SUCCESS) {\r
- /* Force the system to remove the key now. */\r
- RegFlushKey(hkey);\r
- } else {\r
- fprintf(stderr, "RegDeleteValue failed with %d\n", GetLastError());\r
- }\r
-\r
- RegCloseKey(hkey);\r
- }\r
-\r
/* Remove from the catalog */\r
rc = WSCDeinstallProvider(&provider_guid, &err_no);\r
if (rc == SOCKET_ERROR) {\r