Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

893 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. confaddr.cpp
  5. Abstract:
  6. This module contains implementation of CIPConfMSP.
  7. Author:
  8. Mu Han (muhan) 5-September-1997
  9. --*/
  10. #include "stdafx.h"
  11. #include "common.h"
  12. #ifdef USEIPADDRTABLE
  13. #include <iprtrmib.h>
  14. typedef DWORD (WINAPI * PFNGETIPADDRTABLE)(
  15. OUT PMIB_IPADDRTABLE pIPAddrTable,
  16. IN OUT PDWORD pdwSize,
  17. IN BOOL bOrder
  18. );
  19. #define IPHLPAPI_DLL L"IPHLPAPI.DLL"
  20. #define GETIPADDRTABLE "GetIpAddrTable"
  21. #define IsValidInterface(_dwAddr_) \
  22. (((_dwAddr_) != 0) && \
  23. ((_dwAddr_) != htonl(INADDR_LOOPBACK)))
  24. #endif
  25. #define IPCONF_WINSOCKVERSION MAKEWORD(2,0)
  26. HRESULT CIPConfMSP::FinalConstruct()
  27. {
  28. // initialize winsock stack
  29. WSADATA wsaData;
  30. if (WSAStartup(IPCONF_WINSOCKVERSION, &wsaData) != 0)
  31. {
  32. LOG((MSP_ERROR, "WSAStartup failed with:%x", WSAGetLastError()));
  33. return E_FAIL;
  34. }
  35. // allocate control socket
  36. m_hSocket = WSASocket(
  37. AF_INET, // af
  38. SOCK_DGRAM, // type
  39. IPPROTO_IP, // protocol
  40. NULL, // lpProtocolInfo
  41. 0, // g
  42. 0 // dwFlags
  43. );
  44. // validate handle
  45. if (m_hSocket == INVALID_SOCKET) {
  46. LOG((
  47. MSP_ERROR,
  48. "error %d creating control socket.\n",
  49. WSAGetLastError()
  50. ));
  51. // failure
  52. WSACleanup();
  53. return E_FAIL;
  54. }
  55. HRESULT hr = CMSPAddress::FinalConstruct();
  56. if (hr != S_OK)
  57. {
  58. // close socket
  59. closesocket(m_hSocket);
  60. // shutdown
  61. WSACleanup();
  62. }
  63. return hr;
  64. }
  65. void CIPConfMSP::FinalRelease()
  66. {
  67. CMSPAddress::FinalRelease();
  68. if (m_hSocket != INVALID_SOCKET)
  69. {
  70. // close socket
  71. closesocket(m_hSocket);
  72. }
  73. // shutdown
  74. WSACleanup();
  75. }
  76. DWORD CIPConfMSP::FindLocalInterface(DWORD dwIP)
  77. {
  78. SOCKADDR_IN DestAddr;
  79. DestAddr.sin_family = AF_INET;
  80. DestAddr.sin_port = 0;
  81. DestAddr.sin_addr.s_addr = htonl(dwIP);
  82. SOCKADDR_IN LocAddr;
  83. // query for default address based on destination
  84. DWORD dwStatus;
  85. DWORD dwLocAddrSize = sizeof(SOCKADDR_IN);
  86. DWORD dwNumBytesReturned = 0;
  87. if ((dwStatus = WSAIoctl(
  88. m_hSocket, // SOCKET s
  89. SIO_ROUTING_INTERFACE_QUERY, // DWORD dwIoControlCode
  90. &DestAddr, // LPVOID lpvInBuffer
  91. sizeof(SOCKADDR_IN), // DWORD cbInBuffer
  92. &LocAddr, // LPVOID lpvOUTBuffer
  93. dwLocAddrSize, // DWORD cbOUTBuffer
  94. &dwNumBytesReturned, // LPDWORD lpcbBytesReturned
  95. NULL, // LPWSAOVERLAPPED lpOverlapped
  96. NULL // LPWSAOVERLAPPED_COMPLETION_ROUTINE lpComplROUTINE
  97. )) == SOCKET_ERROR)
  98. {
  99. dwStatus = WSAGetLastError();
  100. LOG((MSP_ERROR, "WSAIoctl failed: %d (0x%X)", dwStatus, dwStatus));
  101. return INADDR_NONE;
  102. }
  103. DWORD dwAddr = ntohl(LocAddr.sin_addr.s_addr);
  104. if (dwAddr == 0x7f000001)
  105. {
  106. // it is loopback address, just return none.
  107. return INADDR_NONE;
  108. }
  109. return dwAddr;
  110. }
  111. STDMETHODIMP CIPConfMSP::CreateTerminal(
  112. IN BSTR pTerminalClass,
  113. IN long lMediaType,
  114. IN TERMINAL_DIRECTION Direction,
  115. OUT ITTerminal ** ppTerminal
  116. )
  117. /*++
  118. Routine Description:
  119. This method is called by TAPI3 to create a dynamic terminal. It asks the
  120. terminal manager to create a dynamic terminal.
  121. Arguments:
  122. iidTerminalClass
  123. IID of the terminal class to be created.
  124. dwMediaType
  125. TAPI media type of the terminal to be created.
  126. Direction
  127. Terminal direction of the terminal to be created.
  128. ppTerminal
  129. Returned created terminal object
  130. Return Value:
  131. S_OK
  132. E_OUTOFMEMORY
  133. TAPI_E_INVALIDMEDIATYPE
  134. TAPI_E_INVALIDTERMINALDIRECTION
  135. TAPI_E_INVALIDTERMINALCLASS
  136. --*/
  137. {
  138. LOG((MSP_TRACE,
  139. "CIPConfMSP::CreateTerminal - enter"));
  140. //
  141. // Check if initialized.
  142. //
  143. // lock the event related data
  144. m_EventDataLock.Lock();
  145. if ( m_htEvent == NULL )
  146. {
  147. // unlock the event related data
  148. m_EventDataLock.Unlock();
  149. LOG((MSP_ERROR,
  150. "CIPConfMSP::CreateTerminal - "
  151. "not initialized - returning E_UNEXPECTED"));
  152. return E_UNEXPECTED;
  153. }
  154. // unlock the event related data
  155. m_EventDataLock.Unlock();
  156. //
  157. // Get the IID from the BSTR representation.
  158. //
  159. HRESULT hr;
  160. IID iidTerminalClass;
  161. hr = CLSIDFromString(pTerminalClass, &iidTerminalClass);
  162. if ( FAILED(hr) )
  163. {
  164. LOG((MSP_ERROR, "CIPConfMSP::CreateTerminal - "
  165. "bad CLSID string - returning E_INVALIDARG"));
  166. return E_INVALIDARG;
  167. }
  168. //
  169. // Make sure we support the requested media type.
  170. // The terminal manager checks the terminal class, terminal direction,
  171. // and return pointer.
  172. //
  173. if ( ! IsValidSingleMediaType( (DWORD) lMediaType, GetCallMediaTypes() ) )
  174. {
  175. LOG((MSP_ERROR, "CIPConfMSP::CreateTerminal - "
  176. "non-audio terminal requested - returning E_INVALIDARG"));
  177. return E_INVALIDARG;
  178. }
  179. //
  180. // Use the terminal manager to create the dynamic terminal.
  181. //
  182. _ASSERTE( m_pITTerminalManager != NULL );
  183. hr = m_pITTerminalManager->CreateDynamicTerminal(NULL,
  184. iidTerminalClass,
  185. (DWORD) lMediaType,
  186. Direction,
  187. (MSP_HANDLE) this,
  188. ppTerminal);
  189. if ( FAILED(hr) )
  190. {
  191. LOG((MSP_ERROR, "CIPConfMSP::CreateTerminal - "
  192. "create dynamic terminal failed - returning 0x%08x", hr));
  193. return hr;
  194. }
  195. if ((iidTerminalClass == CLSID_MediaStreamTerminal)
  196. && (lMediaType == TAPIMEDIATYPE_AUDIO))
  197. {
  198. // Set the format of the audio to 8KHZ, 16Bit/Sample, MONO.
  199. hr = ::SetAudioFormat(
  200. *ppTerminal,
  201. g_wAudioCaptureBitPerSample,
  202. g_dwG711AudioSampleRate
  203. );
  204. if (FAILED(hr))
  205. {
  206. LOG((MSP_WARN, "can't set audio format, %x", hr));
  207. }
  208. }
  209. LOG((MSP_TRACE, "CIPConfMSP::CreateTerminal - exit S_OK"));
  210. return S_OK;
  211. }
  212. STDMETHODIMP CIPConfMSP::CreateMSPCall(
  213. IN MSP_HANDLE htCall,
  214. IN DWORD dwReserved,
  215. IN DWORD dwMediaType,
  216. IN IUnknown * pOuterUnknown,
  217. OUT IUnknown ** ppMSPCall
  218. )
  219. /*++
  220. Routine Description:
  221. This method is called by TAPI3 before a call is made or answered. It creates
  222. a aggregated MSPCall object and returns the IUnknown pointer. It calls the
  223. helper template function defined in mspaddress.h to handle the real creation.
  224. Arguments:
  225. htCall
  226. TAPI 3.0's identifier for this call. Returned in events passed back
  227. to TAPI.
  228. dwReserved
  229. Reserved parameter. Not currently used.
  230. dwMediaType
  231. Media type of the call being created. These are TAPIMEDIATYPES and more
  232. than one mediatype can be selected (bitwise).
  233. pOuterUnknown
  234. pointer to the IUnknown interface of the containing object.
  235. ppMSPCall
  236. Returned MSP call that the MSP fills on on success.
  237. Return Value:
  238. S_OK
  239. E_OUTOFMEMORY
  240. E_POINTER
  241. TAPI_E_INVALIDMEDIATYPE
  242. --*/
  243. {
  244. LOG((MSP_TRACE,
  245. "CreateMSPCall entered. htCall:%x, dwMediaType:%x, ppMSPCall:%x",
  246. htCall, dwMediaType, ppMSPCall
  247. ));
  248. CIPConfMSPCall * pMSPCall = NULL;
  249. HRESULT hr = ::CreateMSPCallHelper(
  250. this,
  251. htCall,
  252. dwReserved,
  253. dwMediaType,
  254. pOuterUnknown,
  255. ppMSPCall,
  256. &pMSPCall
  257. );
  258. if (FAILED(hr))
  259. {
  260. LOG((MSP_ERROR, "CreateMSPCallHelper failed:%x", hr));
  261. return hr;
  262. }
  263. // this function doesn't return anything.
  264. pMSPCall->SetIPInterface(m_dwIPInterface);
  265. return hr;
  266. }
  267. STDMETHODIMP CIPConfMSP::ShutdownMSPCall(
  268. IN IUnknown * pUnknown
  269. )
  270. /*++
  271. Routine Description:
  272. This method is called by TAPI3 to shutdown a MSPCall. It calls the helper
  273. function defined in MSPAddress to to the real job.
  274. Arguments:
  275. pUnknown
  276. pointer to the IUnknown interface of the contained object. It is a
  277. CComAggObject that contains our call object.
  278. Return Value:
  279. S_OK
  280. E_POINTER
  281. TAPI_E_INVALIDMEDIATYPE
  282. --*/
  283. {
  284. LOG((MSP_TRACE, "ShutDownMSPCall entered. pUnknown:%x", pUnknown));
  285. if (IsBadReadPtr(pUnknown, sizeof(VOID *) * 3))
  286. {
  287. LOG((MSP_ERROR, "ERROR:pUnknow is a bad pointer"));
  288. return E_POINTER;
  289. }
  290. CIPConfMSPCall * pMSPCall = NULL;
  291. HRESULT hr = ::ShutdownMSPCallHelper(pUnknown, &pMSPCall);
  292. if (FAILED(hr))
  293. {
  294. LOG((MSP_ERROR, "ShutDownMSPCallhelper failed:: %x", hr));
  295. return hr;
  296. }
  297. return hr;
  298. }
  299. DWORD CIPConfMSP::GetCallMediaTypes(void)
  300. {
  301. return IPCONFCALLMEDIATYPES;
  302. }
  303. ULONG CIPConfMSP::MSPAddressAddRef(void)
  304. {
  305. return MSPAddRefHelper(this);
  306. }
  307. ULONG CIPConfMSP::MSPAddressRelease(void)
  308. {
  309. return MSPReleaseHelper(this);
  310. }
  311. #ifdef USEIPADDRTABLE
  312. PMIB_IPADDRTABLE GetIPTable()
  313. /*++
  314. Routine Description:
  315. This method is used to get the table of local IP interfaces.
  316. Arguments:
  317. Return Value:
  318. NULL - failed.
  319. Pointer - a memory buffer that contains the IP interface table.
  320. --*/
  321. {
  322. // dynamically load iphlpapi.dll
  323. HMODULE hIPHLPAPI = LoadLibraryW(IPHLPAPI_DLL);
  324. // validate handle
  325. if (hIPHLPAPI == NULL)
  326. {
  327. LOG((MSP_ERROR, "could not load %s.\n", IPHLPAPI_DLL));
  328. // failure
  329. return NULL;
  330. }
  331. PFNGETIPADDRTABLE pfnGetIpAddrTable = NULL;
  332. // retrieve function pointer to retrieve addresses
  333. pfnGetIpAddrTable = (PFNGETIPADDRTABLE)GetProcAddress(
  334. hIPHLPAPI,
  335. GETIPADDRTABLE
  336. );
  337. // validate function pointer
  338. if (pfnGetIpAddrTable == NULL)
  339. {
  340. LOG((MSP_ERROR, "could not resolve GetIpAddrTable.\n"));
  341. // release
  342. FreeLibrary(hIPHLPAPI);
  343. // failure
  344. return NULL;
  345. }
  346. PMIB_IPADDRTABLE pIPAddrTable = NULL;
  347. DWORD dwBytesRequired = 0;
  348. DWORD dwStatus;
  349. // determine amount of memory needed for table
  350. dwStatus = (*pfnGetIpAddrTable)(pIPAddrTable, &dwBytesRequired, FALSE);
  351. // validate status is what we expect
  352. if (dwStatus != ERROR_INSUFFICIENT_BUFFER)
  353. {
  354. LOG((MSP_ERROR, "error 0x%08lx calling GetIpAddrTable.\n", dwStatus));
  355. // release
  356. FreeLibrary(hIPHLPAPI);
  357. // failure, but we need to return true to load.
  358. return NULL;
  359. }
  360. // attempt to allocate memory for table
  361. pIPAddrTable = (PMIB_IPADDRTABLE)malloc(dwBytesRequired);
  362. // validate pointer
  363. if (pIPAddrTable == NULL)
  364. {
  365. LOG((MSP_ERROR, "could not allocate address table.\n"));
  366. // release
  367. FreeLibrary(hIPHLPAPI);
  368. // failure, but we need to return true to load.
  369. return NULL;
  370. }
  371. // retrieve ip address table from tcp/ip stack via utitity library
  372. dwStatus = (*pfnGetIpAddrTable)(pIPAddrTable, &dwBytesRequired, FALSE);
  373. // validate status
  374. if (dwStatus != NOERROR)
  375. {
  376. LOG((MSP_ERROR, "error 0x%08lx calling GetIpAddrTable.\n", dwStatus));
  377. // release table
  378. free(pIPAddrTable);
  379. // release
  380. FreeLibrary(hIPHLPAPI);
  381. // failure, but we need to return true to load.
  382. return NULL;
  383. }
  384. // release library
  385. FreeLibrary(hIPHLPAPI);
  386. return pIPAddrTable;
  387. }
  388. BSTR IPToBstr(
  389. DWORD dwIP
  390. )
  391. {
  392. struct in_addr Addr;
  393. Addr.s_addr = dwIP;
  394. // convert the interface to a string.
  395. CHAR *pChar = inet_ntoa(Addr);
  396. if (pChar == NULL)
  397. {
  398. LOG((MSP_ERROR, "bad IP address:%x", dwIP));
  399. return NULL;
  400. }
  401. // convert the ascii string to WCHAR.
  402. WCHAR szAddressName[MAXIPADDRLEN + 1];
  403. wsprintfW(szAddressName, L"%hs", pChar);
  404. // create a BSTR.
  405. BSTR bAddress = SysAllocString(szAddressName);
  406. if (bAddress == NULL)
  407. {
  408. LOG((MSP_ERROR, "out of mem in allocation address name"));
  409. return NULL;
  410. }
  411. return bAddress;
  412. }
  413. STDMETHODIMP CIPConfMSP::get_DefaultIPInterface(
  414. OUT BSTR * ppIPAddress
  415. )
  416. {
  417. LOG((MSP_TRACE, "get_DefaultIPInterface, ppIPAddress:%p", ppIPAddress));
  418. if (IsBadWritePtr(ppIPAddress, sizeof(BSTR)))
  419. {
  420. LOG((MSP_ERROR,
  421. "get_DefaultIPInterface, ppIPAddress is bad:%p", ppIPAddress));
  422. return E_POINTER;
  423. }
  424. // get the current local interface.
  425. m_Lock.Lock();
  426. DWORD dwIP= m_dwIPInterface;
  427. m_Lock.Unlock();
  428. BSTR bAddress = IPToBstr(dwIP);
  429. if (bAddress == NULL)
  430. {
  431. return E_OUTOFMEMORY;
  432. }
  433. *ppIPAddress = bAddress;
  434. LOG((MSP_TRACE, "get_DefaultIPInterface, returning %ws", bAddress));
  435. return S_OK;
  436. }
  437. STDMETHODIMP CIPConfMSP::put_DefaultIPInterface(
  438. IN BSTR pIPAddress
  439. )
  440. {
  441. LOG((MSP_TRACE, "put_DefaultIPInterface, pIPAddress:%p", pIPAddress));
  442. if (IsBadStringPtrW(pIPAddress, MAXIPADDRLEN))
  443. {
  444. LOG((MSP_ERROR,
  445. "put_DefaultIPInterface, invalid pointer:%p", pIPAddress));
  446. return E_POINTER;
  447. }
  448. char buffer[MAXIPADDRLEN + 1];
  449. if (WideCharToMultiByte(
  450. GetACP(),
  451. 0,
  452. pIPAddress,
  453. -1,
  454. buffer,
  455. MAXIPADDRLEN,
  456. NULL,
  457. NULL
  458. ) == 0)
  459. {
  460. LOG((MSP_ERROR, "put_DefaultIPInterface, can't covert:%ws", pIPAddress));
  461. return E_INVALIDARG;
  462. }
  463. DWORD dwAddr;
  464. if ((dwAddr = inet_addr(buffer)) == INADDR_NONE)
  465. {
  466. LOG((MSP_ERROR, "put_DefaultIPInterface, bad address:%s", buffer));
  467. return E_INVALIDARG;
  468. }
  469. // set the current local interface.
  470. m_Lock.Lock();
  471. m_dwIPInterface = dwAddr;
  472. m_Lock.Unlock();
  473. LOG((MSP_TRACE, "put_DefaultIPInterface, set to %s", buffer));
  474. return S_OK;
  475. }
  476. HRESULT CreateBstrCollection(
  477. IN BSTR * pBstr,
  478. IN DWORD dwCount,
  479. OUT VARIANT * pVariant
  480. )
  481. {
  482. //
  483. // create the collection object - see mspcoll.h
  484. //
  485. CComObject<CTapiBstrCollection> * pCollection;
  486. HRESULT hr = CComObject<CTapiBstrCollection>::CreateInstance( &pCollection );
  487. if ( FAILED(hr) )
  488. {
  489. LOG((MSP_ERROR, "get_IPInterfaces - "
  490. "can't create collection - exit 0x%08x", hr));
  491. return hr;
  492. }
  493. //
  494. // get the Collection's IDispatch interface
  495. //
  496. IDispatch * pDispatch;
  497. hr = pCollection->_InternalQueryInterface(IID_IDispatch,
  498. (void **) &pDispatch );
  499. if ( FAILED(hr) )
  500. {
  501. LOG((MSP_ERROR, "get_IPInterfaces - "
  502. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  503. delete pCollection;
  504. return hr;
  505. }
  506. //
  507. // Init the collection using an iterator -- pointers to the beginning and
  508. // the ending element plus one.
  509. //
  510. hr = pCollection->Initialize( dwCount,
  511. pBstr,
  512. pBstr + dwCount);
  513. if ( FAILED(hr) )
  514. {
  515. LOG((MSP_ERROR, "get_IPInterfaces - "
  516. "Initialize on collection failed - exit 0x%08x", hr));
  517. pDispatch->Release();
  518. return hr;
  519. }
  520. //
  521. // put the IDispatch interface pointer into the variant
  522. //
  523. LOG((MSP_ERROR, "get_IPInterfaces - "
  524. "placing IDispatch value %08x in variant", pDispatch));
  525. VariantInit(pVariant);
  526. pVariant->vt = VT_DISPATCH;
  527. pVariant->pdispVal = pDispatch;
  528. LOG((MSP_TRACE, "get_IPInterfaces - exit S_OK"));
  529. return S_OK;
  530. }
  531. STDMETHODIMP CIPConfMSP::get_IPInterfaces(
  532. OUT VARIANT * pVariant
  533. )
  534. {
  535. PMIB_IPADDRTABLE pIPAddrTable = GetIPTable();
  536. if (pIPAddrTable == NULL)
  537. {
  538. return E_FAIL;
  539. }
  540. BSTR *Addresses =
  541. (BSTR *)malloc(sizeof(BSTR *) * pIPAddrTable->dwNumEntries);
  542. if (Addresses == NULL)
  543. {
  544. return E_OUTOFMEMORY;
  545. }
  546. HRESULT hr = S_OK;
  547. DWORD dwCount = 0;
  548. // loop through the interfaces and find the valid ones.
  549. for (DWORD i = 0; i < pIPAddrTable->dwNumEntries; i++)
  550. {
  551. if (IsValidInterface(pIPAddrTable->table[i].dwAddr))
  552. {
  553. DWORD dwIPAddr = ntohl(pIPAddrTable->table[i].dwAddr);
  554. Addresses[i] = IPToBstr(dwIPAddr);
  555. if (Addresses[i] == NULL)
  556. {
  557. hr = E_OUTOFMEMORY;
  558. break;
  559. }
  560. }
  561. }
  562. // release table memory
  563. free(pIPAddrTable);
  564. if (FAILED(hr))
  565. {
  566. // release all the BSTRs and the array.
  567. for (i = 0; i < dwCount; i ++)
  568. {
  569. SysFreeString(Addresses[i]);
  570. }
  571. free(Addresses);
  572. return hr;
  573. }
  574. hr = CreateBstrCollection(Addresses, dwCount, pVariant);
  575. // if the collection is not created, release all the BSTRs.
  576. if (FAILED(hr))
  577. {
  578. for (i = 0; i < dwCount; i ++)
  579. {
  580. SysFreeString(Addresses[i]);
  581. }
  582. }
  583. // delete the pointer array.
  584. free(Addresses);
  585. return hr;
  586. }
  587. HRESULT CreateBstrEnumerator(
  588. IN BSTR * begin,
  589. IN BSTR * end,
  590. OUT IEnumBstr ** ppIEnum
  591. )
  592. {
  593. typedef CSafeComEnum<IEnumBstr, &IID_IEnumBstr, BSTR, _CopyBSTR>> CEnumerator;
  594. HRESULT hr;
  595. CComObject<CEnumerator> *pEnum = NULL;
  596. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  597. if (pEnum == NULL)
  598. {
  599. LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
  600. return hr;
  601. }
  602. IEnumBstr * pIEnum;
  603. // query for the IID_IEnumDirectory i/f
  604. hr = pEnum->_InternalQueryInterface(
  605. IID_IEnumBstr,
  606. (void**)&pIEnum
  607. );
  608. if (FAILED(hr))
  609. {
  610. LOG((MSP_ERROR, "query enum interface failed, %x", hr));
  611. delete pEnum;
  612. return hr;
  613. }
  614. hr = pEnum->Init(begin, end, NULL, AtlFlagTakeOwnership);
  615. if (FAILED(hr))
  616. {
  617. LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
  618. pIEnum->Release();
  619. return hr;
  620. }
  621. *ppIEnum = pIEnum;
  622. return hr;
  623. }
  624. STDMETHODIMP CIPConfMSP::EnumerateIPInterfaces(
  625. OUT IEnumBstr ** ppIEnumBstr
  626. )
  627. {
  628. PMIB_IPADDRTABLE pIPAddrTable = GetIPTable();
  629. if (pIPAddrTable == NULL)
  630. {
  631. return E_FAIL;
  632. }
  633. BSTR *Addresses =
  634. (BSTR *)malloc(sizeof(BSTR *) * pIPAddrTable->dwNumEntries);
  635. if (Addresses == NULL)
  636. {
  637. return E_OUTOFMEMORY;
  638. }
  639. HRESULT hr = S_OK;
  640. DWORD dwCount = 0;
  641. // loop through the interfaces and find the valid ones.
  642. for (DWORD i = 0; i < pIPAddrTable->dwNumEntries; i++)
  643. {
  644. if (IsValidInterface(pIPAddrTable->table[i].dwAddr))
  645. {
  646. DWORD dwIPAddr = ntohl(pIPAddrTable->table[i].dwAddr);
  647. Addresses[i] = IPToBstr(dwIPAddr);
  648. if (Addresses[i] == NULL)
  649. {
  650. hr = E_OUTOFMEMORY;
  651. break;
  652. }
  653. }
  654. }
  655. // release table memory
  656. free(pIPAddrTable);
  657. if (FAILED(hr))
  658. {
  659. // release all the BSTRs and the array.
  660. for (i = 0; i < dwCount; i ++)
  661. {
  662. SysFreeString(Addresses[i]);
  663. }
  664. free(Addresses);
  665. return hr;
  666. }
  667. hr = CreateBstrEnumerator(Addresses, Addresses + dwCount, ppIEnumBstr);
  668. // if the collection is not created, release all the BSTRs.
  669. if (FAILED(hr))
  670. {
  671. for (i = 0; i < dwCount; i ++)
  672. {
  673. SysFreeString(Addresses[i]);
  674. }
  675. free(Addresses);
  676. return hr;
  677. }
  678. // the enumerator will destroy the bstr array eventually,
  679. // so no need to free anything here. Even if we tell it to hand
  680. // out zero objects, it will delete the array on destruction.
  681. return hr;
  682. }
  683. #endif