Leaked source code of windows server 2003
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.

1657 lines
41 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 <initguid.h>
  12. DEFINE_GUID(CLSID_IPConfMSP, 0x0F1BE7F7, 0x45CA, 0x11d2,
  13. 0x83, 0x1F, 0x0, 0xA0, 0x24, 0x4D, 0x22, 0x98);
  14. #ifdef USEIPADDRTABLE
  15. #include <iprtrmib.h>
  16. typedef DWORD (WINAPI * PFNGETIPADDRTABLE)(
  17. OUT PMIB_IPADDRTABLE pIPAddrTable,
  18. IN OUT PDWORD pdwSize,
  19. IN BOOL bOrder
  20. );
  21. #define IPHLPAPI_DLL L"IPHLPAPI.DLL"
  22. #define GETIPADDRTABLE "GetIpAddrTable"
  23. #define IsValidInterface(_dwAddr_) \
  24. (((_dwAddr_) != 0) && \
  25. ((_dwAddr_) != htonl(INADDR_LOOPBACK)))
  26. #endif
  27. #define IPCONF_WINSOCKVERSION MAKEWORD(2,0)
  28. HRESULT CIPConfMSP::FinalConstruct()
  29. {
  30. // initialize winsock stack
  31. WSADATA wsaData;
  32. if (WSAStartup(IPCONF_WINSOCKVERSION, &wsaData) != 0)
  33. {
  34. LOG((MSP_ERROR, "WSAStartup failed with:%x", WSAGetLastError()));
  35. return E_FAIL;
  36. }
  37. // allocate control socket
  38. m_hSocket = WSASocket(
  39. AF_INET, // af
  40. SOCK_DGRAM, // type
  41. IPPROTO_IP, // protocol
  42. NULL, // lpProtocolInfo
  43. 0, // g
  44. 0 // dwFlags
  45. );
  46. // validate handle
  47. if (m_hSocket == INVALID_SOCKET) {
  48. LOG((
  49. MSP_ERROR,
  50. "error %d creating control socket.\n",
  51. WSAGetLastError()
  52. ));
  53. // failure
  54. WSACleanup();
  55. return E_FAIL;
  56. }
  57. HRESULT hr = CMSPAddress::FinalConstruct();
  58. if (hr != S_OK)
  59. {
  60. // close socket
  61. closesocket(m_hSocket);
  62. // shutdown
  63. WSACleanup();
  64. }
  65. return hr;
  66. }
  67. void CIPConfMSP::FinalRelease()
  68. {
  69. CMSPAddress::FinalRelease();
  70. if (m_hDxmrtp)
  71. {
  72. FreeLibrary(m_hDxmrtp);
  73. m_hDxmrtp = NULL;
  74. }
  75. if (m_hSocket != INVALID_SOCKET)
  76. {
  77. // close socket
  78. closesocket(m_hSocket);
  79. }
  80. // shutdown
  81. WSACleanup();
  82. }
  83. DWORD CIPConfMSP::FindLocalInterface(DWORD dwIP)
  84. {
  85. SOCKADDR_IN DestAddr;
  86. DestAddr.sin_family = AF_INET;
  87. DestAddr.sin_port = 0;
  88. DestAddr.sin_addr.s_addr = htonl(dwIP);
  89. SOCKADDR_IN LocAddr;
  90. // query for default address based on destination
  91. DWORD dwStatus;
  92. DWORD dwLocAddrSize = sizeof(SOCKADDR_IN);
  93. DWORD dwNumBytesReturned = 0;
  94. if ((dwStatus = WSAIoctl(
  95. m_hSocket, // SOCKET s
  96. SIO_ROUTING_INTERFACE_QUERY, // DWORD dwIoControlCode
  97. &DestAddr, // LPVOID lpvInBuffer
  98. sizeof(SOCKADDR_IN), // DWORD cbInBuffer
  99. &LocAddr, // LPVOID lpvOUTBuffer
  100. dwLocAddrSize, // DWORD cbOUTBuffer
  101. &dwNumBytesReturned, // LPDWORD lpcbBytesReturned
  102. NULL, // LPWSAOVERLAPPED lpOverlapped
  103. NULL // LPWSAOVERLAPPED_COMPLETION_ROUTINE lpComplROUTINE
  104. )) == SOCKET_ERROR)
  105. {
  106. dwStatus = WSAGetLastError();
  107. LOG((MSP_ERROR, "WSAIoctl failed: %d (0x%X)", dwStatus, dwStatus));
  108. return INADDR_NONE;
  109. }
  110. DWORD dwAddr = ntohl(LocAddr.sin_addr.s_addr);
  111. if (dwAddr == 0x7f000001)
  112. {
  113. // it is loopback address, just return none.
  114. return INADDR_NONE;
  115. }
  116. return dwAddr;
  117. }
  118. HRESULT LoadTapiAudioFilterDLL(
  119. IN const TCHAR * const strDllName,
  120. IN OUT HMODULE * phModule,
  121. IN const char * const strAudioGetDeviceInfo,
  122. IN const char * const strAudioReleaseDeviceInfo,
  123. OUT PFNAudioGetDeviceInfo * ppfnAudioGetDeviceInfo,
  124. OUT PFNAudioReleaseDeviceInfo * ppfnAudioReleaseDeviceInfo
  125. )
  126. /*++
  127. Routine Description:
  128. This method enumerate loads the tapi video capture dll.
  129. Arguments:
  130. str DllName - The name of the dll.
  131. phModule - memory to store returned module handle.
  132. ppfnAudioGetDeviceInfo - memory to store the address of AudioGetDeviceInfo
  133. function.
  134. ppfnAudioReleaseDeviceInfo - memory to store the address of
  135. AudioReleaseDeviceInfo function.
  136. Return Value:
  137. S_OK - success.
  138. E_FAIL - failure.
  139. --*/
  140. {
  141. ENTER_FUNCTION("CIPConfMSP::LoadTapiAudioFilterDLL");
  142. // dynamically load the video capture filter dll.
  143. if (*phModule == NULL)
  144. {
  145. *phModule = LoadLibrary(strDllName);
  146. }
  147. // validate handle
  148. if (*phModule == NULL)
  149. {
  150. LOG((MSP_ERROR, "%s, could not load %s., error:%d",
  151. __fxName, strDllName, GetLastError()));
  152. return E_FAIL;
  153. }
  154. // retrieve function pointer to retrieve addresses
  155. PFNAudioGetDeviceInfo pfnAudioGetDeviceInfo
  156. = (PFNAudioGetDeviceInfo)GetProcAddress(
  157. *phModule, strAudioGetDeviceInfo
  158. );
  159. // validate function pointer
  160. if (pfnAudioGetDeviceInfo == NULL)
  161. {
  162. LOG((MSP_ERROR, "%s, could not resolve %s, error:%d",
  163. __fxName, strAudioGetDeviceInfo, GetLastError()));
  164. // failure
  165. return E_FAIL;
  166. }
  167. // retrieve function pointer to retrieve addresses
  168. PFNAudioReleaseDeviceInfo pfnAudioReleaseDeviceInfo
  169. = (PFNAudioReleaseDeviceInfo)GetProcAddress(
  170. *phModule, strAudioReleaseDeviceInfo
  171. );
  172. // validate function pointer
  173. if (pfnAudioReleaseDeviceInfo == NULL)
  174. {
  175. LOG((MSP_ERROR, "%s, could not resolve %s, error:%d",
  176. __fxName, strAudioReleaseDeviceInfo, GetLastError()));
  177. // failure
  178. return E_FAIL;
  179. }
  180. *ppfnAudioGetDeviceInfo = pfnAudioGetDeviceInfo;
  181. *ppfnAudioReleaseDeviceInfo = pfnAudioReleaseDeviceInfo;
  182. return S_OK;
  183. }
  184. HRESULT CIPConfMSP::CreateAudioCaptureTerminals()
  185. /*++
  186. Routine Description:
  187. This method creates audio capture terminals. It uses DShow devenum to
  188. enumerate all the wavein capture devices first. Then it will enumerate
  189. all the DSound capture devices and match them up by name.
  190. Arguments:
  191. nothing
  192. Return Value:
  193. S_OK
  194. --*/
  195. {
  196. const TCHAR * const strAudioCaptureDll = TEXT("DXMRTP");
  197. ENTER_FUNCTION("CIPConfMSP::CreateAudioCaptureTerminals");
  198. // dynamically load the audio capture filter dll.
  199. PFNAudioGetDeviceInfo pfnAudioGetDeviceInfo;
  200. PFNAudioReleaseDeviceInfo pfnAudioReleaseDeviceInfo;
  201. HRESULT hr = LoadTapiAudioFilterDLL(
  202. strAudioCaptureDll,
  203. &m_hDxmrtp,
  204. "AudioGetCaptureDeviceInfo",
  205. "AudioReleaseCaptureDeviceInfo",
  206. &pfnAudioGetDeviceInfo,
  207. &pfnAudioReleaseDeviceInfo
  208. );
  209. if (FAILED(hr))
  210. {
  211. return hr;
  212. }
  213. DWORD dwNumDevices;
  214. AudioDeviceInfo *pDeviceInfo;
  215. hr = (*pfnAudioGetDeviceInfo)(&dwNumDevices, &pDeviceInfo);
  216. if (FAILED(hr))
  217. {
  218. LOG((MSP_ERROR, "%s, AudioGetDeviceInfo failed. hr=%x", __fxName, hr));
  219. return hr;
  220. }
  221. // for each devie, create a terminal.
  222. for (DWORD i = 0; i < dwNumDevices; i ++)
  223. {
  224. ITTerminal *pTerminal;
  225. hr = CIPConfAudioCaptureTerminal::CreateTerminal(
  226. &pDeviceInfo[i],
  227. (MSP_HANDLE) this,
  228. &pTerminal
  229. );
  230. if (FAILED(hr))
  231. {
  232. LOG((MSP_ERROR, "%s, CreateTerminal for device %d failed. hr=%x",
  233. __fxName, i, hr));
  234. break;
  235. }
  236. if (!m_Terminals.Add(pTerminal))
  237. {
  238. hr = E_OUTOFMEMORY;
  239. LOG((MSP_ERROR, "%s, out of mem in adding a terminal", __fxName));
  240. break;
  241. }
  242. }
  243. // release the device info
  244. (*pfnAudioReleaseDeviceInfo)(pDeviceInfo);
  245. return hr;
  246. }
  247. HRESULT CIPConfMSP::CreateAudioRenderTerminals()
  248. /*++
  249. Routine Description:
  250. This method enumerate all the audio render devices and creates a
  251. terminal for each of them.
  252. Arguments:
  253. nothing
  254. Return Value:
  255. S_OK
  256. --*/
  257. {
  258. ENTER_FUNCTION("CIPConfMSP::CreateAudioRenderTerminals");
  259. const TCHAR * const strAudioRenderDll = TEXT("DXMRTP");
  260. // dynamically load the audio render filter dll.
  261. PFNAudioGetDeviceInfo pfnAudioGetDeviceInfo;
  262. PFNAudioReleaseDeviceInfo pfnAudioReleaseDeviceInfo;
  263. HRESULT hr = LoadTapiAudioFilterDLL(
  264. strAudioRenderDll,
  265. &m_hDxmrtp,
  266. "AudioGetRenderDeviceInfo",
  267. "AudioReleaseRenderDeviceInfo",
  268. &pfnAudioGetDeviceInfo,
  269. &pfnAudioReleaseDeviceInfo
  270. );
  271. if (FAILED(hr))
  272. {
  273. return hr;
  274. }
  275. DWORD dwNumDevices;
  276. AudioDeviceInfo *pDeviceInfo;
  277. hr = (*pfnAudioGetDeviceInfo)(&dwNumDevices, &pDeviceInfo);
  278. if (FAILED(hr))
  279. {
  280. LOG((MSP_ERROR, "%s, AudioGetDeviceInfo failed. hr=%x", __fxName, hr));
  281. return hr;
  282. }
  283. // for each devie, create a terminal.
  284. for (DWORD i = 0; i < dwNumDevices; i ++)
  285. {
  286. ITTerminal *pTerminal;
  287. hr = CIPConfAudioRenderTerminal::CreateTerminal(
  288. &pDeviceInfo[i],
  289. (MSP_HANDLE) this,
  290. &pTerminal
  291. );
  292. if (FAILED(hr))
  293. {
  294. LOG((MSP_ERROR, "%s, CreateTerminal for device %d failed. hr=%x",
  295. __fxName, i, hr));
  296. break;
  297. }
  298. if (!m_Terminals.Add(pTerminal))
  299. {
  300. hr = E_OUTOFMEMORY;
  301. LOG((MSP_ERROR, "%s, out of mem in adding a terminal", __fxName));
  302. break;
  303. }
  304. }
  305. // release the device info
  306. (*pfnAudioReleaseDeviceInfo)(pDeviceInfo);
  307. return hr;
  308. }
  309. HRESULT LoadTapiVideoCaptureDLL(
  310. IN OUT HMODULE * phModule,
  311. OUT PFNGetNumCapDevices * ppfnGetNumCapDevices,
  312. OUT PFNGetCapDeviceInfo * ppfnGetCapDeviceInfo
  313. )
  314. /*++
  315. Routine Description:
  316. This method enumerate loads the tapi video capture dll.
  317. Arguments:
  318. phModule - memory to store returned module handle.
  319. ppfnGetNumCapDevices - memory to store the address of GetNumCapDevices
  320. function.
  321. ppfnGetCapDeviceInfo - memory to store the address of GetCapDeviceInfo
  322. function.
  323. Return Value:
  324. S_OK - success.
  325. E_FAIL - failure.
  326. --*/
  327. {
  328. const TCHAR * const strVideoCaptureDll = TEXT("DXMRTP");
  329. const char * const strGetNumCapDevices = "GetNumVideoCapDevices";
  330. const char * const strGetCapDeviceInfo = "GetVideoCapDeviceInfo";
  331. ENTER_FUNCTION("CIPConfMSP::LoadTapiVideoCaptureDLL");
  332. // dynamically load the video capture filter dll.
  333. if (*phModule == NULL)
  334. {
  335. *phModule = LoadLibrary(strVideoCaptureDll);
  336. }
  337. // validate handle
  338. if (*phModule == NULL)
  339. {
  340. LOG((MSP_ERROR, "%s, could not load %s., error:%d",
  341. __fxName, strVideoCaptureDll, GetLastError()));
  342. return E_FAIL;
  343. }
  344. // retrieve function pointer to retrieve addresses
  345. PFNGetNumCapDevices pfnGetNumCapDevices
  346. = (PFNGetNumCapDevices)GetProcAddress(*phModule, strGetNumCapDevices);
  347. // validate function pointer
  348. if (pfnGetNumCapDevices == NULL)
  349. {
  350. LOG((MSP_ERROR, "%s, could not resolve %s, error:%d",
  351. __fxName, strGetNumCapDevices, GetLastError()));
  352. // failure
  353. return E_FAIL;
  354. }
  355. // retrieve function pointer to retrieve addresses
  356. PFNGetCapDeviceInfo pfnGetCapDeviceInfo
  357. = (PFNGetCapDeviceInfo)GetProcAddress(*phModule, strGetCapDeviceInfo);
  358. // validate function pointer
  359. if (pfnGetCapDeviceInfo == NULL)
  360. {
  361. LOG((MSP_ERROR, "%s, could not resolve %s, error:%d",
  362. __fxName, strGetCapDeviceInfo, GetLastError()));
  363. // failure
  364. return E_FAIL;
  365. }
  366. *ppfnGetNumCapDevices = pfnGetNumCapDevices;
  367. *ppfnGetCapDeviceInfo = pfnGetCapDeviceInfo;
  368. return S_OK;
  369. }
  370. HRESULT CIPConfMSP::CreateVideoCaptureTerminals()
  371. /*++
  372. Routine Description:
  373. This method is called by UpdateTerminalList to create all the video
  374. capture terminals. It loads the video capture dll and calls its device
  375. enumeration code to enumerate the devices.
  376. Arguments:
  377. nothing
  378. Return Value:
  379. S_OK
  380. --*/
  381. {
  382. ENTER_FUNCTION("CIPConfMSP::CreateVideoCaptureTerminals");
  383. // dynamically load the video capture filter dll.
  384. PFNGetNumCapDevices pfnGetNumCapDevices;
  385. PFNGetCapDeviceInfo pfnGetCapDeviceInfo;
  386. HRESULT hr = LoadTapiVideoCaptureDLL(
  387. &m_hDxmrtp,
  388. &pfnGetNumCapDevices,
  389. &pfnGetCapDeviceInfo
  390. );
  391. if (FAILED(hr))
  392. {
  393. return hr;
  394. }
  395. DWORD dwNumDevices = 0;
  396. hr = (*pfnGetNumCapDevices)(&dwNumDevices);
  397. // we have to check against S_OK because the function returns S_FALSE when
  398. // there is no device.
  399. if (hr != S_OK)
  400. {
  401. if (FAILED(hr))
  402. {
  403. LOG((MSP_ERROR, "%s, GetNumCapDevices failed. hr=%x", __fxName, hr));
  404. }
  405. else
  406. {
  407. LOG((MSP_WARN, "%s, There is no video device. hr=%x", __fxName, hr));
  408. }
  409. return hr;
  410. }
  411. for (DWORD i = 0; i < dwNumDevices; i ++)
  412. {
  413. VIDEOCAPTUREDEVICEINFO DeviceInfo;
  414. hr = (*pfnGetCapDeviceInfo)(i, &DeviceInfo);
  415. if (FAILED(hr))
  416. {
  417. LOG((MSP_ERROR, "%s, GetNumCapDevices for device %d failed. hr=%x",
  418. __fxName, i, hr));
  419. break;
  420. }
  421. ITTerminal * pTerminal;
  422. hr = CIPConfVideoCaptureTerminal::CreateTerminal(
  423. DeviceInfo.szDeviceDescription,
  424. i,
  425. (MSP_HANDLE) this,
  426. &pTerminal
  427. );
  428. if (FAILED(hr))
  429. {
  430. LOG((MSP_ERROR, "%s, CreateTerminal for device %d failed. hr=%x",
  431. __fxName, i, hr));
  432. break;
  433. }
  434. if (!m_Terminals.Add(pTerminal))
  435. {
  436. hr = E_OUTOFMEMORY;
  437. LOG((MSP_ERROR, "%s, out of mem in adding a terminal", __fxName));
  438. break;
  439. }
  440. }
  441. return hr;
  442. }
  443. HRESULT CIPConfMSP::UpdateTerminalList(void)
  444. /*++
  445. Routine Description:
  446. This method is called by the base class when it first tries to enumerate
  447. all the static terminals. We override this function to create our own
  448. terminals that use our own filters.
  449. Arguments:
  450. nothing
  451. Return Value:
  452. S_OK
  453. --*/
  454. {
  455. ENTER_FUNCTION("CIPConfMSP::UpdateTerminalList");
  456. // the failure of one category of terminals doesn't prevent the enumeration
  457. // of other categories. So we ignore the return code here. If all
  458. // categories fail, the app will get an empty list.
  459. CreateAudioCaptureTerminals();
  460. CreateAudioRenderTerminals();
  461. CreateVideoCaptureTerminals();
  462. //
  463. // Our list is now complete.
  464. //
  465. m_fTerminalsUpToDate = TRUE;
  466. LOG((MSP_TRACE, "%s, exit S_OK", __fxName));
  467. return S_OK;
  468. }
  469. HRESULT CIPConfMSP::UpdateTerminalListForPnp(IN BOOL bDeviceArrival)
  470. /*++
  471. Routine Description:
  472. This method is called by the base class when it receives pnp event
  473. and needs to recreate static terminal list. We override this function
  474. to create our own terminals that use our own filters. terminal list
  475. locks was acquired when calling this method.
  476. Return Value:
  477. S_OK
  478. --*/
  479. {
  480. ENTER_FUNCTION ("CIPConfMSP::UpdateTerminalListForPnp");
  481. LOG ((MSP_TRACE, "%s (%d) entered", __fxName, bDeviceArrival));
  482. HRESULT hr;
  483. // variables for keeping old terminal info
  484. INT i, iout, iin, count;
  485. TERMINAL_DIRECTION *ptd = NULL, td;
  486. LONG *pmedia = NULL, media;
  487. BSTR *pbstr = NULL, bstr=NULL;
  488. ITTerminal **ppterminal = NULL;
  489. BOOL bmatch;
  490. MSPEVENTITEM *pevent = NULL;
  491. count = m_Terminals.GetSize ();
  492. if (count > 0)
  493. {
  494. ptd = new TERMINAL_DIRECTION[count];
  495. pmedia = new LONG[count];
  496. pbstr = new BSTR[count];
  497. ppterminal = new ITTerminal* [count];
  498. if (ptd == NULL || pmedia == NULL || pbstr == NULL || ppterminal == NULL)
  499. {
  500. LOG ((MSP_ERROR, "%s out of memory", __fxName));
  501. hr = E_OUTOFMEMORY;
  502. if (ptd) delete [] ptd;
  503. if (pmedia) delete [] pmedia;
  504. if (pbstr) delete [] pbstr;
  505. if (ppterminal) delete [] ppterminal;
  506. return hr;
  507. }
  508. memset (pbstr, 0, count * sizeof(BSTR));
  509. memset (ppterminal, 0, count * sizeof(ITTerminal*));
  510. }
  511. // for each old terminal, record
  512. for (i = 0; i < count; i++)
  513. {
  514. if (FAILED (hr = m_Terminals[i]->get_Direction (&ptd[i])))
  515. {
  516. LOG ((MSP_ERROR, "%s failed to get terminal direction. %x", __fxName, hr));
  517. goto Cleanup;
  518. }
  519. if (FAILED (hr = m_Terminals[i]->get_MediaType (&pmedia[i])))
  520. {
  521. LOG ((MSP_ERROR, "%s failed to get terminal mediatype. %x", __fxName, hr));
  522. goto Cleanup;
  523. }
  524. if (FAILED (hr = m_Terminals[i]->get_Name (&pbstr[i])))
  525. {
  526. LOG ((MSP_ERROR, "%s failed to get terminal name. %x", __fxName, hr));
  527. goto Cleanup;
  528. }
  529. m_Terminals[i]->AddRef ();
  530. ppterminal[i] = m_Terminals[i];
  531. }
  532. // if we release terminal inside previous loop: recording info
  533. // we would only release some terminals if there is an error
  534. for (i = 0; i < count; i++)
  535. {
  536. m_Terminals[i]->Release ();
  537. }
  538. m_Terminals.RemoveAll ();
  539. // update terminal list
  540. /*
  541. if (FAILED (hr = UpdateTerminalList ()))
  542. {
  543. LOG ((MSP_ERROR, "%s failed to update terminal list. %x", __fxName, hr));
  544. goto Cleanup;
  545. }
  546. */
  547. // copy UpdateTerminalList () here
  548. CreateAudioCaptureTerminals();
  549. CreateAudioRenderTerminals();
  550. CreateVideoCaptureTerminals();
  551. m_fTerminalsUpToDate = TRUE;
  552. // fire event to tapi app
  553. if (bDeviceArrival)
  554. {
  555. // outer loop each new terminal
  556. for (iout = 0; iout < m_Terminals.GetSize (); iout++)
  557. {
  558. if (FAILED (hr = m_Terminals[iout]->get_Direction (&td)))
  559. {
  560. LOG ((MSP_ERROR, "%s failed to get terminal direction. %x", __fxName, hr));
  561. goto Cleanup;
  562. }
  563. if (FAILED (hr = m_Terminals[iout]->get_MediaType (&media)))
  564. {
  565. LOG ((MSP_ERROR, "%s failed to get terminal type. %x", __fxName, hr));
  566. goto Cleanup;
  567. }
  568. if (FAILED (hr = m_Terminals[iout]->get_Name (&bstr)))
  569. {
  570. LOG ((MSP_ERROR, "%s failed to get terminal name. %x", __fxName, hr));
  571. goto Cleanup;
  572. }
  573. // inner loop check if the terminal is new
  574. for (iin = 0, bmatch = FALSE; iin < count; iin ++)
  575. {
  576. if (td == ptd[iin] &&
  577. media == pmedia[iin] &&
  578. 0 == wcscmp (bstr, pbstr[iin]))
  579. {
  580. bmatch = TRUE;
  581. break;
  582. }
  583. }
  584. // fire event if not match
  585. if (!bmatch)
  586. {
  587. LOG ((MSP_TRACE, "%s: new device found. name %ws, td %d, media %d",
  588. __fxName, bstr, td, media));
  589. pevent = AllocateEventItem();
  590. if (pevent == NULL)
  591. {
  592. LOG ((MSP_ERROR, "%s failed to new msp event item", __fxName));
  593. hr = E_OUTOFMEMORY;
  594. goto Cleanup;
  595. }
  596. m_Terminals[iout]->AddRef ();
  597. pevent->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  598. pevent->MSPEventInfo.Event = ME_ADDRESS_EVENT;
  599. pevent->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.Type = ADDRESS_TERMINAL_AVAILABLE;
  600. pevent->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal = m_Terminals[iout];
  601. if (FAILED (hr = PostEvent (pevent)))
  602. {
  603. LOG ((MSP_ERROR, "%s failed to post event. %x", __fxName, hr));
  604. m_Terminals[iout]->Release ();
  605. FreeEventItem(pevent);
  606. pevent = NULL;
  607. // we don't return, try next device
  608. }
  609. } // outer loop
  610. SysFreeString (bstr);
  611. bstr = NULL;
  612. }
  613. }
  614. else // if (bDeviceArrival)
  615. {
  616. // outer loop each old device
  617. for (iout = 0; iout < count; iout++)
  618. {
  619. // inner loop check if the device was removed
  620. for (iin = 0, bmatch = FALSE; iin < m_Terminals.GetSize (); iin++)
  621. {
  622. if (FAILED (hr = m_Terminals[iin]->get_Direction (&td)))
  623. {
  624. LOG ((MSP_ERROR, "%s failed to get terminal direction. %x", __fxName, hr));
  625. goto Cleanup;
  626. }
  627. if (FAILED (hr = m_Terminals[iin]->get_MediaType (&media)))
  628. {
  629. LOG ((MSP_ERROR, "%s failed to get terminal type. %x", __fxName, hr));
  630. goto Cleanup;
  631. }
  632. if (FAILED (hr = m_Terminals[iin]->get_Name (&bstr)))
  633. {
  634. LOG ((MSP_ERROR, "%s failed to get terminal name. %x", __fxName, hr));
  635. goto Cleanup;
  636. }
  637. if (td == ptd[iout] &&
  638. media == pmedia[iout] &&
  639. 0 == wcscmp (bstr, pbstr[iout]))
  640. {
  641. SysFreeString (bstr);
  642. bstr = NULL;
  643. bmatch = TRUE;
  644. break;
  645. }
  646. SysFreeString (bstr);
  647. bstr = NULL;
  648. }
  649. // fire event if not match
  650. if (!bmatch)
  651. {
  652. LOG ((MSP_TRACE, "%s: device removed. name %ws, td %d, media %d",
  653. __fxName, pbstr[iout], ptd[iout], pmedia[iout]));
  654. pevent = AllocateEventItem();
  655. if (pevent == NULL)
  656. {
  657. LOG ((MSP_ERROR, "%s failed to new msp event item", __fxName));
  658. hr = E_OUTOFMEMORY;
  659. goto Cleanup;
  660. }
  661. ppterminal[iout]->AddRef ();
  662. pevent->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  663. pevent->MSPEventInfo.Event = ME_ADDRESS_EVENT;
  664. pevent->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.Type = ADDRESS_TERMINAL_UNAVAILABLE;
  665. pevent->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal = ppterminal[iout];
  666. if (FAILED (hr = PostEvent (pevent)))
  667. {
  668. LOG ((MSP_ERROR, "%s failed to post event. %x", __fxName, hr));
  669. ppterminal[iout]->Release ();
  670. FreeEventItem(pevent);
  671. pevent = NULL;
  672. // we don't return, try next device
  673. }
  674. }
  675. } // outer loop
  676. }
  677. Cleanup:
  678. if (bstr) SysFreeString (bstr);
  679. if (count > 0)
  680. {
  681. delete [] ptd;
  682. delete [] pmedia;
  683. for (i = 0; i < count; i++)
  684. {
  685. if (pbstr[i]) SysFreeString (pbstr[i]);
  686. if (ppterminal[i]) ppterminal[i]->Release ();
  687. }
  688. delete [] pbstr;
  689. delete [] ppterminal;
  690. }
  691. LOG ((MSP_TRACE, "%s returns", __fxName));
  692. return hr;
  693. }
  694. STDMETHODIMP CIPConfMSP::CreateTerminal(
  695. IN BSTR pTerminalClass,
  696. IN long lMediaType,
  697. IN TERMINAL_DIRECTION Direction,
  698. OUT ITTerminal ** ppTerminal
  699. )
  700. /*++
  701. Routine Description:
  702. This method is called by TAPI3 to create a dynamic terminal. It asks the
  703. terminal manager to create a dynamic terminal.
  704. Arguments:
  705. iidTerminalClass
  706. IID of the terminal class to be created.
  707. dwMediaType
  708. TAPI media type of the terminal to be created.
  709. Direction
  710. Terminal direction of the terminal to be created.
  711. ppTerminal
  712. Returned created terminal object
  713. Return Value:
  714. S_OK
  715. E_OUTOFMEMORY
  716. TAPI_E_INVALIDMEDIATYPE
  717. TAPI_E_INVALIDTERMINALDIRECTION
  718. TAPI_E_INVALIDTERMINALCLASS
  719. --*/
  720. {
  721. ENTER_FUNCTION("CIPConfMSP::CreateTerminal");
  722. LOG((MSP_TRACE, "%s - enter", __fxName));
  723. //
  724. // Check if initialized.
  725. //
  726. // lock the event related data
  727. m_EventDataLock.Lock();
  728. if ( m_htEvent == NULL )
  729. {
  730. // unlock the event related data
  731. m_EventDataLock.Unlock();
  732. LOG((MSP_ERROR,
  733. "%s, not initialized - returning E_UNEXPECTED", __fxName));
  734. return E_UNEXPECTED;
  735. }
  736. // unlock the event related data
  737. m_EventDataLock.Unlock();
  738. //
  739. // Get the IID from the BSTR representation.
  740. //
  741. HRESULT hr;
  742. IID iidTerminalClass;
  743. hr = CLSIDFromString(pTerminalClass, &iidTerminalClass);
  744. if ( FAILED(hr) )
  745. {
  746. LOG((MSP_ERROR, "%s, bad CLSID string", __fxName));
  747. return E_INVALIDARG;
  748. }
  749. //
  750. // Make sure we support the requested media type.
  751. // The terminal manager checks the terminal class, terminal direction,
  752. // and return pointer.
  753. //
  754. //
  755. // we don't have any specific req's to terminal's media type.
  756. // termmgr will check if the media type is valid at all.
  757. //
  758. //
  759. // Use the terminal manager to create the dynamic terminal.
  760. //
  761. _ASSERTE( m_pITTerminalManager != NULL );
  762. hr = m_pITTerminalManager->CreateDynamicTerminal(NULL,
  763. iidTerminalClass,
  764. (DWORD) lMediaType,
  765. Direction,
  766. (MSP_HANDLE) this,
  767. ppTerminal);
  768. if ( FAILED(hr) )
  769. {
  770. LOG((MSP_ERROR,
  771. "%s create dynamic terminal failed. hr=%x", __fxName, hr));
  772. return hr;
  773. }
  774. const DWORD dwAudioCaptureBitPerSample = 16;
  775. const DWORD dwAudioSampleRate = 8000;
  776. if ((iidTerminalClass == CLSID_MediaStreamTerminal)
  777. && (lMediaType == TAPIMEDIATYPE_AUDIO))
  778. {
  779. // Set the format of the audio to 8KHZ, 16Bit/Sample, MONO.
  780. hr = ::SetAudioFormat(
  781. *ppTerminal,
  782. dwAudioCaptureBitPerSample,
  783. dwAudioSampleRate
  784. );
  785. if (FAILED(hr))
  786. {
  787. LOG((MSP_WARN, "%s, can't set audio format, %x", __fxName, hr));
  788. }
  789. }
  790. LOG((MSP_TRACE, "%s - exit S_OK", __fxName));
  791. return S_OK;
  792. }
  793. STDMETHODIMP CIPConfMSP::CreateMSPCall(
  794. IN MSP_HANDLE htCall,
  795. IN DWORD dwReserved,
  796. IN DWORD dwMediaType,
  797. IN IUnknown * pOuterUnknown,
  798. OUT IUnknown ** ppMSPCall
  799. )
  800. /*++
  801. Routine Description:
  802. This method is called by TAPI3 before a call is made or answered. It creates
  803. a aggregated MSPCall object and returns the IUnknown pointer. It calls the
  804. helper template function defined in mspaddress.h to handle the real creation.
  805. Arguments:
  806. htCall
  807. TAPI 3.0's identifier for this call. Returned in events passed back
  808. to TAPI.
  809. dwReserved
  810. Reserved parameter. Not currently used.
  811. dwMediaType
  812. Media type of the call being created. These are TAPIMEDIATYPES and more
  813. than one mediatype can be selected (bitwise).
  814. pOuterUnknown
  815. pointer to the IUnknown interface of the containing object.
  816. ppMSPCall
  817. Returned MSP call that the MSP fills on on success.
  818. Return Value:
  819. S_OK
  820. E_OUTOFMEMORY
  821. E_POINTER
  822. TAPI_E_INVALIDMEDIATYPE
  823. --*/
  824. {
  825. LOG((MSP_TRACE,
  826. "CreateMSPCall entered. htCall:%x, dwMediaType:%x, ppMSPCall:%x",
  827. htCall, dwMediaType, ppMSPCall
  828. ));
  829. CIPConfMSPCall * pMSPCall = NULL;
  830. HRESULT hr = ::CreateMSPCallHelper(
  831. this,
  832. htCall,
  833. dwReserved,
  834. dwMediaType,
  835. pOuterUnknown,
  836. ppMSPCall,
  837. &pMSPCall
  838. );
  839. if (FAILED(hr))
  840. {
  841. LOG((MSP_ERROR, "CreateMSPCallHelper failed:%x", hr));
  842. return hr;
  843. }
  844. // this function doesn't return anything.
  845. pMSPCall->SetIPInterface(m_dwIPInterface);
  846. return hr;
  847. }
  848. STDMETHODIMP CIPConfMSP::ShutdownMSPCall(
  849. IN IUnknown * pUnknown
  850. )
  851. /*++
  852. Routine Description:
  853. This method is called by TAPI3 to shutdown a MSPCall. It calls the helper
  854. function defined in MSPAddress to to the real job.
  855. Arguments:
  856. pUnknown
  857. pointer to the IUnknown interface of the contained object. It is a
  858. CComAggObject that contains our call object.
  859. Return Value:
  860. S_OK
  861. E_POINTER
  862. TAPI_E_INVALIDMEDIATYPE
  863. --*/
  864. {
  865. LOG((MSP_TRACE, "ShutDownMSPCall entered. pUnknown:%x", pUnknown));
  866. if (IsBadReadPtr(pUnknown, sizeof(VOID *) * 3))
  867. {
  868. LOG((MSP_ERROR, "ERROR:pUnknow is a bad pointer"));
  869. return E_POINTER;
  870. }
  871. CIPConfMSPCall * pMSPCall = NULL;
  872. HRESULT hr = ::ShutdownMSPCallHelper(pUnknown, &pMSPCall);
  873. if (FAILED(hr))
  874. {
  875. LOG((MSP_ERROR, "ShutDownMSPCallhelper failed:: %x", hr));
  876. return hr;
  877. }
  878. return hr;
  879. }
  880. DWORD CIPConfMSP::GetCallMediaTypes(void)
  881. {
  882. return IPCONFCALLMEDIATYPES;
  883. }
  884. ULONG CIPConfMSP::MSPAddressAddRef(void)
  885. {
  886. return MSPAddRefHelper(this);
  887. }
  888. ULONG CIPConfMSP::MSPAddressRelease(void)
  889. {
  890. return MSPReleaseHelper(this);
  891. }
  892. #ifdef USEIPADDRTABLE
  893. PMIB_IPADDRTABLE GetIPTable()
  894. /*++
  895. Routine Description:
  896. This method is used to get the table of local IP interfaces.
  897. Arguments:
  898. Return Value:
  899. NULL - failed.
  900. Pointer - a memory buffer that contains the IP interface table.
  901. --*/
  902. {
  903. // dynamically load iphlpapi.dll
  904. HMODULE hIPHLPAPI = LoadLibraryW(IPHLPAPI_DLL);
  905. // validate handle
  906. if (hIPHLPAPI == NULL)
  907. {
  908. LOG((MSP_ERROR, "could not load %s.\n", IPHLPAPI_DLL));
  909. // failure
  910. return NULL;
  911. }
  912. PFNGETIPADDRTABLE pfnGetIpAddrTable = NULL;
  913. // retrieve function pointer to retrieve addresses
  914. pfnGetIpAddrTable = (PFNGETIPADDRTABLE)GetProcAddress(
  915. hIPHLPAPI,
  916. GETIPADDRTABLE
  917. );
  918. // validate function pointer
  919. if (pfnGetIpAddrTable == NULL)
  920. {
  921. LOG((MSP_ERROR, "could not resolve GetIpAddrTable.\n"));
  922. // release
  923. FreeLibrary(hIPHLPAPI);
  924. // failure
  925. return NULL;
  926. }
  927. PMIB_IPADDRTABLE pIPAddrTable = NULL;
  928. DWORD dwBytesRequired = 0;
  929. DWORD dwStatus;
  930. // determine amount of memory needed for table
  931. dwStatus = (*pfnGetIpAddrTable)(pIPAddrTable, &dwBytesRequired, FALSE);
  932. // validate status is what we expect
  933. if (dwStatus != ERROR_INSUFFICIENT_BUFFER)
  934. {
  935. LOG((MSP_ERROR, "error 0x%08lx calling GetIpAddrTable.\n", dwStatus));
  936. // release
  937. FreeLibrary(hIPHLPAPI);
  938. // failure, but we need to return true to load.
  939. return NULL;
  940. }
  941. // attempt to allocate memory for table
  942. pIPAddrTable = (PMIB_IPADDRTABLE)malloc(dwBytesRequired);
  943. // validate pointer
  944. if (pIPAddrTable == NULL)
  945. {
  946. LOG((MSP_ERROR, "could not allocate address table.\n"));
  947. // release
  948. FreeLibrary(hIPHLPAPI);
  949. // failure, but we need to return true to load.
  950. return NULL;
  951. }
  952. // retrieve ip address table from tcp/ip stack via utitity library
  953. dwStatus = (*pfnGetIpAddrTable)(pIPAddrTable, &dwBytesRequired, FALSE);
  954. // validate status
  955. if (dwStatus != NOERROR)
  956. {
  957. LOG((MSP_ERROR, "error 0x%08lx calling GetIpAddrTable.\n", dwStatus));
  958. // release table
  959. free(pIPAddrTable);
  960. // release
  961. FreeLibrary(hIPHLPAPI);
  962. // failure, but we need to return true to load.
  963. return NULL;
  964. }
  965. // release library
  966. FreeLibrary(hIPHLPAPI);
  967. return pIPAddrTable;
  968. }
  969. BSTR IPToBstr(
  970. DWORD dwIP
  971. )
  972. {
  973. struct in_addr Addr;
  974. Addr.s_addr = dwIP;
  975. // convert the interface to a string.
  976. CHAR *pChar = inet_ntoa(Addr);
  977. if (pChar == NULL)
  978. {
  979. LOG((MSP_ERROR, "bad IP address:%x", dwIP));
  980. return NULL;
  981. }
  982. // convert the ascii string to WCHAR.
  983. WCHAR szAddressName[MAXIPADDRLEN + 1];
  984. wsprintfW(szAddressName, L"%hs", pChar);
  985. // create a BSTR.
  986. BSTR bAddress = SysAllocString(szAddressName);
  987. if (bAddress == NULL)
  988. {
  989. LOG((MSP_ERROR, "out of mem in allocation address name"));
  990. return NULL;
  991. }
  992. return bAddress;
  993. }
  994. STDMETHODIMP CIPConfMSP::get_DefaultIPInterface(
  995. OUT BSTR * ppIPAddress
  996. )
  997. {
  998. LOG((MSP_TRACE, "get_DefaultIPInterface, ppIPAddress:%p", ppIPAddress));
  999. if (IsBadWritePtr(ppIPAddress, sizeof(BSTR)))
  1000. {
  1001. LOG((MSP_ERROR,
  1002. "get_DefaultIPInterface, ppIPAddress is bad:%p", ppIPAddress));
  1003. return E_POINTER;
  1004. }
  1005. // get the current local interface.
  1006. m_Lock.Lock();
  1007. DWORD dwIP= m_dwIPInterface;
  1008. m_Lock.Unlock();
  1009. BSTR bAddress = IPToBstr(dwIP);
  1010. if (bAddress == NULL)
  1011. {
  1012. return E_OUTOFMEMORY;
  1013. }
  1014. *ppIPAddress = bAddress;
  1015. LOG((MSP_TRACE, "get_DefaultIPInterface, returning %ws", bAddress));
  1016. return S_OK;
  1017. }
  1018. STDMETHODIMP CIPConfMSP::put_DefaultIPInterface(
  1019. IN BSTR pIPAddress
  1020. )
  1021. {
  1022. LOG((MSP_TRACE, "put_DefaultIPInterface, pIPAddress:%p", pIPAddress));
  1023. if (IsBadStringPtrW(pIPAddress, MAXIPADDRLEN))
  1024. {
  1025. LOG((MSP_ERROR,
  1026. "put_DefaultIPInterface, invalid pointer:%p", pIPAddress));
  1027. return E_POINTER;
  1028. }
  1029. char buffer[MAXIPADDRLEN + 1];
  1030. if (WideCharToMultiByte(
  1031. GetACP(),
  1032. 0,
  1033. pIPAddress,
  1034. -1,
  1035. buffer,
  1036. MAXIPADDRLEN,
  1037. NULL,
  1038. NULL
  1039. ) == 0)
  1040. {
  1041. LOG((MSP_ERROR, "put_DefaultIPInterface, can't covert:%ws", pIPAddress));
  1042. return E_INVALIDARG;
  1043. }
  1044. DWORD dwAddr;
  1045. if ((dwAddr = inet_addr(buffer)) == INADDR_NONE)
  1046. {
  1047. LOG((MSP_ERROR, "put_DefaultIPInterface, bad address:%s", buffer));
  1048. return E_INVALIDARG;
  1049. }
  1050. // set the current local interface.
  1051. m_Lock.Lock();
  1052. m_dwIPInterface = dwAddr;
  1053. m_Lock.Unlock();
  1054. LOG((MSP_TRACE, "put_DefaultIPInterface, set to %s", buffer));
  1055. return S_OK;
  1056. }
  1057. HRESULT CreateBstrCollection(
  1058. IN BSTR * pBstr,
  1059. IN DWORD dwCount,
  1060. OUT VARIANT * pVariant
  1061. )
  1062. {
  1063. //
  1064. // create the collection object - see mspcoll.h
  1065. //
  1066. CComObject<CTapiBstrCollection> * pCollection;
  1067. HRESULT hr;
  1068. hr = ::CreateCComObjectInstance(&pCollection);
  1069. if ( FAILED(hr) )
  1070. {
  1071. LOG((MSP_ERROR, "get_IPInterfaces - "
  1072. "can't create collection - exit 0x%08x", hr));
  1073. return hr;
  1074. }
  1075. //
  1076. // get the Collection's IDispatch interface
  1077. //
  1078. IDispatch * pDispatch;
  1079. hr = pCollection->_InternalQueryInterface(__uuidof(IDispatch),
  1080. (void **) &pDispatch );
  1081. if ( FAILED(hr) )
  1082. {
  1083. LOG((MSP_ERROR, "get_IPInterfaces - "
  1084. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  1085. delete pCollection;
  1086. return hr;
  1087. }
  1088. //
  1089. // Init the collection using an iterator -- pointers to the beginning and
  1090. // the ending element plus one.
  1091. //
  1092. hr = pCollection->Initialize( dwCount,
  1093. pBstr,
  1094. pBstr + dwCount);
  1095. if ( FAILED(hr) )
  1096. {
  1097. LOG((MSP_ERROR, "get_IPInterfaces - "
  1098. "Initialize on collection failed - exit 0x%08x", hr));
  1099. pDispatch->Release();
  1100. return hr;
  1101. }
  1102. //
  1103. // put the IDispatch interface pointer into the variant
  1104. //
  1105. LOG((MSP_ERROR, "get_IPInterfaces - "
  1106. "placing IDispatch value %08x in variant", pDispatch));
  1107. VariantInit(pVariant);
  1108. pVariant->vt = VT_DISPATCH;
  1109. pVariant->pdispVal = pDispatch;
  1110. LOG((MSP_TRACE, "get_IPInterfaces - exit S_OK"));
  1111. return S_OK;
  1112. }
  1113. STDMETHODIMP CIPConfMSP::get_IPInterfaces(
  1114. OUT VARIANT * pVariant
  1115. )
  1116. {
  1117. PMIB_IPADDRTABLE pIPAddrTable = GetIPTable();
  1118. if (pIPAddrTable == NULL)
  1119. {
  1120. return E_FAIL;
  1121. }
  1122. BSTR *Addresses =
  1123. (BSTR *)malloc(sizeof(BSTR *) * pIPAddrTable->dwNumEntries);
  1124. if (Addresses == NULL)
  1125. {
  1126. return E_OUTOFMEMORY;
  1127. }
  1128. HRESULT hr = S_OK;
  1129. DWORD dwCount = 0;
  1130. // loop through the interfaces and find the valid ones.
  1131. for (DWORD i = 0; i < pIPAddrTable->dwNumEntries; i++)
  1132. {
  1133. if (IsValidInterface(pIPAddrTable->table[i].dwAddr))
  1134. {
  1135. DWORD dwIPAddr = ntohl(pIPAddrTable->table[i].dwAddr);
  1136. Addresses[i] = IPToBstr(dwIPAddr);
  1137. if (Addresses[i] == NULL)
  1138. {
  1139. hr = E_OUTOFMEMORY;
  1140. break;
  1141. }
  1142. dwCount ++;
  1143. }
  1144. }
  1145. // release table memory
  1146. free(pIPAddrTable);
  1147. if (FAILED(hr))
  1148. {
  1149. // release all the BSTRs and the array.
  1150. for (i = 0; i < dwCount; i ++)
  1151. {
  1152. SysFreeString(Addresses[i]);
  1153. }
  1154. free(Addresses);
  1155. return hr;
  1156. }
  1157. hr = CreateBstrCollection(Addresses, dwCount, pVariant);
  1158. // if the collection is not created, release all the BSTRs.
  1159. if (FAILED(hr))
  1160. {
  1161. for (i = 0; i < dwCount; i ++)
  1162. {
  1163. SysFreeString(Addresses[i]);
  1164. }
  1165. }
  1166. // delete the pointer array.
  1167. free(Addresses);
  1168. return hr;
  1169. }
  1170. HRESULT CreateBstrEnumerator(
  1171. IN BSTR * begin,
  1172. IN BSTR * end,
  1173. OUT IEnumBstr ** ppIEnum
  1174. )
  1175. {
  1176. typedef CSafeComEnum<IEnumBstr, &__uuidof(IEnumBstr), BSTR, _CopyBSTR>> CEnumerator;
  1177. HRESULT hr;
  1178. CComObject<CEnumerator> *pEnum = NULL;
  1179. hr = ::CreateCComObjectInstance(&pEnum);
  1180. if (pEnum == NULL)
  1181. {
  1182. LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
  1183. return hr;
  1184. }
  1185. IEnumBstr * pIEnum;
  1186. // query for the __uuidof(IEnumDirectory) i/f
  1187. hr = pEnum->_InternalQueryInterface(
  1188. __uuidof(IEnumBstr),
  1189. (void**)&pIEnum
  1190. );
  1191. if (FAILED(hr))
  1192. {
  1193. LOG((MSP_ERROR, "query enum interface failed, %x", hr));
  1194. delete pEnum;
  1195. return hr;
  1196. }
  1197. hr = pEnum->Init(begin, end, NULL, AtlFlagTakeOwnership);
  1198. if (FAILED(hr))
  1199. {
  1200. LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
  1201. pIEnum->Release();
  1202. return hr;
  1203. }
  1204. *ppIEnum = pIEnum;
  1205. return hr;
  1206. }
  1207. STDMETHODIMP CIPConfMSP::EnumerateIPInterfaces(
  1208. OUT IEnumBstr ** ppIEnumBstr
  1209. )
  1210. {
  1211. PMIB_IPADDRTABLE pIPAddrTable = GetIPTable();
  1212. if (pIPAddrTable == NULL)
  1213. {
  1214. return E_FAIL;
  1215. }
  1216. BSTR *Addresses =
  1217. (BSTR *)malloc(sizeof(BSTR *) * pIPAddrTable->dwNumEntries);
  1218. if (Addresses == NULL)
  1219. {
  1220. return E_OUTOFMEMORY;
  1221. }
  1222. HRESULT hr = S_OK;
  1223. DWORD dwCount = 0;
  1224. // loop through the interfaces and find the valid ones.
  1225. for (DWORD i = 0; i < pIPAddrTable->dwNumEntries; i++)
  1226. {
  1227. if (IsValidInterface(pIPAddrTable->table[i].dwAddr))
  1228. {
  1229. DWORD dwIPAddr = ntohl(pIPAddrTable->table[i].dwAddr);
  1230. Addresses[i] = IPToBstr(dwIPAddr);
  1231. if (Addresses[i] == NULL)
  1232. {
  1233. hr = E_OUTOFMEMORY;
  1234. break;
  1235. }
  1236. dwCount ++;
  1237. }
  1238. }
  1239. // release table memory
  1240. free(pIPAddrTable);
  1241. if (FAILED(hr))
  1242. {
  1243. // release all the BSTRs and the array.
  1244. for (i = 0; i < dwCount; i ++)
  1245. {
  1246. SysFreeString(Addresses[i]);
  1247. }
  1248. free(Addresses);
  1249. return hr;
  1250. }
  1251. hr = CreateBstrEnumerator(Addresses, Addresses + dwCount, ppIEnumBstr);
  1252. // if the collection is not created, release all the BSTRs.
  1253. if (FAILED(hr))
  1254. {
  1255. for (i = 0; i < dwCount; i ++)
  1256. {
  1257. SysFreeString(Addresses[i]);
  1258. }
  1259. free(Addresses);
  1260. return hr;
  1261. }
  1262. // the enumerator will destroy the bstr array eventually,
  1263. // so no need to free anything here. Even if we tell it to hand
  1264. // out zero objects, it will delete the array on destruction.
  1265. return hr;
  1266. }
  1267. #endif