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.

864 lines
19 KiB

  1. // SAFIntercomServer.cpp : Implementation of CSAFIntercomServer
  2. #include "stdafx.h"
  3. // This is the PORT that we are using for the DPlayVoice connection
  4. //#define SAFINTERCOM_PORT 4000
  5. // *************************************************************
  6. // This GUID is defined for the sake of DPlay8Peer!
  7. // *************************************************************
  8. // {4FE80EF4-AD10-45bd-B6EB-0B7BFB95155F}
  9. static const GUID g_guidApplication =
  10. { 0x4fe80ef4, 0xad10, 0x45bd, { 0xb6, 0xeb, 0xb, 0x7b, 0xfb, 0x95, 0x15, 0x5f } };
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CSAFIntercomServer
  13. //
  14. // Constructor
  15. //
  16. CSAFIntercomServer::CSAFIntercomServer()
  17. {
  18. m_dwSinkCookie = 0x0;
  19. m_bInit = FALSE;
  20. m_bAdvised = FALSE;
  21. m_bRTCInit = FALSE;
  22. m_bOnCall = FALSE;
  23. m_iSamplingRate = 1; // Set the sampling rate to start at low
  24. }
  25. //
  26. // Destructor
  27. //
  28. CSAFIntercomServer::~CSAFIntercomServer()
  29. {
  30. DebugLog(L"CSAFIntercomServer Destructor!\r\n");
  31. Cleanup();
  32. }
  33. STDMETHODIMP CSAFIntercomServer::Event(RTC_EVENT RTCEvent, IDispatch * pEvent)
  34. {
  35. HRESULT hr = S_OK;
  36. CComPtr<IRTCSessionStateChangeEvent> pSessEvent;
  37. CComPtr<IRTCMediaEvent> pMedEvent;
  38. CComPtr<IRTCSession> pSession;
  39. HRESULT ResCode;
  40. RTC_SESSION_STATE State;
  41. switch(RTCEvent)
  42. {
  43. case RTCE_SESSION_STATE_CHANGE:
  44. hr = pEvent ->QueryInterface(IID_IRTCSessionStateChangeEvent,
  45. (void **)&pSessEvent);
  46. if(FAILED(hr))
  47. {
  48. return hr;
  49. }
  50. pSessEvent->get_StatusCode(&ResCode);
  51. pSessEvent->get_State(&State);
  52. pSessEvent->get_Session(&pSession);
  53. hr = OnSessionChange(pSession, State, ResCode);
  54. pSessEvent.Release();
  55. if(pSession)
  56. {
  57. pSession.Release();
  58. }
  59. break;
  60. case RTCE_MEDIA:
  61. hr = pEvent->QueryInterface(IID_IRTCMediaEvent, (void **)&pMedEvent);
  62. if (FAILED(hr))
  63. {
  64. DebugLog(L"Could not get IID_IRTCMediaEvent!\r\n");
  65. return hr;
  66. }
  67. hr = onMediaEvent(pMedEvent);
  68. if (FAILED(hr))
  69. {
  70. pMedEvent.Release();
  71. }
  72. break;
  73. }
  74. return hr;
  75. }
  76. HRESULT CSAFIntercomServer::onMediaEvent(IRTCMediaEvent * pMedEvent)
  77. {
  78. HRESULT hr = S_OK;
  79. long lMediaType;
  80. RTC_MEDIA_EVENT_TYPE EventType;
  81. RTC_MEDIA_EVENT_REASON EventReason;
  82. // Get all the values for this Event
  83. pMedEvent->get_MediaType(&lMediaType);
  84. pMedEvent->get_EventType(&EventType);
  85. pMedEvent->get_EventReason(&EventReason);
  86. // Make sure we are talking about audio
  87. if (!(
  88. ( lMediaType & RTCMT_AUDIO_SEND ) | // Send
  89. ( lMediaType & RTCMT_AUDIO_RECEIVE )
  90. )
  91. )
  92. {
  93. // Don't handle it since it's not an audio event
  94. return S_OK;
  95. }
  96. switch (EventType)
  97. {
  98. case RTCMET_STOPPED:
  99. // Check to see if we have stopped because of a timeout
  100. // SPECIAL CASE:
  101. // This is the case where we are in front of a firewall
  102. if (EventReason == RTCMER_TIMEOUT)
  103. {
  104. // Disable Voice
  105. Fire_onVoiceDisabled(this);
  106. }
  107. break;
  108. case RTCMET_FAILED:
  109. // Disable voice, something happened to the connection
  110. // Special Case:
  111. // This COULD be the case where one person is GUEST
  112. Fire_onVoiceDisabled(this);
  113. break;
  114. }
  115. return hr;
  116. }
  117. HRESULT CSAFIntercomServer::OnSessionChange(IRTCSession *pSession,
  118. RTC_SESSION_STATE nState,
  119. HRESULT ResCode)
  120. {
  121. HRESULT hr = S_OK;
  122. int iRet;
  123. switch (nState)
  124. {
  125. case RTCSS_INCOMING:
  126. if (m_bOnCall)
  127. {
  128. // We are on a call, reject
  129. pSession->Terminate(RTCTR_BUSY);
  130. return S_OK;
  131. }
  132. m_pRTCSession = pSession; // Make the incoming the active session
  133. // Set the key on the server side
  134. if (FAILED(hr = m_pRTCSession->put_EncryptionKey(RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE,
  135. m_bstrKey)))
  136. {
  137. DebugLog(L"put_EncryptionKey failed!\r\n");
  138. return hr;
  139. }
  140. m_pRTCSession->Answer();
  141. return S_OK;
  142. break;
  143. case RTCSS_CONNECTED:
  144. Fire_onVoiceConnected(this);
  145. m_bOnCall = TRUE;
  146. break;
  147. case RTCSS_DISCONNECTED:
  148. if (m_pRTCSession)
  149. {
  150. Fire_onVoiceDisconnected(this);
  151. }
  152. m_bOnCall = FALSE;
  153. if (m_pRTCSession)
  154. {
  155. m_pRTCSession.Release();
  156. }
  157. return S_OK;
  158. break;
  159. }
  160. return hr;
  161. }
  162. STDMETHODIMP CSAFIntercomServer::Listen(/* out, retval */ BSTR * pVal)
  163. {
  164. HRESULT hr = S_OK;
  165. VARIANT_BOOL vbRun;
  166. long flags;
  167. /*
  168. if (m_bInit)
  169. {
  170. DebugLog(L"Cannot call Listen(...) twice\r\n");
  171. return E_FAIL;
  172. }
  173. */
  174. // Initialize the Server
  175. if (FAILED(hr = Init()))
  176. {
  177. DebugLog(L"Call to Init() failed!\r\n");
  178. Fire_onVoiceDisabled(this);
  179. return hr;
  180. }
  181. // Get media capabilities.
  182. // Question: Do we have audio send and receive capabilities on this machine?
  183. if (FAILED( hr = m_pRTCClient->get_MediaCapabilities(&flags)))
  184. {
  185. DebugLog(L"Call to get_MediaCapabilities failed!\r\n");
  186. Fire_onVoiceDisabled(this);
  187. return hr;
  188. }
  189. // Check results
  190. if ( !(flags & ( RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE )) )
  191. {
  192. DebugLog(L"This machine does not have audio capabilites, Voice is Disabled!\r\n");
  193. Fire_onVoiceDisabled(this);
  194. return hr;
  195. }
  196. // If we have never run the Audio wizard, run it now
  197. if (FAILED( hr = m_pRTCClient->get_IsTuned(&vbRun)))
  198. {
  199. DebugLog(L"Call to IsTuned failed!\r\n");
  200. Fire_onVoiceDisabled(this);
  201. return hr;
  202. }
  203. if (VARIANT_FALSE == vbRun)
  204. {
  205. if (FAILED(hr = RunSetupWizard()))
  206. {
  207. DebugLog(L"Call to RunSetupWizard() failed!\r\n");
  208. return hr;
  209. }
  210. }
  211. VARIANT_BOOL vbTCP = VARIANT_FALSE;
  212. VARIANT_BOOL vbExternal = VARIANT_TRUE;
  213. VARIANT vsaAddresses;
  214. VARIANT vsaIntAddresses;
  215. MPC::WStringList listIPs;
  216. MPC::WStringIter listIPIter;
  217. MPC::WStringList listIntIPs;
  218. MPC::WStringIter listIntIPIter;
  219. CComBSTR bstrTemp;
  220. // Grab the IP SAFEARRAY from the RTC object
  221. if (FAILED( hr = m_pRTCClient->get_NetworkAddresses(vbTCP, vbExternal, &vsaAddresses)))
  222. {
  223. DebugLog(L"call to get_NetworkAddresses failed!\r\n");
  224. Fire_onVoiceDisabled(this);
  225. return hr;
  226. }
  227. // Convert the SAFEARRAY to a list of wstrings
  228. if (FAILED(hr = MPC::ConvertSafeArrayToList(vsaAddresses, listIPs)))
  229. {
  230. DebugLog(L"call to ConvertSafeArrayToList failed!\r\n");
  231. Fire_onVoiceDisabled(this);
  232. return hr;
  233. }
  234. // get our intenal IP
  235. vbExternal = VARIANT_FALSE;
  236. if (FAILED( hr = m_pRTCClient->get_NetworkAddresses(vbTCP, vbExternal, &vsaIntAddresses)))
  237. {
  238. DebugLog(L"call to get_NetworkAddresses failed (Internal)\r\n");
  239. Fire_onVoiceDisabled(this);
  240. return hr;
  241. }
  242. if (FAILED( hr = MPC::ConvertSafeArrayToList(vsaIntAddresses, listIntIPs)))
  243. {
  244. DebugLog(L"call to ConvertSafeArrayToList failed!\r\n");
  245. Fire_onVoiceDisabled(this);
  246. return hr;
  247. }
  248. m_bInit = TRUE;
  249. // Place the Key in the front of the string
  250. bstrTemp = m_bstrKey;
  251. // append all the ip:port's to the key string (external)
  252. for(listIPIter = listIPs.begin(); listIPIter != listIPs.end(); listIPIter++)
  253. {
  254. bstrTemp += L";";
  255. bstrTemp += (*listIPIter).c_str();
  256. }
  257. // append all internal ip:port's to the key string (internal)
  258. for(listIntIPIter = listIntIPs.begin(); listIntIPIter != listIntIPs.end(); listIntIPIter++)
  259. {
  260. bstrTemp += L";";
  261. bstrTemp += (*listIntIPIter).c_str();
  262. }
  263. // Note: m_bstrKey could be changed by calling RunSetupWizard, thus set the return
  264. // value now (at the end of this function)
  265. *pVal = bstrTemp.Copy();
  266. return S_OK;
  267. }
  268. STDMETHODIMP CSAFIntercomServer::Disconnect()
  269. {
  270. // TODO: make sure we handle the case where we are shutting down.
  271. // Find out if we care about RTCSHUTDOWN
  272. HRESULT hr;
  273. if (!m_bOnCall)
  274. {
  275. DebugLog(L"Must be on a call to call Disconnect!\r\n");
  276. return E_FAIL;
  277. }
  278. if (m_pRTCSession)
  279. {
  280. if (FAILED( hr = m_pRTCSession->Terminate(RTCTR_NORMAL)))
  281. {
  282. DebugLog(L"Terminate off of the Session object failed!\r\n");
  283. return hr;
  284. }
  285. m_pRTCSession.Release();
  286. }
  287. return S_OK;
  288. }
  289. //
  290. // This method is used to Unadvise the RTCClient object of us (CSAFIntercomServer)
  291. //
  292. STDMETHODIMP CSAFIntercomServer::Exit()
  293. {
  294. HRESULT hr;
  295. DebugLog(L"Inside CSAFIntercomServer::Exit()\r\n");
  296. // Unadvise IRTCClient of the sink
  297. if (m_bAdvised)
  298. {
  299. AtlUnadvise((IUnknown *)m_pRTCClient, IID_IRTCEventNotification, m_dwSinkCookie);
  300. }
  301. return S_OK;
  302. }
  303. HRESULT CSAFIntercomServer::RunSetupWizard()
  304. {
  305. HRESULT hr = S_OK;
  306. long flags;
  307. // Setup
  308. if (FAILED(hr = Init()))
  309. {
  310. DebugLog(L"Call to Init() failed!\r\n");
  311. Fire_onVoiceDisabled(this);
  312. return hr;
  313. }
  314. if (FAILED(hr = m_pRTCClient->InvokeTuningWizard(NULL)))
  315. {
  316. DebugLog(L"InvokeTuningWizard FAILED!\r\n");
  317. Fire_onVoiceDisabled(this);
  318. return hr;
  319. }
  320. // Get media capabilities. If the wizard failed to detect sound we can
  321. // disable Voice
  322. if (FAILED( hr = m_pRTCClient->get_MediaCapabilities(&flags)))
  323. {
  324. DebugLog(L"Call to get_MediaCapabilities failed!\r\n");
  325. Fire_onVoiceDisabled(this);
  326. return hr;
  327. }
  328. // Check results
  329. if ( !(flags & ( RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE )) )
  330. {
  331. DebugLog(L"This machine does not have audio capabilites, Voice is Disabled!\r\n");
  332. Fire_onVoiceDisabled(this);
  333. return E_FAIL;
  334. }
  335. return S_OK;
  336. }
  337. HRESULT CSAFIntercomServer::Init()
  338. {
  339. HRESULT hr = S_OK;
  340. CComPtr<IUnknown> pUnkThis;
  341. // First Generate the Key
  342. if (ERROR_SUCCESS != GenerateRandomString(32, &m_bstrKey))
  343. {
  344. DebugLog(L"GenerateRandomString Failed!\r\n");
  345. return E_FAIL;
  346. }
  347. // Once the object exists, do nothing
  348. if (!m_pRTCClient)
  349. {
  350. DWORD dwProfileFlags;
  351. // Check to see if we have a temporary profile
  352. if(GetProfileType( &dwProfileFlags ))
  353. {
  354. if (dwProfileFlags & PT_TEMPORARY)
  355. {
  356. return E_FAIL;
  357. }
  358. }
  359. // Create the RTCClient object
  360. if (FAILED(hr = m_pRTCClient.CoCreateInstance(CLSID_RTCClient)))
  361. {
  362. DebugLog(L"Could not create the RTCClient object\r\n");
  363. return hr;
  364. }
  365. if (FAILED(hr = m_pRTCClient->Initialize()))
  366. {
  367. DebugLog(L"Call to Initialize on the RTCClient object failed!\r\n");
  368. return hr;
  369. }
  370. // Set the sampling bit rate (it may be different because of changes in the property)
  371. if (m_iSamplingRate == 1)
  372. {
  373. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(6400)))
  374. {
  375. DebugLog(L"put_MaxBitrate failed!\r\n");
  376. }
  377. }
  378. else
  379. {
  380. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(64000)))
  381. {
  382. DebugLog(L"put_MaxBitrate failed!\r\n");
  383. }
  384. }
  385. // Since we have Initialized the RTCClient, enable the flag
  386. m_bRTCInit = TRUE;
  387. if (FAILED(hr = m_pRTCClient->SetPreferredMediaTypes( RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE,
  388. FALSE )))
  389. {
  390. DebugLog(L"Call to SetPreferredMediaType failed!\r\n");
  391. return hr;
  392. }
  393. // Get the IUnknown of the 'this' ptr
  394. if (FAILED( hr = this->QueryInterface(IID_IUnknown, (void **)&pUnkThis)))
  395. {
  396. DebugLog(L"QueryInterface for IUnknown failed!\r\n");
  397. return hr;
  398. }
  399. // Advise IRTCClient of the sink
  400. if (FAILED( hr = m_pRTCClient.Advise( pUnkThis, IID_IRTCEventNotification, &m_dwSinkCookie)))
  401. {
  402. DebugLog(L"AtlAdvise failed!\r\n");
  403. return hr;
  404. }
  405. m_bAdvised = TRUE;
  406. // TODO: Verify about RTCLM_BOTH
  407. if (FAILED( hr = m_pRTCClient->put_ListenForIncomingSessions(RTCLM_BOTH)))
  408. {
  409. DebugLog(L"Set ListenForIncomingSessions property failed!\r\n");
  410. return hr;
  411. }
  412. }
  413. return hr;
  414. }
  415. HRESULT CSAFIntercomServer::Cleanup()
  416. {
  417. HRESULT hr = S_OK;
  418. // Shutdown if needed
  419. if (m_bRTCInit)
  420. {
  421. m_pRTCClient->Shutdown();
  422. }
  423. // Unadvise IRTCClient of the sink
  424. if (m_bAdvised)
  425. {
  426. AtlUnadvise((IUnknown *)m_pRTCClient, IID_IRTCEventNotification, m_dwSinkCookie);
  427. }
  428. // Now release all the interfaces we used
  429. if (m_pRTCSession)
  430. {
  431. m_pRTCSession.Release();
  432. }
  433. if (m_pRTCClient)
  434. {
  435. m_pRTCClient.Release();
  436. }
  437. return hr;
  438. }
  439. /////////////////////////////////////////////////////////////////////////////
  440. /////////////////////////////////////////////////////////////////////////////
  441. //////////////////////////
  442. // //
  443. // Event Firing Methods //
  444. // //
  445. //////////////////////////
  446. HRESULT CSAFIntercomServer::Fire_onVoiceConnected( ISAFIntercomServer * safi)
  447. {
  448. CComVariant pvars[1];
  449. pvars[0] = safi;
  450. return FireAsync_Generic( DISPID_PCH_INSE__ONDISCONNECTED, pvars, ARRAYSIZE( pvars ), m_sink_onVoiceConnected );
  451. }
  452. HRESULT CSAFIntercomServer::Fire_onVoiceDisconnected( ISAFIntercomServer * safi)
  453. {
  454. CComVariant pvars[1];
  455. pvars[0] = safi;
  456. return FireAsync_Generic( DISPID_PCH_INSE__ONDISCONNECTED, pvars, ARRAYSIZE( pvars ), m_sink_onVoiceDisconnected );
  457. }
  458. HRESULT CSAFIntercomServer::Fire_onVoiceDisabled( ISAFIntercomServer * safi)
  459. {
  460. CComVariant pvars[1];
  461. pvars[0] = safi;
  462. return FireAsync_Generic( DISPID_PCH_INSE__ONVOICEDISABLED, pvars, ARRAYSIZE( pvars ), m_sink_onVoiceDisabled );
  463. }
  464. //////////////////////////
  465. // //
  466. // Properties //
  467. // //
  468. //////////////////////////
  469. STDMETHODIMP CSAFIntercomServer::put_onVoiceConnected( /*[in]*/ IDispatch* function )
  470. {
  471. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomServer::put_onVoiceConnected",hr);
  472. m_sink_onVoiceConnected = function;
  473. __HCP_END_PROPERTY(hr);
  474. }
  475. STDMETHODIMP CSAFIntercomServer::put_onVoiceDisconnected( /*[in]*/ IDispatch* function )
  476. {
  477. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomServer::put_onVoiceDisconnected",hr);
  478. m_sink_onVoiceDisconnected = function;
  479. __HCP_END_PROPERTY(hr);
  480. }
  481. STDMETHODIMP CSAFIntercomServer::put_onVoiceDisabled( /*[in]*/ IDispatch* function)
  482. {
  483. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomServer::put_onVoiceDisconnected",hr);
  484. m_sink_onVoiceDisabled = function;
  485. __HCP_END_PROPERTY(hr);
  486. }
  487. STDMETHODIMP CSAFIntercomServer::put_SamplingRate ( /*[in]*/ LONG newVal)
  488. {
  489. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomServer::put_SamplingRate", hr);
  490. hr = S_OK;
  491. // Make sure that the newVal is correct
  492. if ((newVal == 1) || (newVal == 2))
  493. {
  494. // If m_pRTCClient doesn't exist then persist the m_iSamplingRate for when it is created
  495. m_iSamplingRate = newVal;
  496. if (m_pRTCClient)
  497. {
  498. // Set the MaxBitRates on the client, because it exists (m_pRTCClient)
  499. if (m_iSamplingRate == 1)
  500. {
  501. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(6400)))
  502. {
  503. DebugLog(L"put_MaxBitrate failed!\r\n");
  504. }
  505. }
  506. else
  507. {
  508. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(64000)))
  509. {
  510. DebugLog(L"put_MaxBitrate failed!\r\n");
  511. }
  512. }
  513. }
  514. }
  515. else
  516. {
  517. hr = E_INVALIDARG;
  518. }
  519. __HCP_END_PROPERTY(hr);
  520. }
  521. STDMETHODIMP CSAFIntercomServer::get_SamplingRate (/*[out, retval]*/ LONG * pVal )
  522. {
  523. __HCP_BEGIN_PROPERTY_GET("CSAFIntercomServer::put_SamplingRate", hr, pVal);
  524. *pVal = m_iSamplingRate;
  525. hr = S_OK;
  526. __HCP_END_PROPERTY(hr);
  527. }
  528. /////////////////////////////////////////////////////////////////////////////
  529. /////////////////////////////////////////////////////////////////////////////
  530. DWORD
  531. CSAFIntercomServer::GenerateRandomBytes(
  532. IN DWORD dwSize,
  533. IN OUT LPBYTE pbBuffer
  534. )
  535. /*++
  536. Description:
  537. Generate fill buffer with random bytes.
  538. Parameters:
  539. dwSize : Size of buffer pbBuffer point to.
  540. pbBuffer : Pointer to buffer to hold the random bytes.
  541. Returns:
  542. TRUE/FALSE
  543. --*/
  544. {
  545. HCRYPTPROV hProv = NULL;
  546. DWORD dwStatus = ERROR_SUCCESS;
  547. //
  548. // Create a Crypto Provider to generate random number
  549. //
  550. if( !CryptAcquireContext(
  551. &hProv,
  552. NULL,
  553. NULL,
  554. PROV_RSA_FULL,
  555. CRYPT_VERIFYCONTEXT
  556. ) )
  557. {
  558. dwStatus = GetLastError();
  559. goto CLEANUPANDEXIT;
  560. }
  561. if( !CryptGenRandom(hProv, dwSize, pbBuffer) )
  562. {
  563. dwStatus = GetLastError();
  564. }
  565. CLEANUPANDEXIT:
  566. if( NULL != hProv )
  567. {
  568. CryptReleaseContext( hProv, 0 );
  569. }
  570. return dwStatus;
  571. }
  572. DWORD
  573. CSAFIntercomServer::GenerateRandomString(
  574. IN DWORD dwSizeRandomSeed,
  575. IN OUT BSTR *pBstr
  576. )
  577. /*++
  578. Generate a
  579. --*/
  580. {
  581. PBYTE lpBuffer = NULL;
  582. DWORD dwStatus = ERROR_SUCCESS;
  583. BOOL bSuccess;
  584. DWORD cbConvertString = 0;
  585. WCHAR *szString = NULL;
  586. BSTR bstrTemp = NULL;
  587. if( 0 == dwSizeRandomSeed || NULL == pBstr )
  588. {
  589. dwStatus = ERROR_INVALID_PARAMETER;
  590. goto CLEANUPANDEXIT;
  591. }
  592. //*pBstr = NULL;
  593. lpBuffer = (PBYTE)LocalAlloc( LPTR, dwSizeRandomSeed );
  594. if( NULL == lpBuffer )
  595. {
  596. dwStatus = GetLastError();
  597. goto CLEANUPANDEXIT;
  598. }
  599. dwStatus = GenerateRandomBytes( dwSizeRandomSeed, lpBuffer );
  600. if( ERROR_SUCCESS != dwStatus )
  601. {
  602. goto CLEANUPANDEXIT;
  603. }
  604. // Convert to string
  605. bSuccess = CryptBinaryToString(
  606. lpBuffer,
  607. dwSizeRandomSeed,
  608. CRYPT_STRING_BASE64,
  609. 0,
  610. &cbConvertString
  611. );
  612. if( FALSE == bSuccess )
  613. {
  614. dwStatus = GetLastError();
  615. goto CLEANUPANDEXIT;
  616. }
  617. szString = (LPWSTR)LocalAlloc( LPTR, (cbConvertString+1)*sizeof(WCHAR) );
  618. if( NULL == szString )
  619. {
  620. dwStatus = GetLastError();
  621. goto CLEANUPANDEXIT;
  622. }
  623. bSuccess = CryptBinaryToString(
  624. lpBuffer,
  625. dwSizeRandomSeed,
  626. CRYPT_STRING_BASE64,
  627. szString,
  628. &cbConvertString
  629. );
  630. if( FALSE == bSuccess )
  631. {
  632. dwStatus = GetLastError();
  633. }
  634. else
  635. {
  636. if( (szString)[cbConvertString - 1] == '\n' &&
  637. (szString)[cbConvertString - 2] == '\r' )
  638. {
  639. (szString)[cbConvertString - 2] = 0;
  640. }
  641. }
  642. // Place the string in the temp
  643. bstrTemp = SysAllocString(szString);
  644. // Set the return value: pBstr to the BSTR that contains this generated stiring
  645. *pBstr = bstrTemp;
  646. CLEANUPANDEXIT:
  647. if( ERROR_SUCCESS != dwStatus )
  648. {
  649. if( NULL != szString )
  650. {
  651. LocalFree(szString);
  652. }
  653. }
  654. if( NULL != lpBuffer )
  655. {
  656. LocalFree(lpBuffer);
  657. }
  658. return dwStatus;
  659. }