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.

802 lines
16 KiB

  1. // binding.cpp : Implementation of CServerBinding & CServerBindings.
  2. #include "stdafx.h"
  3. #include "smtpadm.h"
  4. #include "cmultisz.h"
  5. #include "binding.h"
  6. #include "oleutil.h"
  7. #include "smtpcmn.h"
  8. HRESULT CBinding::SetProperties (
  9. BSTR strIpAddress,
  10. long dwTcpPort,
  11. long dwSslPort
  12. )
  13. {
  14. _ASSERT ( IS_VALID_STRING ( strIpAddress ) );
  15. m_strIpAddress = strIpAddress;
  16. m_dwTcpPort = dwTcpPort;
  17. m_dwSslPort = dwSslPort;
  18. if ( !m_strIpAddress ) {
  19. return E_OUTOFMEMORY;
  20. }
  21. return NOERROR;
  22. }
  23. // Must define THIS_FILE_* macros to use SmtpCreateException()
  24. #define THIS_FILE_HELP_CONTEXT 0
  25. #define THIS_FILE_PROG_ID _T("Smtpadm.VirtualServer.1")
  26. #define THIS_FILE_IID IID_IServerBinding
  27. /////////////////////////////////////////////////////////////////////////////
  28. //
  29. STDMETHODIMP CServerBinding::InterfaceSupportsErrorInfo(REFIID riid)
  30. {
  31. static const IID* arr[] =
  32. {
  33. &IID_IServerBinding,
  34. };
  35. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  36. {
  37. if (InlineIsEqualGUID(*arr[i],riid))
  38. return S_OK;
  39. }
  40. return S_FALSE;
  41. }
  42. CServerBinding::CServerBinding ()
  43. // CComBSTR's are initialized to NULL by default.
  44. {
  45. }
  46. CServerBinding::~CServerBinding ()
  47. {
  48. // All CComBSTR's are freed automatically.
  49. }
  50. //////////////////////////////////////////////////////////////////////
  51. // Properties:
  52. //////////////////////////////////////////////////////////////////////
  53. STDMETHODIMP CServerBinding::get_IpAddress ( BSTR * pstrIpAddress )
  54. {
  55. return StdPropertyGet ( m_binding.m_strIpAddress, pstrIpAddress );
  56. }
  57. STDMETHODIMP CServerBinding::put_IpAddress ( BSTR strIpAddress )
  58. {
  59. return StdPropertyPut ( &m_binding.m_strIpAddress, strIpAddress );
  60. }
  61. STDMETHODIMP CServerBinding::get_TcpPort ( long * pdwTcpPort )
  62. {
  63. return StdPropertyGet ( m_binding.m_dwTcpPort, pdwTcpPort );
  64. }
  65. STDMETHODIMP CServerBinding::put_TcpPort ( long dwTcpPort )
  66. {
  67. return StdPropertyPut ( &m_binding.m_dwTcpPort, dwTcpPort );
  68. }
  69. STDMETHODIMP CServerBinding::get_SslPort ( long * plSslPort )
  70. {
  71. return StdPropertyGet ( m_binding.m_dwSslPort, plSslPort );
  72. }
  73. STDMETHODIMP CServerBinding::put_SslPort ( long lSslPort )
  74. {
  75. return StdPropertyPut ( &m_binding.m_dwSslPort, lSslPort );
  76. }
  77. //
  78. // Must define THIS_FILE_* macros to use SmtpCreateException()
  79. //
  80. #undef THIS_FILE_HELP_CONTEXT
  81. #undef THIS_FILE_PROG_ID
  82. #undef THIS_FILE_IID
  83. #define THIS_FILE_HELP_CONTEXT 0
  84. #define THIS_FILE_PROG_ID _T("smtpadm.VirtualServer.1")
  85. #define THIS_FILE_IID IID_IServerBindings
  86. /////////////////////////////////////////////////////////////////////////////
  87. //
  88. STDMETHODIMP CServerBindings::InterfaceSupportsErrorInfo(REFIID riid)
  89. {
  90. static const IID* arr[] =
  91. {
  92. &IID_IServerBindings,
  93. };
  94. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  95. {
  96. if (InlineIsEqualGUID(*arr[i],riid))
  97. return S_OK;
  98. }
  99. return S_FALSE;
  100. }
  101. CServerBindings::CServerBindings () :
  102. m_dwCount ( 0 ),
  103. m_rgBindings ( NULL )
  104. // CComBSTR's are initialized to NULL by default.
  105. {
  106. }
  107. CServerBindings::~CServerBindings ()
  108. {
  109. // All CComBSTR's are freed automatically.
  110. delete [] m_rgBindings;
  111. }
  112. //////////////////////////////////////////////////////////////////////
  113. // Properties:
  114. //////////////////////////////////////////////////////////////////////
  115. STDMETHODIMP CServerBindings::get_Count ( long * pdwCount )
  116. {
  117. return StdPropertyGet ( m_dwCount, pdwCount );
  118. }
  119. //////////////////////////////////////////////////////////////////////
  120. // Methods:
  121. //////////////////////////////////////////////////////////////////////
  122. STDMETHODIMP CServerBindings::Item (
  123. long index,
  124. IServerBinding ** ppBinding
  125. )
  126. {
  127. TraceFunctEnter ( "CServerBindings::Item" );
  128. _ASSERT ( IS_VALID_OUT_PARAM ( ppBinding ) );
  129. *ppBinding = NULL;
  130. HRESULT hr = NOERROR;
  131. CComObject<CServerBinding> * pBinding = NULL;
  132. if ( index < 0 || index >= m_dwCount ) {
  133. hr = SmtpCreateException ( IDS_SMTPEXCEPTION_INVALID_INDEX );
  134. goto Exit;
  135. }
  136. hr = CComObject<CServerBinding>::CreateInstance ( &pBinding );
  137. if ( FAILED(hr) ) {
  138. goto Exit;
  139. }
  140. _ASSERT ( pBinding );
  141. hr = pBinding->SetProperties ( m_rgBindings[index] );
  142. if ( FAILED(hr) ) {
  143. goto Exit;
  144. }
  145. hr = pBinding->QueryInterface ( IID_IServerBinding, (void **) ppBinding );
  146. _ASSERT ( SUCCEEDED(hr) );
  147. Exit:
  148. if ( FAILED(hr) && hr != DISP_E_EXCEPTION ) {
  149. hr = SmtpCreateExceptionFromHresult ( hr );
  150. }
  151. if ( FAILED(hr) ) {
  152. delete pBinding;
  153. }
  154. TraceFunctLeave ();
  155. return hr;
  156. }
  157. STDMETHODIMP CServerBindings::ItemDispatch ( long index, IDispatch ** ppDispatch )
  158. {
  159. HRESULT hr;
  160. CComPtr<IServerBinding> pBinding;
  161. hr = Item ( index, &pBinding );
  162. BAIL_ON_FAILURE ( hr );
  163. hr = pBinding->QueryInterface ( IID_IDispatch, (void **) ppDispatch );
  164. BAIL_ON_FAILURE ( hr );
  165. Exit:
  166. return hr;
  167. }
  168. STDMETHODIMP CServerBindings::Add (
  169. BSTR strIpAddress,
  170. long dwTcpPort,
  171. long dwSslPort
  172. )
  173. {
  174. TraceFunctEnter ( "CServerBindings::Add" );
  175. _ASSERT ( IS_VALID_STRING ( strIpAddress ) );
  176. HRESULT hr = NOERROR;
  177. CBinding * rgNewBindings = NULL;
  178. long i;
  179. //
  180. // Validate the new binding:
  181. //
  182. //
  183. // See if we can merge this binding with an existing one:
  184. //
  185. if ( dwTcpPort == 0 || dwSslPort == 0 ) {
  186. for ( i = 0; i < m_dwCount; i++ ) {
  187. if ( (dwTcpPort == 0 && m_rgBindings[i].m_dwSslPort == 0) ||
  188. (dwSslPort == 0 && m_rgBindings[i].m_dwTcpPort == 0) ) {
  189. if ( lstrcmpi ( m_rgBindings[i].m_strIpAddress, strIpAddress ) == 0 ) {
  190. if ( m_rgBindings[i].m_dwSslPort == 0 ) {
  191. m_rgBindings[i].m_dwSslPort = dwSslPort;
  192. }
  193. else {
  194. m_rgBindings[i].m_dwTcpPort = dwTcpPort;
  195. }
  196. hr = NOERROR;
  197. goto Exit;
  198. }
  199. }
  200. }
  201. }
  202. // Allocate the new binding array:
  203. rgNewBindings = new CBinding [ m_dwCount + 1 ];
  204. if ( !rgNewBindings ) {
  205. hr = E_OUTOFMEMORY;
  206. goto Exit;
  207. }
  208. // Copy the old bindings to the new array:
  209. for ( i = 0; i < m_dwCount; i++ ) {
  210. hr = rgNewBindings[i].SetProperties ( m_rgBindings[i] );
  211. if ( FAILED (hr) ) {
  212. goto Exit;
  213. }
  214. }
  215. // Add the new binding to the end of the array:
  216. hr = rgNewBindings[m_dwCount].SetProperties ( strIpAddress, dwTcpPort, dwSslPort );
  217. if ( FAILED(hr) ) {
  218. goto Exit;
  219. }
  220. _ASSERT ( SUCCEEDED(hr) );
  221. delete [] m_rgBindings;
  222. m_rgBindings = rgNewBindings;
  223. rgNewBindings = NULL;
  224. m_dwCount++;
  225. Exit:
  226. if (FAILED(hr) && rgNewBindings)
  227. delete [] rgNewBindings;
  228. TraceFunctLeave ();
  229. return hr;
  230. }
  231. STDMETHODIMP CServerBindings::ChangeBinding (
  232. long index,
  233. IServerBinding * pBinding
  234. )
  235. {
  236. TraceFunctEnter ( "CServerBindings::ChangeBinding" );
  237. HRESULT hr = NOERROR;
  238. CComBSTR strIpAddress;
  239. long dwTcpPort;
  240. long dwSslPort;
  241. if ( index < 0 || index >= m_dwCount ) {
  242. hr = SmtpCreateException ( IDS_SMTPEXCEPTION_INVALID_INDEX );
  243. goto Exit;
  244. }
  245. hr = pBinding->get_IpAddress ( &strIpAddress );
  246. if ( FAILED(hr) ) {
  247. goto Exit;
  248. }
  249. hr = pBinding->get_TcpPort ( &dwTcpPort );
  250. if ( FAILED(hr) ) {
  251. goto Exit;
  252. }
  253. hr = pBinding->get_SslPort ( &dwSslPort );
  254. if ( FAILED(hr) ) {
  255. goto Exit;
  256. }
  257. hr = m_rgBindings[index].SetProperties ( strIpAddress, dwTcpPort, dwSslPort );
  258. if ( FAILED(hr) ) {
  259. goto Exit;
  260. }
  261. Exit:
  262. TraceFunctLeave ();
  263. return hr;
  264. }
  265. STDMETHODIMP CServerBindings::ChangeBindingDispatch ( long index, IDispatch * pDispatch )
  266. {
  267. HRESULT hr;
  268. CComPtr<IServerBinding> pBinding;
  269. hr = pDispatch->QueryInterface ( IID_IServerBinding, (void **) &pBinding );
  270. BAIL_ON_FAILURE ( hr );
  271. hr = ChangeBinding ( index, pBinding );
  272. BAIL_ON_FAILURE ( hr );
  273. Exit:
  274. return hr;
  275. }
  276. STDMETHODIMP CServerBindings::Remove ( long index )
  277. {
  278. TraceFunctEnter ( "CServerBindings::Remove" );
  279. HRESULT hr = NOERROR;
  280. CBinding temp;
  281. long cPositionsToSlide;
  282. if ( index < 0 || index >= m_dwCount ) {
  283. hr = SmtpCreateException ( IDS_SMTPEXCEPTION_INVALID_INDEX );
  284. goto Exit;
  285. }
  286. // Slide the array down by one position:
  287. _ASSERT ( m_rgBindings );
  288. cPositionsToSlide = (m_dwCount - 1) - index;
  289. _ASSERT ( cPositionsToSlide < m_dwCount );
  290. if ( cPositionsToSlide > 0 ) {
  291. // Save the deleted binding in temp:
  292. CopyMemory ( &temp, &m_rgBindings[index], sizeof ( CBinding ) );
  293. // Move the array down one:
  294. MoveMemory ( &m_rgBindings[index], &m_rgBindings[index + 1], sizeof ( CBinding ) * cPositionsToSlide );
  295. // Put the deleted binding on the end (so it gets destructed):
  296. CopyMemory ( &m_rgBindings[m_dwCount - 1], &temp, sizeof ( CBinding ) );
  297. // Zero out the temp binding:
  298. ZeroMemory ( &temp, sizeof ( CBinding ) );
  299. }
  300. m_dwCount--;
  301. Exit:
  302. TraceFunctLeave ();
  303. return hr;
  304. }
  305. STDMETHODIMP CServerBindings::Clear ( )
  306. {
  307. delete [] m_rgBindings;
  308. m_rgBindings = NULL;
  309. m_dwCount = 0;
  310. return NOERROR;
  311. }
  312. //////////////////////////////////////////////////////////////////////
  313. //
  314. // Useful routines to go from IServerBindings to
  315. // Metabase data types.
  316. //
  317. //////////////////////////////////////////////////////////////////////
  318. static DWORD CountBindingChars ( LPCWSTR strIpAddress, DWORD dwPort )
  319. {
  320. _ASSERT ( IS_VALID_STRING ( strIpAddress ) );
  321. DWORD cchResult = 0;
  322. WCHAR wszPort [256];
  323. wsprintf ( wszPort, _T("%u"), dwPort );
  324. cchResult += lstrlen ( strIpAddress ); // <IPADDRESS>
  325. cchResult += 1; // :
  326. cchResult += lstrlen ( wszPort ); // <PORT>
  327. cchResult += 1; // :
  328. // cchResult += lstrlen ( strPathHeader ); // <PATHHEADER>
  329. cchResult += 1; // For the terminating NULL
  330. return cchResult;
  331. }
  332. static void ToBindingString ( LPCWSTR strIpAddress, DWORD dwPort, LPWSTR wszBinding )
  333. {
  334. _ASSERT ( IS_VALID_STRING ( strIpAddress ) );
  335. _ASSERT ( dwPort != 0 );
  336. _ASSERT ( !IsBadWritePtr ( wszBinding, CountBindingChars ( strIpAddress, dwPort ) ) );
  337. wsprintf ( wszBinding, _T("%s:%u:"), strIpAddress, dwPort );
  338. }
  339. static HRESULT FromBindingString ( LPCWSTR wszBinding, LPWSTR wszIpAddressOut, DWORD * pdwPort )
  340. {
  341. HRESULT hr = NOERROR;
  342. LPWSTR pchFirstColon;
  343. LPWSTR pchSecondColon;
  344. WCHAR wszIpAddress [ 256 ];
  345. WCHAR wszPort [ 256 ];
  346. long dwPort;
  347. LPWSTR pchColon;
  348. wszIpAddress[0] = NULL;
  349. wszPort[0] = NULL;
  350. pchFirstColon = wcschr ( wszBinding, _T(':') );
  351. if ( pchFirstColon ) {
  352. pchSecondColon = wcschr ( pchFirstColon + 1, _T(':') );
  353. }
  354. if ( !pchFirstColon || !pchSecondColon ) {
  355. hr = E_FAIL;
  356. goto Exit;
  357. }
  358. lstrcpyn ( wszIpAddress, wszBinding, 250 );
  359. lstrcpyn ( wszPort, pchFirstColon + 1, 250 );
  360. // Get the Port:
  361. dwPort = _wtoi ( wszPort );
  362. // Cutoff the IpAddress at the colon:
  363. pchColon = wcschr ( wszIpAddress, _T(':') );
  364. if ( pchColon ) {
  365. *pchColon = NULL;
  366. }
  367. lstrcpy ( wszIpAddressOut, wszIpAddress );
  368. *pdwPort = dwPort;
  369. Exit:
  370. return hr;
  371. }
  372. HRESULT
  373. MDBindingsToIBindings (
  374. CMultiSz * pmsz,
  375. BOOL fTcpBindings,
  376. IServerBindings * pBindings
  377. )
  378. {
  379. HRESULT hr = NOERROR;
  380. DWORD cBindings;
  381. DWORD i;
  382. LPCWSTR pchCurrent;
  383. CBinding binding;
  384. cBindings = pmsz->Count ();
  385. for (
  386. i = 0, pchCurrent = *pmsz;
  387. i < cBindings;
  388. i++, pchCurrent += lstrlen ( pchCurrent ) + 1
  389. ) {
  390. WCHAR wszIpAddress[512];
  391. DWORD dwPort;
  392. hr = FromBindingString ( pchCurrent, wszIpAddress, &dwPort );
  393. if ( FAILED(hr) ) {
  394. // Skip bad binding strings:
  395. hr = NOERROR;
  396. continue;
  397. }
  398. if ( fTcpBindings ) {
  399. hr = pBindings->Add ( wszIpAddress, dwPort, 0 );
  400. }
  401. else {
  402. hr = pBindings->Add ( wszIpAddress, 0, dwPort );
  403. }
  404. BAIL_ON_FAILURE(hr);
  405. }
  406. Exit:
  407. return hr;
  408. }
  409. HRESULT IBindingsToMDBindings (
  410. IServerBindings * pBindings,
  411. BOOL fTcpBindings,
  412. CMultiSz * pmsz
  413. )
  414. {
  415. HRESULT hr = NOERROR;
  416. long cBindings;
  417. long i;
  418. DWORD cbCount = 0;
  419. LPWSTR wszBindings = NULL;
  420. // Count the characters of the regular bindings list:
  421. cbCount = 0;
  422. pBindings->get_Count ( &cBindings );
  423. for ( i = 0; i < cBindings; i++ ) {
  424. CComPtr<IServerBinding> pBinding;
  425. CComBSTR strIpAddress;
  426. long lTcpPort;
  427. long lSslPort;
  428. hr = pBindings->Item ( i, &pBinding );
  429. BAIL_ON_FAILURE(hr);
  430. pBinding->get_IpAddress ( &strIpAddress );
  431. pBinding->get_TcpPort ( &lTcpPort );
  432. pBinding->get_SslPort ( &lSslPort );
  433. if ( fTcpBindings ) {
  434. if ( lTcpPort != 0 ) {
  435. cbCount += CountBindingChars ( strIpAddress, lTcpPort );
  436. }
  437. }
  438. else {
  439. if ( lSslPort != 0 ) {
  440. cbCount += CountBindingChars ( strIpAddress, lSslPort );
  441. }
  442. }
  443. }
  444. if ( cbCount == 0 ) {
  445. cbCount = 2;
  446. wszBindings = new WCHAR [ cbCount ];
  447. if ( !wszBindings ) {
  448. hr = E_OUTOFMEMORY;
  449. goto Exit;
  450. }
  451. wszBindings[0] = NULL;
  452. wszBindings[1] = NULL;
  453. }
  454. else {
  455. cbCount++; // For double null terminator
  456. wszBindings = new WCHAR [ cbCount ];
  457. if ( !wszBindings ) {
  458. BAIL_WITH_FAILURE(hr, E_OUTOFMEMORY);
  459. }
  460. LPWSTR pchCurrent = wszBindings;
  461. for ( i = 0; i < cBindings; i++ ) {
  462. CComPtr<IServerBinding> pBinding;
  463. CComBSTR strIpAddress;
  464. long lTcpPort;
  465. long lSslPort;
  466. hr = pBindings->Item ( i, &pBinding );
  467. BAIL_ON_FAILURE(hr);
  468. pBinding->get_IpAddress ( &strIpAddress );
  469. pBinding->get_TcpPort ( &lTcpPort );
  470. pBinding->get_SslPort ( &lSslPort );
  471. if ( fTcpBindings ) {
  472. if ( lTcpPort != 0 ) {
  473. ToBindingString ( strIpAddress, lTcpPort, pchCurrent );
  474. pchCurrent += lstrlen ( pchCurrent ) + 1;
  475. }
  476. }
  477. else {
  478. if ( lSslPort != 0 ) {
  479. ToBindingString ( strIpAddress, lSslPort, pchCurrent );
  480. pchCurrent += lstrlen ( pchCurrent ) + 1;
  481. }
  482. }
  483. }
  484. *pchCurrent = NULL;
  485. }
  486. _ASSERT ( wszBindings[cbCount - 1] == NULL );
  487. _ASSERT ( wszBindings[cbCount - 2] == NULL );
  488. pmsz->Attach ( wszBindings );
  489. Exit:
  490. return hr;
  491. }
  492. #if 0
  493. DWORD CBinding::SizeInChars ( )
  494. {
  495. DWORD cchResult = 0;
  496. WCHAR wszTcpPort [256];
  497. wsprintf ( wszTcpPort, _T("%d"), m_dwTcpPort );
  498. cchResult += lstrlen ( m_strIpAddress ); // <IPADDRESS>
  499. cchResult += 1; // :
  500. cchResult += lstrlen ( wszTcpPort ); // <TCPPORT>
  501. cchResult += 1; // :
  502. // cchResult += lstrlen ( m_strPathHeader ); // <PATHHEADER>
  503. return cchResult;
  504. }
  505. void CBinding::ToString ( LPWSTR wszBinding )
  506. {
  507. wsprintf ( wszBinding, _T("%s:%d:"), m_strIpAddress, m_dwTcpPort );
  508. }
  509. HRESULT CBinding::FromString ( LPCWSTR wszBinding )
  510. {
  511. HRESULT hr = NOERROR;
  512. LPWSTR pchFirstColon;
  513. LPWSTR pchSecondColon;
  514. WCHAR wszIpAddress [ 256 ];
  515. WCHAR wszTcpPort [ 256 ];
  516. long dwTcpPort;
  517. LPWSTR pchColon;
  518. wszIpAddress[0] = NULL;
  519. wszTcpPort[0] = NULL;
  520. pchFirstColon = wcschr ( wszBinding, _T(':') );
  521. if ( pchFirstColon ) {
  522. pchSecondColon = wcschr ( pchFirstColon + 1, _T(':') );
  523. }
  524. if ( !pchFirstColon || !pchSecondColon ) {
  525. hr = E_FAIL;
  526. goto Exit;
  527. }
  528. lstrcpyn ( wszIpAddress, wszBinding, 250 );
  529. lstrcpyn ( wszTcpPort, pchFirstColon + 1, 250 );
  530. // Get the TcpPort:
  531. dwTcpPort = _wtoi ( wszTcpPort );
  532. // Cutoff the IpAddress at the colon:
  533. pchColon = wcschr ( wszIpAddress, _T(':') );
  534. if ( pchColon ) {
  535. *pchColon = NULL;
  536. }
  537. m_strIpAddress = wszIpAddress;
  538. m_dwTcpPort = dwTcpPort;
  539. if ( !m_strIpAddress ) {
  540. hr = E_OUTOFMEMORY;
  541. goto Exit;
  542. }
  543. Exit:
  544. return hr;
  545. }
  546. HRESULT CServerBindings::FromMultiSz ( CMultiSz * pmsz )
  547. {
  548. HRESULT hr;
  549. DWORD cBindings;
  550. DWORD i;
  551. LPCWSTR pchCurrent;
  552. CBinding binding;
  553. hr = Clear ();
  554. _ASSERT ( SUCCEEDED(hr) );
  555. cBindings = pmsz->Count ();
  556. for (
  557. i = 0, pchCurrent = *pmsz;
  558. i < cBindings;
  559. i++, pchCurrent += lstrlen ( pchCurrent ) + 1
  560. ) {
  561. hr = binding.FromString ( pchCurrent );
  562. if ( FAILED(hr) ) {
  563. if ( hr == E_FAIL ) {
  564. // Skip the bad binding strings.
  565. continue;
  566. }
  567. else {
  568. goto Exit;
  569. }
  570. }
  571. hr = Add ( binding.m_strIpAddress, binding.m_dwTcpPort );
  572. if ( FAILED(hr) ) {
  573. goto Exit;
  574. }
  575. }
  576. Exit:
  577. return hr;
  578. }
  579. HRESULT CServerBindings::ToMultiSz ( CMultiSz * pmsz )
  580. {
  581. HRESULT hr = NOERROR;
  582. DWORD cchSize;
  583. long i;
  584. LPWSTR wszBindings;
  585. LPWSTR pchCurrent;
  586. // Special case - the empty binding list:
  587. if ( m_dwCount == 0 ) {
  588. cchSize = 2;
  589. wszBindings = new WCHAR [ cchSize ];
  590. if ( !wszBindings ) {
  591. hr = E_OUTOFMEMORY;
  592. goto Exit;
  593. }
  594. wszBindings[0] = NULL;
  595. wszBindings[1] = NULL;
  596. }
  597. else {
  598. cchSize = 0;
  599. for ( i = 0; i < m_dwCount; i++ ) {
  600. cchSize += m_rgBindings[i].SizeInChars ( ) + 1;
  601. }
  602. // Add the size of the final terminator:
  603. cchSize += 1;
  604. wszBindings = new WCHAR [ cchSize ];
  605. if ( !wszBindings ) {
  606. hr = E_OUTOFMEMORY;
  607. goto Exit;
  608. }
  609. for ( i = 0, pchCurrent = wszBindings; i < m_dwCount; i++ ) {
  610. m_rgBindings[i].ToString ( pchCurrent );
  611. pchCurrent += lstrlen ( pchCurrent ) + 1;
  612. }
  613. // Add the final NULL terminator:
  614. *pchCurrent = NULL;
  615. }
  616. _ASSERT ( wszBindings[cchSize - 1] == NULL );
  617. _ASSERT ( wszBindings[cchSize - 2] == NULL );
  618. pmsz->Attach ( wszBindings );
  619. _ASSERT ( pmsz->Count () == (DWORD) m_dwCount );
  620. Exit:
  621. return hr;
  622. }
  623. #endif