/* File netcfgdb.c Implements a database abstraction on top of the net config items needed by the ras server ui for connections. Paul Mayfield, 12/15/97 */ #include #include "protedit.h" // Macro for bounds checking #define netDbBoundsCheck(db, ind) (((ind) < (db)->dwCompCount) ? TRUE : FALSE) // // Defines function that sends pnp event through ndis // typedef UINT (* pNdisHandlePnpEventFunc)( IN UINT Layer, IN UINT Operation, IN PUNICODE_STRING LowerComponent, IN PUNICODE_STRING UpperComponent, IN PUNICODE_STRING BindList, IN PVOID ReConfigBuffer, IN UINT ReConfigBufferSize); // // Maps a protocol string to its integer id // typedef struct _COMP_MAPPING { LPCTSTR pszId; DWORD dwId; } COMP_MAPPING; // // Defines attributes of a network component // typedef struct _RASSRV_NET_COMPONENT { DWORD dwType; // Is it client/service/protocol PWCHAR pszName; // Display name PWCHAR pszDesc; // Display description PWCHAR pszId; // Id to destinguish which client/service, etc BOOL bManip; // Whether is manipulatable by ras (ip, ipx, etc.) BOOL bHasUi; // For whether has properties ui (non-manip only) INetCfgComponent * pINetCfgComp; // The following fields only apply to manipulatable // components (bManip == TRUE) // DWORD dwId; // DWORD counterpart to pszId. BOOL bEnabled; // whether it is enabled for dialin BOOL bEnabledOrig; // original value of bEnabled (optimization) BOOL bExposes; // whether it exposes the network its on LPBYTE pbData; // pointer to protocol specific data BOOL bDataDirty; // should the protocol specific data be flushed? //For whistler bug 347355 // BOOL bRemovable; //If this component removable //TCP/IP is not user removable } RASSRV_NET_COMPONENT; // // Defines attributes of a network component database // typedef struct _RASSRV_COMPONENT_DB { INetCfg * pINetCfg; BOOL bHasINetCfgLock; BOOL bInitCom; DWORD dwCompCount; BOOL bFlushOnClose; RASSRV_NET_COMPONENT ** pComps; PWCHAR pszClientName; INetConnectionUiUtilities * pNetConUtilities; } RASSRV_COMPONENT_DB; // // Definitions of functions taken from ndis // const static WCHAR pszNdispnpLib[] = L"ndispnp.dll"; const static CHAR pszNidspnpFunc[] = "NdisHandlePnPEvent"; // Parameters for the protocols const static WCHAR pszRemoteAccessParamStub[] = L"SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Parameters\\"; static WCHAR pszIpParams[] = L"Ip"; static WCHAR pszIpxParams[] = L"Ipx"; static WCHAR pszNetBuiParams[] = L"Nbf"; static WCHAR pszArapParams[] = L"AppleTalk"; static WCHAR pszShowNetworkToClients[] = L"AllowNetworkAccess"; static WCHAR pszShowNetworkArap[] = L"NetworkAccess"; static WCHAR pszEnableForDialin[] = L"EnableIn"; static WCHAR pszIpPoolSubKey[] = L"\\StaticAddressPool\\0"; // Ip specific registry parameters const static WCHAR pszIpFrom[] = L"From"; const static WCHAR pszIpTo[] = L"To"; const static WCHAR pszIpAddress[] = L"IpAddress"; const static WCHAR pszIpMask[] = L"IpMask"; const static WCHAR pszIpClientSpec[] = L"AllowClientIpAddresses"; const static WCHAR pszIpShowNetworkToClients[] = L"AllowNetworkAccess"; const static WCHAR pszIpUseDhcp[] = L"UseDhcpAddressing"; // Ipx specific registry paramters const static WCHAR pszIpxAddress[] = L"FirstWanNet"; const static WCHAR pszIpxClientSpec[] = L"AcceptRemoteNodeNumber"; const static WCHAR pszIpxAutoAssign[] = L"AutoWanNetAllocation"; const static WCHAR pszIpxAssignSame[] = L"GlobalWanNet"; // Tcp specific registry parameters const static WCHAR pszTcpipParamsKey[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\"; const static WCHAR pszTcpEnableRouter[] = L"IPEnableRouter"; const static WCHAR pszEmptyString[] = L""; // // Initializes a unicode string // VOID SetUnicodeString ( IN OUT UNICODE_STRING* pustr, IN LPCWSTR psz ) { pustr->Buffer = (PWSTR)(psz); pustr->Length = (USHORT)(lstrlenW(pustr->Buffer) * sizeof(WCHAR)); pustr->MaximumLength = pustr->Length + sizeof(WCHAR); } // // Sets the expose property of a protocol // DWORD protSetExpose( IN BOOL bExposes, IN DWORD dwId) { PWCHAR pszProtocol = NULL, pszKey = NULL; PWCHAR pszAccess = pszShowNetworkToClients; DWORD dwErr; WCHAR pszProtKey[1024]; bExposes = (bExposes) ? 1 : 0; // Base the registry location on the // id of the protocol switch (dwId) { case NETCFGDB_ID_IP: pszProtocol = (PWCHAR)pszIpParams; break; case NETCFGDB_ID_IPX: pszProtocol = (PWCHAR)pszIpxParams; break; case NETCFGDB_ID_NETBUI: pszProtocol = (PWCHAR)pszNetBuiParams; break; case NETCFGDB_ID_ARAP: pszProtocol = (PWCHAR)pszArapParams; pszAccess = (PWCHAR)pszShowNetworkArap; break; default: return ERROR_CAN_NOT_COMPLETE; } // Generate the registry key // wsprintfW(pszProtKey, L"%s%s", pszRemoteAccessParamStub, pszProtocol); if (! pszKey) { pszKey = pszProtKey; } // Set the value and return // dwErr = RassrvRegSetDw(bExposes, pszKey, pszAccess); return dwErr; } // // Gets the expose property of a protocol // DWORD protGetExpose( OUT BOOL* pbExposed, IN DWORD dwId) { PWCHAR pszProtocol = NULL, pszKey = NULL; PWCHAR pszAccess = pszShowNetworkToClients; DWORD dwErr; WCHAR pszProtKey[1024]; switch (dwId) { case NETCFGDB_ID_IP: pszProtocol = (PWCHAR)pszIpParams; break; case NETCFGDB_ID_IPX: pszProtocol = (PWCHAR)pszIpxParams; break; case NETCFGDB_ID_NETBUI: pszProtocol = (PWCHAR)pszNetBuiParams; break; case NETCFGDB_ID_ARAP: pszProtocol = (PWCHAR)pszArapParams; pszAccess = (PWCHAR)pszShowNetworkArap; break; default: return ERROR_CAN_NOT_COMPLETE; } // Generate the registry key if needed if (! pszKey) { wsprintfW( pszProtKey, L"%s%s", pszRemoteAccessParamStub, pszProtocol); pszKey = pszProtKey; } // Get the value and return it dwErr = RassrvRegGetDw(pbExposed, TRUE, pszKey, pszAccess); return dwErr; } // // Sets the enable property of a protocol // DWORD protSetEnabling( IN BOOL bExposes, IN DWORD dwId) { PWCHAR pszProtocol = NULL; DWORD dwErr; bExposes = (bExposes) ? 1 : 0; if (dwId == NETCFGDB_ID_IP) { pszProtocol = pszIpParams; } else if (dwId == NETCFGDB_ID_IPX) { pszProtocol = pszIpxParams; } else if (dwId == NETCFGDB_ID_NETBUI) { pszProtocol = pszNetBuiParams; } else if (dwId == NETCFGDB_ID_ARAP) { pszProtocol = pszArapParams; } if (pszProtocol) { WCHAR pszProtKey[512]; wsprintfW( pszProtKey, L"%s%s", pszRemoteAccessParamStub, pszProtocol); dwErr = RassrvRegSetDw(bExposes, pszProtKey, pszEnableForDialin); if (dwErr != NO_ERROR) { DbgOutputTrace( "protSetEnabling: Failed for %S: 0x%08x", pszProtocol, dwErr); } return dwErr; } return ERROR_CAN_NOT_COMPLETE; } // // Gets the Enabling property of a protocol // DWORD protGetEnabling( OUT BOOL* pbExposed, IN DWORD dwId) { PWCHAR pszProtocol = NULL; DWORD dwErr; if (dwId == NETCFGDB_ID_IP) { pszProtocol = pszIpParams; } else if (dwId == NETCFGDB_ID_IPX) { pszProtocol = pszIpxParams; } else if (dwId == NETCFGDB_ID_NETBUI) { pszProtocol = pszNetBuiParams; } else if (dwId == NETCFGDB_ID_ARAP) { pszProtocol = pszArapParams; } if (pszProtocol) { WCHAR pszProtKey[512]; wsprintfW( pszProtKey, L"%s%s", pszRemoteAccessParamStub, pszProtocol); dwErr = RassrvRegGetDw( pbExposed, TRUE, pszProtKey, pszEnableForDialin); if (dwErr != NO_ERROR) { DbgOutputTrace( "protGetEnabling: Failed for %S: 0x%08x", pszProtocol, dwErr); } return dwErr; } return ERROR_CAN_NOT_COMPLETE; } // // Saves the enabling of a service out to the // system. // DWORD svcSetEnabling( IN RASSRV_NET_COMPONENT* pComp) { HANDLE hService = NULL; DWORD dwErr = NO_ERROR; do { // Or enable the component // if (pComp->bEnabled) { if (pComp->dwId == NETCFGDB_ID_FILEPRINT) { // Start the service // dwErr = SvcOpenServer(&hService); if (dwErr != NO_ERROR) { break; } dwErr = SvcStart(hService, 10); if (dwErr != NO_ERROR) { break; } } } } while (FALSE); // Cleanup { if (hService) { SvcClose(hService); } } return dwErr; } // // Gets the enabling property of a service // DWORD svcGetEnabling( OUT BOOL* pbExposed, IN DWORD dwId) { HANDLE hService = NULL; DWORD dwErr = NO_ERROR; do { dwErr = SvcOpenServer(&hService); if (dwErr != NO_ERROR) { break; } dwErr = SvcIsStarted(hService, pbExposed); if (dwErr != NO_ERROR) { break; } } while (FALSE); // Cleanup { if (hService) { SvcClose(hService); } } return dwErr; } // // Loads the tcpip parameters from the system // DWORD TcpipLoadParamsFromSystem( OUT TCPIP_PARAMS *pTcpipParams) { WCHAR buf[256], pszKey[512]; DWORD dwRet = NO_ERROR, dwErr; DWORD dwNet = 0, dwMask = 0; wsprintfW(pszKey, L"%s%s", pszRemoteAccessParamStub, pszIpParams); // Load the params from the various registry locations. dwErr = RassrvRegGetDw( &pTcpipParams->bUseDhcp, TRUE, pszKey, (const PWCHAR)pszIpUseDhcp); if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipLoad: dhcp fail 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegGetDw( &pTcpipParams->bCaller, TRUE, pszKey, (const PWCHAR)pszIpClientSpec); if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipLoad: clientspec fail 0x%08x", dwErr); dwRet = dwErr; } // Read in the "legacy" pool values (w2k RC1, w2k Beta3) // { WCHAR pszNet[256]=L"0.0.0.0", pszMask[256]=L"0.0.0.0"; RassrvRegGetStr( pszNet, L"0.0.0.0", pszKey, (PWCHAR)pszIpAddress); RassrvRegGetStr( pszMask, L"0.0.0.0", pszKey, (PWCHAR)pszIpMask); dwNet = IpPszToHostAddr(pszNet); dwMask = IpPszToHostAddr(pszMask); } // Generate the path the the new registry values // wcscat(pszKey, pszIpPoolSubKey); // See if new info is stored by reading the "from" // value // dwErr = RassrvRegGetDwEx( &pTcpipParams->dwPoolStart, 0, pszKey, (const PWCHAR)pszIpFrom, FALSE); // There is new info in the registry -- use it // if (dwErr == ERROR_SUCCESS) { // Read in the "to" value // dwErr = RassrvRegGetDwEx( &pTcpipParams->dwPoolEnd, 0, pszKey, (const PWCHAR)pszIpTo, FALSE); if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipLoad: mask fail 0x%08x", dwErr); dwRet = dwErr; } } // There is not new data in the new section -- use legacy // values // else if (dwErr == ERROR_FILE_NOT_FOUND) { pTcpipParams->dwPoolStart = dwNet; pTcpipParams->dwPoolEnd = (dwNet + ~dwMask); } // An unexpected error occured // else if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipLoad: pool fail 0x%08x", dwErr); dwRet = dwErr; } return dwRet; } // // Commits the given tcpip parameters to the system. // DWORD TcpipSaveParamsToSystem( IN TCPIP_PARAMS * pTcpipParams) { WCHAR pszKey[512]; DWORD dwRet = NO_ERROR, dwErr; wsprintfW(pszKey, L"%s%s", pszRemoteAccessParamStub, pszIpParams); // Load the params from the various registry locations. dwErr = RassrvRegSetDw( pTcpipParams->bUseDhcp, pszKey, (const PWCHAR)pszIpUseDhcp); if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipSave: dhcp fail 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegSetDw( pTcpipParams->bCaller, pszKey, (const PWCHAR)pszIpClientSpec); if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipSave: callerspec fail 0x%08x", dwErr); dwRet = dwErr; } wcscat(pszKey, pszIpPoolSubKey); dwErr = RassrvRegSetDwEx( pTcpipParams->dwPoolStart, pszKey, (const PWCHAR)pszIpFrom, TRUE); if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipSave: from fail 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegSetDwEx( pTcpipParams->dwPoolEnd, pszKey, (const PWCHAR)pszIpTo, TRUE); if (dwErr != NO_ERROR) { DbgOutputTrace("TcpipSave: to fail 0x%08x", dwErr); dwRet = dwErr; } return dwRet; } // // Loads the ipx parameters from the system // DWORD IpxLoadParamsFromSystem( OUT IPX_PARAMS *pIpxParams) { WCHAR pszKey[512]; DWORD dwRet = NO_ERROR, dwErr; wsprintfW(pszKey, L"%s%s", pszRemoteAccessParamStub, pszIpxParams); // Load the params from the various registry locations. dwErr = RassrvRegGetDw( &pIpxParams->bAutoAssign, TRUE, pszKey, (const PWCHAR)pszIpxAutoAssign); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxLoad: auto-assign fail 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegGetDw( &pIpxParams->bCaller, TRUE, pszKey, (const PWCHAR)pszIpxClientSpec); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxLoad: client-spec fail 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegGetDw( &pIpxParams->dwIpxAddress, 0, pszKey, (const PWCHAR)pszIpxAddress); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxLoad: address fail 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegGetDw( &pIpxParams->bGlobalWan, 0, pszKey, (const PWCHAR)pszIpxAssignSame); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxLoad: same-addr fail 0x%08x", dwErr); dwRet = dwErr; } return dwRet; } // // Commits the given ipx parameters to the system. // DWORD IpxSaveParamsToSystem( IN IPX_PARAMS * pIpxParams) { WCHAR pszKey[512]; DWORD dwRet = NO_ERROR, dwErr; wsprintfW(pszKey, L"%s%s", pszRemoteAccessParamStub, pszIpxParams); // Save params to the various registry locations. dwErr = RassrvRegSetDw( pIpxParams->bAutoAssign, pszKey, (const PWCHAR)pszIpxAutoAssign); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxSave: auto-addr save 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegSetDw( pIpxParams->bCaller, pszKey, (const PWCHAR)pszIpxClientSpec); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxSave: client-spec fail 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegSetDw( pIpxParams->dwIpxAddress, pszKey, (const PWCHAR)pszIpxAddress); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxSave: addr save 0x%08x", dwErr); dwRet = dwErr; } dwErr = RassrvRegSetDw( pIpxParams->bGlobalWan, pszKey, (const PWCHAR)pszIpxAssignSame); if (dwErr != NO_ERROR) { DbgOutputTrace("IpxSave: assign-same fail 0x%08x", dwErr); dwRet = dwErr; } return dwRet; } // // Dialog procedure that handles the editing of generic protocol // information. Dialog proc that governs the ipx settings dialog // INT_PTR CALLBACK GenericProtSettingsDialogProc ( IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { PROT_EDIT_DATA* pEditData = ((PROT_EDIT_DATA*)lParam); // Set the network exposure check SendDlgItemMessage( hwndDlg, CID_NetTab_GenProt_CB_ExposeNetwork, BM_SETCHECK, (pEditData->bExpose) ? BST_CHECKED : BST_UNCHECKED, 0); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); return FALSE; } break; case WM_DESTROY: SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); break; case WM_COMMAND: { PROT_EDIT_DATA * pEditData = (PROT_EDIT_DATA*) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (wParam) { case IDOK: pEditData->bExpose = SendDlgItemMessage( hwndDlg, CID_NetTab_GenProt_CB_ExposeNetwork, BM_GETCHECK, 0, 0) == BST_CHECKED; EndDialog(hwndDlg, 1); break; case IDCANCEL: EndDialog(hwndDlg, 0); break; } } break; } return FALSE; } // // Function edits the properties of a generic protocol, // that is a protocol that has no ras-specific properties. // DWORD GenericProtocolEditProperties( IN HWND hwndParent, IN OUT PROT_EDIT_DATA * pEditData, IN OUT BOOL * pbCommit) { DWORD dwErr; INT_PTR iRet; // Popup the dialog box iRet = DialogBoxParam( Globals.hInstDll, MAKEINTRESOURCE(DID_NetTab_GenProt), hwndParent, GenericProtSettingsDialogProc, (LPARAM)pEditData); // If ok was pressed, save off the new settings *pbCommit = FALSE; if ( (iRet) && (iRet != -1) ) { *pbCommit = TRUE; } return NO_ERROR; } // // Releases resources reserved by this // network component database. // DWORD netDbCleanup( RASSRV_COMPONENT_DB* This) { DWORD i, dwCount; // Free all of the strings if (This->pComps) { for (i = 0; i < This->dwCompCount; i++) { if (This->pComps[i]) { if (This->pComps[i]->pINetCfgComp) { dwCount = INetCfgComponent_Release( This->pComps[i]->pINetCfgComp); DbgOutputTrace( "netDbCleanup: %ls ref=%x", This->pComps[i]->pszId, dwCount); } if (This->pComps[i]->pszName) { CoTaskMemFree(This->pComps[i]->pszName); } if (This->pComps[i]->pszDesc) { CoTaskMemFree(This->pComps[i]->pszDesc); } if (This->pComps[i]->pszId) { CoTaskMemFree(This->pComps[i]->pszId); } RassrvFree(This->pComps[i]); } } RassrvFree(This->pComps); } // Reset all of the values This->dwCompCount = 0; This->pComps = 0; return NO_ERROR; } // // Loads in the netshell library which is responsible for adding // and removing network components // DWORD netDbLoadNetShell ( RASSRV_COMPONENT_DB* This) { if (!This->pNetConUtilities) { HRESULT hr; hr = HrCreateNetConnectionUtilities(&This->pNetConUtilities); if (FAILED(hr)) { DbgOutputTrace("LoadNetShell: loadlib fial 0x%08x", hr); } } return NO_ERROR; } // // Loads protocol specific info for a ras-manipulatable protocol. This // function assumes that the component passed in is a ras-manipulatable // component. (tcpip, ipx, nbf, arap) // DWORD netDbLoadProtcolInfo( IN OUT RASSRV_NET_COMPONENT * pNetComp) { LPBYTE pbData; // Initialize the dirty bit and the data pNetComp->bDataDirty = FALSE; pNetComp->pbData = NULL; // Get the enabled and exposed properties protGetEnabling(&(pNetComp->bEnabled), pNetComp->dwId); protGetExpose(&(pNetComp->bExposes), pNetComp->dwId); pNetComp->bEnabledOrig = pNetComp->bEnabled; // Load protocol specific data // switch (pNetComp->dwId) { case NETCFGDB_ID_IP: pNetComp->pbData = RassrvAlloc(sizeof(TCPIP_PARAMS), TRUE); if (pNetComp->pbData == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } TcpipLoadParamsFromSystem((TCPIP_PARAMS*)(pNetComp->pbData)); break; case NETCFGDB_ID_IPX: pNetComp->pbData = RassrvAlloc(sizeof(IPX_PARAMS), TRUE); if (pNetComp->pbData == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } IpxLoadParamsFromSystem((IPX_PARAMS*)(pNetComp->pbData)); break; } return NO_ERROR; } // // Loads service specific info for a ras-manipulatable service. This // function assumes that the component passed in is a ras-manipulatable // component. // DWORD netDbLoadServiceInfo( IN OUT RASSRV_NET_COMPONENT * pNetComp) { // Get the enabled property // svcGetEnabling(&(pNetComp->bEnabled), pNetComp->dwId); pNetComp->bEnabledOrig = pNetComp->bEnabled; return NO_ERROR; } // // Returns the protol id of the given component // DWORD netDbLoadCompId ( IN OUT RASSRV_NET_COMPONENT * pNetComp) { DWORD i; static const COMP_MAPPING pManipCompMap [] = { { NETCFG_TRANS_CID_MS_TCPIP, NETCFGDB_ID_IP }, { NETCFG_TRANS_CID_MS_NWIPX, NETCFGDB_ID_IPX }, { NETCFG_TRANS_CID_MS_NETBEUI, NETCFGDB_ID_NETBUI }, { NETCFG_TRANS_CID_MS_APPLETALK, NETCFGDB_ID_ARAP }, { NETCFG_SERVICE_CID_MS_SERVER, NETCFGDB_ID_FILEPRINT } }; // See if the id matches any of the protocols that we manage. // pNetComp->dwId = NETCFGDB_ID_OTHER; for (i = 0; i < sizeof(pManipCompMap)/sizeof(*pManipCompMap); i++) { if (lstrcmpi(pNetComp->pszId, pManipCompMap[i].pszId) == 0) { pNetComp->dwId = pManipCompMap[i].dwId; break; } } return pNetComp->dwId; } // // Returns TRUE if this iNetCfg component is not hidden and if // it successfully yeilds it's information. // BOOL netDbGetCompInfo( IN INetCfgComponent * pComponent, IN OUT RASSRV_NET_COMPONENT * pNetComp, IN RASSRV_COMPONENT_DB * pCompDb ) { DWORD dwCharacter; GUID Guid; WCHAR * pszwId = NULL; HRESULT hr = S_OK, hr2; // Make sure that this is not a "hidden" component // hr = INetCfgComponent_GetCharacteristics (pComponent, &dwCharacter); if ( (FAILED(hr)) || (dwCharacter & NCF_HIDDEN) ) { return FALSE; } // //for .Net 605988 filter out IPX, at this point //pNetComp->pszId should be valid // if ( SUCCEEDED(INetCfgComponent_GetId (pComponent, &pszwId) ) ) { WCHAR * pszwTmpId = NULL; pszwTmpId = StrDupWFromT(NETCFG_TRANS_CID_MS_NWIPX); if(pszwTmpId) { if ( 0 == lstrcmpW(pszwId, pszwTmpId)) { Free0(pszwTmpId); CoTaskMemFree(pszwId); return FALSE; } Free0(pszwTmpId); } pszwTmpId = StrDupWFromT( TEXT("ms_nwnb") ); if(pszwTmpId) { if ( 0 == lstrcmpW(pszwId, pszwTmpId)) { Free0(pszwTmpId); CoTaskMemFree(pszwId); return FALSE; } Free0(pszwTmpId); } CoTaskMemFree(pszwId); } // Get the display name hr = INetCfgComponent_GetDisplayName (pComponent, &pNetComp->pszName); if (FAILED(hr)) { return FALSE; } // Assign the has properties value pNetComp->bHasUi = !!(dwCharacter & NCF_HAS_UI); // pmay: 323274 // // Make sure that the component can display properties without // a context if it claims to support displaying properties. // if (pNetComp->bHasUi) { hr2 = INetCfgComponent_RaisePropertyUi( pComponent, GetActiveWindow(), NCRP_QUERY_PROPERTY_UI, NULL); pNetComp->bHasUi = !!(hr2 == S_OK); } // Load the rest of the props if (FAILED(INetCfgComponent_GetClassGuid (pComponent, &Guid)) || FAILED(INetCfgComponent_GetId (pComponent, &pNetComp->pszId)) || FAILED(INetCfgComponent_GetHelpText(pComponent, &pNetComp->pszDesc)) ) { DbgOutputTrace("GetCompInfo: fail %S", pNetComp->pszName); return FALSE; } // Assign the type if (memcmp(&Guid, &GUID_DEVCLASS_NETCLIENT, sizeof(GUID)) == 0) { pNetComp->dwType = NETCFGDB_CLIENT; } else if (memcmp(&Guid, &GUID_DEVCLASS_NETSERVICE, sizeof(GUID)) == 0) { pNetComp->dwType = NETCFGDB_SERVICE; } else { pNetComp->dwType = NETCFGDB_PROTOCOL; } // If this is a protocol that ras server can manipulate, // initailize its additional fields here. pNetComp->dwId = netDbLoadCompId(pNetComp); if (pNetComp->dwId != NETCFGDB_ID_OTHER) { if (pNetComp->dwType == NETCFGDB_PROTOCOL) { netDbLoadProtcolInfo(pNetComp); } else if (pNetComp->dwType == NETCFGDB_SERVICE) { netDbLoadServiceInfo(pNetComp); } pNetComp->bManip = TRUE; } // Assign the inetcfg component pNetComp->pINetCfgComp = pComponent; INetCfgComponent_AddRef(pComponent); //For whistler bug 347355 // { BOOL fEnableRemove=FALSE; DWORD dwFlags; fEnableRemove = INetConnectionUiUtilities_UserHasPermission( pCompDb->pNetConUtilities, NCPERM_AddRemoveComponents); hr = INetCfgComponent_GetCharacteristics(pComponent, &dwFlags ); if( SUCCEEDED(hr) && (NCF_NOT_USER_REMOVABLE & dwFlags) ) { fEnableRemove = FALSE; } pNetComp->bRemovable = fEnableRemove; } return TRUE; } // // Raise the ui for a ras-manipulatable protocol // DWORD netDbRaiseRasProps( IN RASSRV_NET_COMPONENT * pNetComp, IN HWND hwndParent) { PROT_EDIT_DATA ProtEditData; TCPIP_PARAMS TcpParams; IPX_PARAMS IpxParams; BOOL bOk; DWORD dwErr; // Initialize the protocol data properties structure // ProtEditData.bExpose = pNetComp->bExposes; ProtEditData.pbData = NULL; // Launch the appropriate ui switch (pNetComp->dwId) { case NETCFGDB_ID_IP: CopyMemory(&TcpParams, pNetComp->pbData, sizeof(TCPIP_PARAMS)); ProtEditData.pbData = (LPBYTE)(&TcpParams); dwErr = TcpipEditProperties(hwndParent, &ProtEditData, &bOk); if (dwErr != NO_ERROR) { return dwErr; } if (bOk) { pNetComp->bDataDirty = TRUE; CopyMemory( pNetComp->pbData, &TcpParams, sizeof(TCPIP_PARAMS)); pNetComp->bExposes = ProtEditData.bExpose;; } break; case NETCFGDB_ID_IPX: CopyMemory(&IpxParams, pNetComp->pbData, sizeof(IPX_PARAMS)); ProtEditData.pbData = (LPBYTE)(&IpxParams); dwErr = IpxEditProperties(hwndParent, &ProtEditData, &bOk); if (dwErr != NO_ERROR) { return dwErr; } if (bOk) { pNetComp->bDataDirty = TRUE; CopyMemory(pNetComp->pbData, &IpxParams, sizeof(IPX_PARAMS)); pNetComp->bExposes = ProtEditData.bExpose;; } break; default: dwErr = GenericProtocolEditProperties( hwndParent, &ProtEditData, &bOk); if (dwErr != NO_ERROR) { return dwErr; } if (bOk) { pNetComp->bDataDirty = TRUE; pNetComp->bExposes = ProtEditData.bExpose;; } break; } return NO_ERROR; } // // Comparison function used to sort the network components // It's easier to implement here rather than the UI // int __cdecl netDbCompare ( CONST VOID* pElem1, CONST VOID* pElem2) { RASSRV_NET_COMPONENT * pc1 = *((RASSRV_NET_COMPONENT **)pElem1); RASSRV_NET_COMPONENT * pc2 = *((RASSRV_NET_COMPONENT **)pElem2); if (pc1->bManip == pc2->bManip) { if (pc1->bManip == FALSE) { return 0; } if (pc1->dwId == pc2->dwId) { return 0; } else if (pc1->dwId < pc2->dwId) { return -1; } return 1; } else if (pc1->bManip) { return -1; } return 1; } // // Opens the database of network config components // DWORD netDbOpen ( OUT PHANDLE phNetCompDatabase, IN PWCHAR pszClientName) { RASSRV_COMPONENT_DB * This; DWORD dwLength; // Validate parameters if (! phNetCompDatabase || !pszClientName) { return ERROR_INVALID_PARAMETER; } // Allocate the database This = RassrvAlloc (sizeof(RASSRV_COMPONENT_DB), TRUE); if (This == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // Initialize dwLength = wcslen(pszClientName); if (dwLength) { This->pszClientName = RassrvAlloc((dwLength + 1) * sizeof(WCHAR), FALSE); if (This->pszClientName) { wcscpy(This->pszClientName, pszClientName); } } This->bFlushOnClose = FALSE; *phNetCompDatabase = (HANDLE)This; // Load the net shell library netDbLoadNetShell(This); return NO_ERROR; } // // Cleans up all resources held by the database // DWORD netDbClose ( IN HANDLE hNetCompDatabase) { RASSRV_COMPONENT_DB* This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate parameters if (!This) { return ERROR_INVALID_PARAMETER; } // Flush if needed if (This->bFlushOnClose) { netDbFlush(hNetCompDatabase); } else { // If we've made changes to inetcfg that require backing out, // do so now. if (This->pINetCfg) { INetCfg_Cancel(This->pINetCfg); } } netDbCleanup(This); // Free the client name if (This->pszClientName) { RassrvFree(This->pszClientName); } // Release our reference to inetcfg. We will still have it // at this point if a protocol/client/service was added. if (This->pINetCfg) { HrUninitializeAndReleaseINetCfg ( This->bInitCom, This->pINetCfg, This->bHasINetCfgLock); } // Free the netshell library if appropriate if (This->pNetConUtilities) { INetConnectionUiUtilities_Release(This->pNetConUtilities); } // Free this RassrvFree(This); return NO_ERROR; } // Commits all changes to the database to the system DWORD netDbFlush ( IN HANDLE hNetCompDatabase) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; RASSRV_NET_COMPONENT* pComp = NULL; DWORD i; // Validate parameters if (!This) { return ERROR_INVALID_PARAMETER; } // Flush any ras-manipulatable's data if dirty for (i = 0; i < This->dwCompCount; i++) { pComp = This->pComps[i]; // If the enabling of this component has changed, commit // that change if ((pComp->bEnabled != pComp->bEnabledOrig) && (pComp->bManip)) { if (pComp ->dwType == NETCFGDB_PROTOCOL) { protSetEnabling( pComp->bEnabled, pComp->dwId); } else if (pComp->dwType == NETCFGDB_SERVICE) { svcSetEnabling(pComp); } } // If the ras-server-specific properties of the component // have changed, commit the changes. if (pComp->bDataDirty) { protSetExpose(pComp->bExposes, pComp->dwId); switch (pComp->dwId) { case NETCFGDB_ID_IP: { TCPIP_PARAMS* pTcpParams = (TCPIP_PARAMS*)(pComp->pbData); TcpipSaveParamsToSystem(pTcpParams); } break; case NETCFGDB_ID_IPX: { IPX_PARAMS* pIpxParams = (IPX_PARAMS*)(pComp->pbData); IpxSaveParamsToSystem(pIpxParams); } break; } } } // If we have a pointer to the inetcfg instance then we can // commit the changes now if (This->pINetCfg) { INetCfg_Apply(This->pINetCfg); } return NO_ERROR; } // // Loads the net config database for the first time. Because inetcfg // requires time to load and be manipulated, we delay the load of this // database until it is explicitly requested. // DWORD netDbLoad( IN HANDLE hNetCompDatabase) { return netDbReload(hNetCompDatabase); } // // Reloads net information from system // DWORD netDbReload( IN HANDLE hNetCompDatabase) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; DWORD i, j, dwProtCount = 0, dwRefCount; HRESULT hr; RASSRV_NET_COMPONENT TempComp; INetCfgComponent* pComponents [256]; PWCHAR pszName = NULL; static const GUID* c_apguidClasses [] = { &GUID_DEVCLASS_NETTRANS, &GUID_DEVCLASS_NETCLIENT, &GUID_DEVCLASS_NETSERVICE, }; // Validate if (!This) { return ERROR_INVALID_PARAMETER; } DbgOutputTrace( "netDbReload %x %x %x %x %x %x %x %x", This->pINetCfg, This->bHasINetCfgLock, This->bInitCom, This->dwCompCount, This->bFlushOnClose, This->pComps, This->pszClientName, This->pNetConUtilities); // Cleanup any previous values netDbCleanup(This); // If we don't have a reference to inetcfg yet, get it // here. if (This->pINetCfg == NULL) { This->bInitCom = TRUE; This->bHasINetCfgLock = TRUE; hr = HrCreateAndInitializeINetCfg( &This->bInitCom, &This->pINetCfg, TRUE, 0, This->pszClientName, NULL); // Handle error conditions here if (S_FALSE == hr) { return ERROR_CAN_NOT_COMPLETE; } else if (FAILED(hr)) { return ERROR_CAN_NOT_COMPLETE; } } // // Enumerate all of the client and service components in the system. // hr = HrEnumComponentsInClasses ( This->pINetCfg, sizeof(c_apguidClasses) / sizeof(c_apguidClasses[0]), (GUID**)c_apguidClasses, sizeof(pComponents) / sizeof(pComponents[0]), pComponents, &This->dwCompCount); if (!SUCCEEDED(hr)) { return ERROR_CAN_NOT_COMPLETE; } // Initialize the array of internal objects This->pComps = RassrvAlloc ( This->dwCompCount * sizeof (RASSRV_NET_COMPONENT*), TRUE); if (!This->pComps) { return ERROR_NOT_ENOUGH_MEMORY; } // Initialize the installed component array // j = 0; ZeroMemory(&TempComp, sizeof(TempComp)); for (i = 0; i < This->dwCompCount; i++) { pszName = L""; //Add this (RASSRV_COMPONENT_DB *) for whistler bug 347355 // if (netDbGetCompInfo(pComponents[i], &TempComp, This)) { // // Currently we do not support IPv6 for incoming connections. // If this component is IPv6, skip it // if ((TempComp.dwType == NETCFGDB_PROTOCOL) && (lstrcmpi(TempComp.pszId, TEXT("ms_tcpip6")) == 0)) { dwRefCount = INetCfgComponent_Release(pComponents[i]); DbgOutputTrace( "netDbReload: skipping %ls ref=%d", pszName, dwRefCount); continue; } This->pComps[j] = RassrvAlloc (sizeof(RASSRV_NET_COMPONENT), FALSE); if (!This->pComps[j]) { return ERROR_NOT_ENOUGH_MEMORY; } // Fill in the fields CopyMemory(This->pComps[j], &TempComp, sizeof(TempComp)); ZeroMemory(&TempComp, sizeof(TempComp)); if (This->pComps[j]->dwType == NETCFGDB_PROTOCOL) { dwProtCount++; } pszName = This->pComps[j]->pszName; j++; } dwRefCount = INetCfgComponent_Release(pComponents[i]); DbgOutputTrace( "netDbReload: %ls ref=%d", pszName, dwRefCount); } This->dwCompCount = j; // Sort the array. // qsort( This->pComps, This->dwCompCount, sizeof(This->pComps[0]), netDbCompare); return NO_ERROR; } // // Reload the status of a given component // DWORD netDbReloadComponent ( IN HANDLE hNetCompDatabase, IN DWORD dwComponentId) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; RASSRV_NET_COMPONENT* pComp = NULL; DWORD i; // Validate if (!This) { return ERROR_INVALID_PARAMETER; } // Currently, we only need to support the fileprint // component // if (dwComponentId != NETCFGDB_ID_FILEPRINT) { return ERROR_INVALID_PARAMETER; } // Find the appropriate component // for (i = 0; i < This->dwCompCount; i++) { if (This->pComps[i]->dwId == dwComponentId) { pComp = This->pComps[i]; break; } } // Nothing to do if we can't find the component // if (pComp == NULL) { return ERROR_NOT_FOUND; } // Reload the component information // if (dwComponentId == NETCFGDB_ID_FILEPRINT) { svcGetEnabling(&(pComp->bEnabled), NETCFGDB_ID_FILEPRINT); } return NO_ERROR; } // // Reverts the database to the state it was in when opened // DWORD netDbRollback ( IN HANDLE hNetCompDatabase) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; if (!This) { return ERROR_INVALID_PARAMETER; } This->bFlushOnClose = FALSE; return NO_ERROR; } // // Special function denotes whether the network tab has been // loaded // BOOL netDbIsLoaded ( IN HANDLE hNetCompDatabase) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; if (!This) { return ERROR_INVALID_PARAMETER; } return (!!(This->pINetCfg));// || (This->bHasINetCfgLock)); } // // Gets the number of components in the database // DWORD netDbGetCompCount ( IN HANDLE hNetCompDatabase, OUT LPDWORD lpdwCount) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; DWORD i; // Validate parameters if (!This || !lpdwCount) { return ERROR_INVALID_PARAMETER; } *lpdwCount = This->dwCompCount; return NO_ERROR; } // // Returns a pointer to the name of a component (don't alter it) // DWORD netDbGetName( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, OUT PWCHAR* pszName) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate if (!This || !pszName) { return ERROR_INVALID_PARAMETER; } // Bounds check if (!netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } // return the name *pszName = This->pComps[dwIndex]->pszName; return NO_ERROR; } // // Returns a description of a component (don't alter it) // DWORD netDbGetDesc( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, IN PWCHAR* pszName) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate if (!This || !pszName) { return ERROR_INVALID_PARAMETER; } // Bounds check if (!netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } // return the name *pszName = This->pComps[dwIndex]->pszDesc; return NO_ERROR; } // // Returns a type of a component (don't alter it) // DWORD netDbGetType ( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, OUT LPDWORD lpdwType) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate if (!This || !lpdwType) { return ERROR_INVALID_PARAMETER; } // Bounds check if (!netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } // return the name *lpdwType = This->pComps[dwIndex]->dwType; return NO_ERROR; } // // Get a component id // DWORD netDbGetId( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, OUT LPDWORD lpdwId) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate if (!This || !lpdwId) { return ERROR_INVALID_PARAMETER; } // Bounds check if (!netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } // return the name *lpdwId = This->pComps[dwIndex]->dwId; return NO_ERROR; } // // Gets whether the given component is enabled. For non-ras-manipulatable // components, this yields TRUE // DWORD netDbGetEnable( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, OUT PBOOL pbEnabled) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate if (!This || !pbEnabled) { return ERROR_INVALID_PARAMETER; } // Bounds check if (!netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } // return the name if (This->pComps[dwIndex]->bManip) { *pbEnabled = This->pComps[dwIndex]->bEnabled; } else { *pbEnabled = TRUE; } return NO_ERROR; } // // Gets whether the given component is enabled. This function only has // effect on ras-manipulatable components. // DWORD netDbSetEnable( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, IN BOOL bEnabled) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate if (!This) { return ERROR_INVALID_PARAMETER; } // Bounds check if (!netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } // return the name This->pComps[dwIndex]->bEnabled = bEnabled; return NO_ERROR; } // // Returns whether the given network component can // be manipulated by ras server. // DWORD netDbIsRasManipulatable ( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, OUT PBOOL pbManip) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate if (!This || !pbManip) { return ERROR_INVALID_PARAMETER; } // Bounds check if (! netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } // return the name *pbManip = This->pComps[dwIndex]->bManip; return NO_ERROR; } // ////Disable/Enable the Uninstall button for whislter bug 347355 gangz // DWORD netDbHasRemovePermission( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, OUT PBOOL pbHasPermit) { RASSRV_COMPONENT_DB * This = NULL; INetCfgComponent* pComponent = NULL; BOOL fEnableRemove = FALSE; HRESULT hr = S_OK; DWORD dwErr = NO_ERROR, dwFlags; //Disable/Enable Uninstall button according to its user permission and user // removability // do { This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; // Validate pointer if (!This || !pbHasPermit || ( -1 == dwIndex )) { dwErr = ERROR_INVALID_PARAMETER; break; } // Make sure that netshell library has been opened if (!This->pNetConUtilities) { dwErr = ERROR_CAN_NOT_COMPLETE; break; } if (dwIndex >= This->dwCompCount) { dwErr = ERROR_CAN_NOT_COMPLETE; break; } ASSERT(This->pComps[dwIndex]); if( !(This->pComps[dwIndex]) ) { dwErr = ERROR_CAN_NOT_COMPLETE; break; } fEnableRemove = This->pComps[dwIndex]->bRemovable; *pbHasPermit = fEnableRemove; } while(FALSE); return dwErr; } // // Returns whether the given network component has // a properties ui that it can raise // DWORD netDbHasPropertiesUI( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, OUT PBOOL pbHasUi) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; RASSRV_NET_COMPONENT* pComp = NULL; // Validate if (!This || !pbHasUi) { return ERROR_INVALID_PARAMETER; } // Bounds check if (!netDbBoundsCheck(This, dwIndex)) { return ERROR_INVALID_INDEX; } pComp = This->pComps[dwIndex]; if ((pComp->bManip) && (pComp->dwType == NETCFGDB_PROTOCOL)) { *pbHasUi = TRUE; } else { *pbHasUi = pComp->bHasUi; } return NO_ERROR; } // // Raises the properties of the component at the given index // DWORD netDbRaisePropertiesDialog ( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, IN HWND hwndParent) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; RASSRV_NET_COMPONENT* pComp = NULL; // Validate if (!This) { return ERROR_INVALID_PARAMETER; } // Bounds check if (dwIndex >= This->dwCompCount) { return ERROR_INVALID_INDEX; } pComp = This->pComps[dwIndex]; // If this is a ras-manipulatable protocol, raise its // properties manually. if ((pComp->bManip) && (pComp->dwType == NETCFGDB_PROTOCOL)) { netDbRaiseRasProps(This->pComps[dwIndex], hwndParent); } // Otherwise, let inetcfg do the work else { return INetCfgComponent_RaisePropertyUi ( pComp->pINetCfgComp, hwndParent, NCRP_SHOW_PROPERTY_UI, NULL); } return NO_ERROR; } // // Brings up the UI that allows a user to install a component // DWORD netDbRaiseInstallDialog( IN HANDLE hNetCompDatabase, IN HWND hwndParent) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; HRESULT hr = S_OK; // For whistler 524777 // Validate if (!This) { return ERROR_INVALID_PARAMETER; } // Make sure that netshell library has been opened if (!This->pNetConUtilities) { return ERROR_CAN_NOT_COMPLETE; } else { // If we have our pointer to the function used to bring up the add // component dialog (obtained above only once), call it. // We want to filter out protocols that RAS does not care about // We do this by sending in a CI_FILTER_INFO structure indicating // we want non-RAS protocols filtered out // CI_FILTER_INFO cfi = {0}; cfi.eFilter = FC_RASSRV; hr = INetConnectionUiUtilities_DisplayAddComponentDialog( This->pNetConUtilities, hwndParent, This->pINetCfg, &cfi); // Ui will handle reboot if (hr == NETCFG_S_REBOOT) { netDbReload(hNetCompDatabase); return hr; } // If the user didn't cancel, refresh the database. if (S_FALSE != hr) { if (SUCCEEDED (hr)) { netDbReload(hNetCompDatabase); return NO_ERROR; } else { return hr; } } } return ERROR_CANCELLED; } // // Uninstalls the given component // DWORD netDbRaiseRemoveDialog ( IN HANDLE hNetCompDatabase, IN DWORD dwIndex, IN HWND hwndParent) { RASSRV_COMPONENT_DB * This = (RASSRV_COMPONENT_DB*)hNetCompDatabase; HRESULT hr; // Validate if (!This) { return ERROR_INVALID_PARAMETER; } // Make sure that netshell library has been opened if (!This->pNetConUtilities) { return ERROR_CAN_NOT_COMPLETE; } // If we have our pointer to the function used to bring up the add // component dialog (obtained above only once), call it. if (dwIndex < This->dwCompCount) { if (This->pComps[dwIndex]->pINetCfgComp) { hr = INetConnectionUiUtilities_QueryUserAndRemoveComponent( This->pNetConUtilities, hwndParent, This->pINetCfg, This->pComps[dwIndex]->pINetCfgComp); // Ui will handle reboot if (hr == NETCFG_S_REBOOT) { netDbReload(hNetCompDatabase); return hr; } // If the user didn't cancel, refresh the database. else if (S_FALSE != hr) { if (SUCCEEDED (hr)) { netDbReload(hNetCompDatabase); return NO_ERROR; } else { return hr; } } } } return ERROR_CANCELLED; }