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.

795 lines
16 KiB

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