Team Fortress 2 Source Code as on 22/4/2020
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.

2754 lines
77 KiB

  1. /*******************************************************************************
  2. * SPHelper.h *
  3. *------------*
  4. * Description:
  5. * This is the header file for core helper functions implementation.
  6. *-------------------------------------------------------------------------------
  7. * Copyright (c) Microsoft Corporation. All rights reserved.
  8. *******************************************************************************/
  9. #ifndef SPHelper_h
  10. #define SPHelper_h
  11. #ifndef _INC_MALLOC
  12. #include <malloc.h>
  13. #endif
  14. #ifndef _INC_CRTDBG
  15. #include <crtdbg.h>
  16. #endif
  17. #ifndef __sapi_h__
  18. #include <sapi.h>
  19. #endif
  20. #ifndef __sapiddk_h__
  21. #include <sapiddk.h>
  22. #endif
  23. #ifndef SPError_h
  24. #include <SPError.h>
  25. #endif
  26. #ifndef SPDebug_h
  27. #include <SPDebug.h>
  28. #endif
  29. #ifndef _INC_LIMITS
  30. #include <limits.h>
  31. #endif
  32. #ifndef _INC_MMSYSTEM
  33. #include <mmsystem.h>
  34. #endif
  35. #ifndef __comcat_h__
  36. #include <comcat.h>
  37. #endif
  38. #ifndef _INC_MMREG
  39. #include <mmreg.h>
  40. #endif
  41. #ifndef __ATLBASE_H__
  42. #include <atlbase.h>
  43. #endif
  44. //=== Constants ==============================================================
  45. #define sp_countof(x) ((sizeof(x) / sizeof(*(x))))
  46. /*** CSpDynamicString helper class
  47. *
  48. */
  49. class CSpDynamicString
  50. {
  51. public:
  52. WCHAR * m_psz;
  53. CSpDynamicString()
  54. {
  55. m_psz = NULL;
  56. }
  57. CSpDynamicString(size_t cchReserve)
  58. {
  59. m_psz = (WCHAR *)::CoTaskMemAlloc(cchReserve * sizeof(WCHAR));
  60. }
  61. WCHAR * operator=(const CSpDynamicString& src)
  62. {
  63. if (m_psz != src.m_psz)
  64. {
  65. ::CoTaskMemFree(m_psz);
  66. m_psz = src.Copy();
  67. }
  68. return m_psz;
  69. }
  70. WCHAR * operator=(const WCHAR * pSrc)
  71. {
  72. Clear();
  73. if (pSrc)
  74. {
  75. size_t cbNeeded = (wcslen(pSrc) + 1) * sizeof(WCHAR);
  76. m_psz = (WCHAR *)::CoTaskMemAlloc(cbNeeded);
  77. SPDBG_ASSERT(m_psz);
  78. if (m_psz)
  79. {
  80. memcpy(m_psz, pSrc, cbNeeded);
  81. }
  82. }
  83. return m_psz;
  84. }
  85. WCHAR * operator=(const char * pSrc)
  86. {
  87. Clear();
  88. if (pSrc)
  89. {
  90. ULONG cbNeeded = (lstrlenA(pSrc) + 1) * sizeof(WCHAR);
  91. m_psz = (WCHAR *)::CoTaskMemAlloc(cbNeeded);
  92. SPDBG_ASSERT(m_psz);
  93. if (m_psz)
  94. {
  95. ::MultiByteToWideChar(CP_ACP, 0, pSrc, -1, m_psz, cbNeeded/sizeof(WCHAR));
  96. }
  97. }
  98. return m_psz;
  99. }
  100. WCHAR * operator=(REFGUID rguid)
  101. {
  102. Clear();
  103. ::StringFromCLSID(rguid, &m_psz);
  104. return m_psz;
  105. }
  106. /*explicit*/ CSpDynamicString(const WCHAR * pSrc)
  107. {
  108. m_psz = NULL;
  109. operator=(pSrc);
  110. }
  111. /*explicit*/ CSpDynamicString(const char * pSrc)
  112. {
  113. m_psz = NULL;
  114. operator=(pSrc);
  115. }
  116. /*explicit*/ CSpDynamicString(const CSpDynamicString& src)
  117. {
  118. m_psz = src.Copy();
  119. }
  120. /*explicit*/ CSpDynamicString(REFGUID rguid)
  121. {
  122. ::StringFromCLSID(rguid, &m_psz);
  123. }
  124. ~CSpDynamicString()
  125. {
  126. ::CoTaskMemFree(m_psz);
  127. }
  128. unsigned int Length() const
  129. {
  130. return static_cast<unsigned int>( (m_psz == NULL)? 0 : wcslen(m_psz) );
  131. }
  132. operator WCHAR * () const
  133. {
  134. return m_psz;
  135. }
  136. //The assert on operator& usually indicates a bug. If this is really
  137. //what is needed, however, take the address of the m_psz member explicitly.
  138. WCHAR ** operator&()
  139. {
  140. SPDBG_ASSERT(m_psz == NULL);
  141. return &m_psz;
  142. }
  143. WCHAR * Append(const WCHAR * pszSrc)
  144. {
  145. if (pszSrc)
  146. {
  147. size_t lenSrc = wcslen(pszSrc);
  148. if (lenSrc)
  149. {
  150. ULONG lenMe = Length();
  151. WCHAR *pszNew = (WCHAR *)::CoTaskMemAlloc((lenMe + lenSrc + 1) * sizeof(WCHAR));
  152. if (pszNew)
  153. {
  154. if (m_psz) // Could append to an empty string so check...
  155. {
  156. if (lenMe)
  157. {
  158. memcpy(pszNew, m_psz, lenMe * sizeof(WCHAR));
  159. }
  160. ::CoTaskMemFree(m_psz);
  161. }
  162. memcpy(pszNew + lenMe, pszSrc, (lenSrc + 1) * sizeof(WCHAR));
  163. m_psz = pszNew;
  164. }
  165. else
  166. {
  167. SPDBG_ASSERT(FALSE);
  168. }
  169. }
  170. }
  171. return m_psz;
  172. }
  173. WCHAR * Append(const WCHAR * pszSrc, const ULONG lenSrc)
  174. {
  175. if (pszSrc && lenSrc)
  176. {
  177. ULONG lenMe = Length();
  178. WCHAR *pszNew = (WCHAR *)::CoTaskMemAlloc((lenMe + lenSrc + 1) * sizeof(WCHAR));
  179. if (pszNew)
  180. {
  181. if (m_psz) // Could append to an empty string so check...
  182. {
  183. if (lenMe)
  184. {
  185. memcpy(pszNew, m_psz, lenMe * sizeof(WCHAR));
  186. }
  187. ::CoTaskMemFree(m_psz);
  188. }
  189. memcpy(pszNew + lenMe, pszSrc, lenSrc * sizeof(WCHAR));
  190. *(pszNew + lenMe + lenSrc) = L'\0';
  191. m_psz = pszNew;
  192. }
  193. else
  194. {
  195. SPDBG_ASSERT(FALSE);
  196. }
  197. }
  198. return m_psz;
  199. }
  200. WCHAR * Append2(const WCHAR * pszSrc1, const WCHAR * pszSrc2)
  201. {
  202. size_t lenSrc1 = pszSrc1 ? wcslen(pszSrc1) : 0;
  203. size_t lenSrc2 = pszSrc2 ? wcslen(pszSrc2) : 0;
  204. if (lenSrc1 || lenSrc2)
  205. {
  206. ULONG lenMe = Length();
  207. WCHAR *pszNew = (WCHAR *)::CoTaskMemAlloc((lenMe + lenSrc1 + lenSrc2 + 1) * sizeof(WCHAR));
  208. if (pszNew)
  209. {
  210. if (m_psz) // Could append to an empty string so check...
  211. {
  212. if (lenMe)
  213. {
  214. memcpy(pszNew, m_psz, lenMe * sizeof(WCHAR));
  215. }
  216. ::CoTaskMemFree(m_psz);
  217. }
  218. // In both of these cases, we copy the trailing NULL so that we're sure it gets
  219. // there (if lenSrc2 is 0 then we better copy it from pszSrc1).
  220. if (lenSrc1)
  221. {
  222. memcpy(pszNew + lenMe, pszSrc1, (lenSrc1 + 1) * sizeof(WCHAR));
  223. }
  224. if (lenSrc2)
  225. {
  226. memcpy(pszNew + lenMe + lenSrc1, pszSrc2, (lenSrc2 + 1) * sizeof(WCHAR));
  227. }
  228. m_psz = pszNew;
  229. }
  230. else
  231. {
  232. SPDBG_ASSERT(FALSE);
  233. }
  234. }
  235. return m_psz;
  236. }
  237. WCHAR * Copy() const
  238. {
  239. if (m_psz)
  240. {
  241. CSpDynamicString szNew(m_psz);
  242. return szNew.Detach();
  243. }
  244. return NULL;
  245. }
  246. CHAR * CopyToChar() const
  247. {
  248. if (m_psz)
  249. {
  250. CHAR* psz;
  251. ULONG cbNeeded = ::WideCharToMultiByte(CP_ACP, 0, m_psz, -1, NULL, NULL, NULL, NULL);
  252. psz = (CHAR *)::CoTaskMemAlloc(cbNeeded);
  253. SPDBG_ASSERT(psz);
  254. if (psz)
  255. {
  256. ::WideCharToMultiByte(CP_ACP, 0, m_psz, -1, psz, cbNeeded/sizeof(CHAR), NULL, NULL);
  257. }
  258. return psz;
  259. }
  260. return NULL;
  261. }
  262. void Attach(WCHAR * pszSrc)
  263. {
  264. SPDBG_ASSERT(m_psz == NULL);
  265. m_psz = pszSrc;
  266. }
  267. WCHAR * Detach()
  268. {
  269. WCHAR * s = m_psz;
  270. m_psz = NULL;
  271. return s;
  272. }
  273. void Clear()
  274. {
  275. ::CoTaskMemFree(m_psz);
  276. m_psz = NULL;
  277. }
  278. bool operator!() const
  279. {
  280. return (m_psz == NULL);
  281. }
  282. HRESULT CopyToBSTR(BSTR * pbstr)
  283. {
  284. if (m_psz)
  285. {
  286. *pbstr = ::SysAllocString(m_psz);
  287. if (*pbstr == NULL)
  288. {
  289. return E_OUTOFMEMORY;
  290. }
  291. }
  292. else
  293. {
  294. *pbstr = NULL;
  295. }
  296. return S_OK;
  297. }
  298. void TrimToSize(ULONG ulNumChars)
  299. {
  300. if (m_psz && ulNumChars < Length())
  301. {
  302. m_psz[ulNumChars] = 0;
  303. }
  304. }
  305. WCHAR * Compact()
  306. {
  307. if (m_psz)
  308. {
  309. size_t cch = wcslen(m_psz);
  310. m_psz = (WCHAR *)::CoTaskMemRealloc(m_psz, (cch + 1) * sizeof(WCHAR));
  311. }
  312. return m_psz;
  313. }
  314. WCHAR * ClearAndGrowTo(ULONG cch)
  315. {
  316. if (m_psz)
  317. {
  318. Clear();
  319. }
  320. m_psz = (WCHAR *)::CoTaskMemAlloc(cch * sizeof(WCHAR));
  321. return m_psz;
  322. }
  323. WCHAR * LTrim()
  324. {
  325. if (m_psz)
  326. {
  327. WCHAR * pszRead = m_psz;
  328. while (iswspace(*pszRead))
  329. {
  330. pszRead++;
  331. }
  332. if (pszRead != m_psz)
  333. {
  334. WCHAR * pszWrite = m_psz;
  335. while (*pszRead)
  336. {
  337. *pszWrite++ = *pszRead++;
  338. }
  339. *pszWrite = '\0';
  340. }
  341. }
  342. return m_psz;
  343. }
  344. WCHAR * RTrim()
  345. {
  346. if (m_psz)
  347. {
  348. WCHAR * pszTail = m_psz + wcslen(m_psz);
  349. WCHAR * pszZeroTerm = pszTail;
  350. while (pszZeroTerm > m_psz && iswspace(pszZeroTerm[-1]))
  351. {
  352. pszZeroTerm--;
  353. }
  354. if (pszZeroTerm != pszTail)
  355. {
  356. *pszZeroTerm = '\0';
  357. }
  358. }
  359. return m_psz;
  360. }
  361. WCHAR * TrimBoth()
  362. {
  363. RTrim();
  364. return LTrim();
  365. }
  366. };
  367. //
  368. // Simple inline function converts a ulong to a hex string.
  369. //
  370. inline void SpHexFromUlong(WCHAR * psz, ULONG ul)
  371. {
  372. const static WCHAR szHexChars[] = L"0123456789ABCDEF";
  373. if (ul == 0)
  374. {
  375. psz[0] = L'0';
  376. psz[1] = 0;
  377. }
  378. else
  379. {
  380. ULONG ulChars = 1;
  381. psz[0] = 0;
  382. while (ul)
  383. {
  384. memmove(psz + 1, psz, ulChars * sizeof(WCHAR));
  385. psz[0] = szHexChars[ul % 16];
  386. ul /= 16;
  387. ulChars++;
  388. }
  389. }
  390. }
  391. //=== Token helpers
  392. inline HRESULT SpGetTokenFromId(
  393. const WCHAR * pszTokenId,
  394. ISpObjectToken ** ppToken,
  395. BOOL fCreateIfNotExist = FALSE)
  396. {
  397. SPDBG_FUNC("SpGetTokenFromId");
  398. HRESULT hr;
  399. CComPtr<ISpObjectToken> cpToken;
  400. hr = cpToken.CoCreateInstance(CLSID_SpObjectToken);
  401. if (SUCCEEDED(hr))
  402. {
  403. hr = cpToken->SetId(NULL, pszTokenId, fCreateIfNotExist);
  404. }
  405. if (SUCCEEDED(hr))
  406. {
  407. *ppToken = cpToken.Detach();
  408. }
  409. if (hr != SPERR_NOT_FOUND)
  410. {
  411. SPDBG_REPORT_ON_FAIL(hr);
  412. }
  413. return hr;
  414. }
  415. inline HRESULT SpGetCategoryFromId(
  416. const WCHAR * pszCategoryId,
  417. ISpObjectTokenCategory ** ppCategory,
  418. BOOL fCreateIfNotExist = FALSE)
  419. {
  420. SPDBG_FUNC("SpGetCategoryFromId");
  421. HRESULT hr;
  422. CComPtr<ISpObjectTokenCategory> cpTokenCategory;
  423. hr = cpTokenCategory.CoCreateInstance(CLSID_SpObjectTokenCategory);
  424. if (SUCCEEDED(hr))
  425. {
  426. hr = cpTokenCategory->SetId(pszCategoryId, fCreateIfNotExist);
  427. }
  428. if (SUCCEEDED(hr))
  429. {
  430. *ppCategory = cpTokenCategory.Detach();
  431. }
  432. SPDBG_REPORT_ON_FAIL(hr);
  433. return hr;
  434. }
  435. inline HRESULT SpGetDefaultTokenIdFromCategoryId(
  436. const WCHAR * pszCategoryId,
  437. WCHAR ** ppszTokenId)
  438. {
  439. SPDBG_FUNC("SpGetDefaultTokenFromCategoryId");
  440. HRESULT hr;
  441. CComPtr<ISpObjectTokenCategory> cpCategory;
  442. hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
  443. if (SUCCEEDED(hr))
  444. {
  445. hr = cpCategory->GetDefaultTokenId(ppszTokenId);
  446. }
  447. return hr;
  448. }
  449. inline HRESULT SpSetDefaultTokenIdForCategoryId(
  450. const WCHAR * pszCategoryId,
  451. const WCHAR * pszTokenId)
  452. {
  453. SPDBG_FUNC("SpSetDefaultTokenIdForCategoryId");
  454. HRESULT hr;
  455. CComPtr<ISpObjectTokenCategory> cpCategory;
  456. hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
  457. if (SUCCEEDED(hr))
  458. {
  459. hr = cpCategory->SetDefaultTokenId(pszTokenId);
  460. }
  461. return hr;
  462. }
  463. inline HRESULT SpGetDefaultTokenFromCategoryId(
  464. const WCHAR * pszCategoryId,
  465. ISpObjectToken ** ppToken,
  466. BOOL fCreateCategoryIfNotExist = TRUE)
  467. {
  468. SPDBG_FUNC("SpGetDefaultTokenFromCategoryId");
  469. HRESULT hr;
  470. CComPtr<ISpObjectTokenCategory> cpCategory;
  471. hr = SpGetCategoryFromId(pszCategoryId, &cpCategory, fCreateCategoryIfNotExist);
  472. if (SUCCEEDED(hr))
  473. {
  474. WCHAR * pszTokenId;
  475. hr = cpCategory->GetDefaultTokenId(&pszTokenId);
  476. if (SUCCEEDED(hr))
  477. {
  478. hr = SpGetTokenFromId(pszTokenId, ppToken);
  479. ::CoTaskMemFree(pszTokenId);
  480. }
  481. }
  482. return hr;
  483. }
  484. inline HRESULT SpSetDefaultTokenForCategoryId(
  485. const WCHAR * pszCategoryId,
  486. ISpObjectToken * pToken)
  487. {
  488. SPDBG_FUNC("SpSetDefaultTokenForCategoryId");
  489. HRESULT hr;
  490. WCHAR * pszTokenId;
  491. hr = pToken->GetId(&pszTokenId);
  492. if (SUCCEEDED(hr))
  493. {
  494. hr = SpSetDefaultTokenIdForCategoryId(pszCategoryId, pszTokenId);
  495. ::CoTaskMemFree(pszTokenId);
  496. }
  497. return hr;
  498. }
  499. inline HRESULT SpSetCommonTokenData(
  500. ISpObjectToken * pToken,
  501. const CLSID * pclsid,
  502. const WCHAR * pszLangIndependentName,
  503. LANGID langid,
  504. const WCHAR * pszLangDependentName,
  505. ISpDataKey ** ppDataKeyAttribs)
  506. {
  507. SPDBG_FUNC("SpSetCommonTokenData");
  508. HRESULT hr = S_OK;
  509. // Set the new token's CLSID (if specified)
  510. if (SUCCEEDED(hr) && pclsid)
  511. {
  512. CSpDynamicString dstrClsid;
  513. hr = StringFromCLSID(*pclsid, &dstrClsid);
  514. if (SUCCEEDED(hr))
  515. {
  516. hr = pToken->SetStringValue(SPTOKENVALUE_CLSID, dstrClsid);
  517. }
  518. }
  519. // Set the token's lang independent name
  520. if (SUCCEEDED(hr) && pszLangIndependentName)
  521. {
  522. hr = pToken->SetStringValue(NULL, pszLangIndependentName);
  523. }
  524. // Set the token's lang dependent name
  525. if (SUCCEEDED(hr) && pszLangDependentName)
  526. {
  527. USES_CONVERSION;
  528. TCHAR szLangId[10];
  529. wsprintf(szLangId, _T("%x"), langid);
  530. hr = pToken->SetStringValue(T2W(szLangId), pszLangDependentName);
  531. }
  532. // Open the attributes key if requested
  533. if (SUCCEEDED(hr) && ppDataKeyAttribs)
  534. {
  535. hr = pToken->CreateKey(L"Attributes", ppDataKeyAttribs);
  536. }
  537. SPDBG_REPORT_ON_FAIL(hr);
  538. return hr;
  539. }
  540. inline HRESULT SpCreateNewToken(
  541. const WCHAR * pszTokenId,
  542. ISpObjectToken ** ppToken)
  543. {
  544. SPDBG_FUNC("SpCreateNewToken");
  545. HRESULT hr;
  546. // Forcefully create the token
  547. hr = SpGetTokenFromId(pszTokenId, ppToken, TRUE);
  548. SPDBG_REPORT_ON_FAIL(hr);
  549. return hr;
  550. }
  551. inline HRESULT SpCreateNewToken(
  552. const WCHAR * pszCategoryId,
  553. const WCHAR * pszTokenKeyName,
  554. ISpObjectToken ** ppToken)
  555. {
  556. SPDBG_FUNC("SpCreateNewToken");
  557. HRESULT hr;
  558. // Forcefully create the category
  559. CComPtr<ISpObjectTokenCategory> cpCategory;
  560. hr = SpGetCategoryFromId(pszCategoryId, &cpCategory, TRUE);
  561. // Come up with a token key name if one wasn't specified
  562. CSpDynamicString dstrTokenKeyName;
  563. if (SUCCEEDED(hr))
  564. {
  565. if (pszTokenKeyName == NULL)
  566. {
  567. GUID guidTokenKeyName;
  568. hr = CoCreateGuid(&guidTokenKeyName);
  569. if (SUCCEEDED(hr))
  570. {
  571. hr = StringFromCLSID(guidTokenKeyName, &dstrTokenKeyName);
  572. }
  573. if (SUCCEEDED(hr))
  574. {
  575. pszTokenKeyName = dstrTokenKeyName;
  576. }
  577. }
  578. }
  579. // Build the token id
  580. CSpDynamicString dstrTokenId;
  581. if (SUCCEEDED(hr))
  582. {
  583. dstrTokenId = pszCategoryId;
  584. dstrTokenId.Append2(L"\\Tokens\\", pszTokenKeyName);
  585. }
  586. // Forcefully create the token
  587. if (SUCCEEDED(hr))
  588. {
  589. hr = SpGetTokenFromId(dstrTokenId, ppToken, TRUE);
  590. }
  591. SPDBG_REPORT_ON_FAIL(hr);
  592. return hr;
  593. }
  594. inline HRESULT SpCreateNewTokenEx(
  595. const WCHAR * pszCategoryId,
  596. const WCHAR * pszTokenKeyName,
  597. const CLSID * pclsid,
  598. const WCHAR * pszLangIndependentName,
  599. LANGID langid,
  600. const WCHAR * pszLangDependentName,
  601. ISpObjectToken ** ppToken,
  602. ISpDataKey ** ppDataKeyAttribs)
  603. {
  604. SPDBG_FUNC("SpCreateNewTokenEx");
  605. HRESULT hr;
  606. // Create the new token
  607. hr = SpCreateNewToken(pszCategoryId, pszTokenKeyName, ppToken);
  608. // Now set the extra data
  609. if (SUCCEEDED(hr))
  610. {
  611. hr = SpSetCommonTokenData(
  612. *ppToken,
  613. pclsid,
  614. pszLangIndependentName,
  615. langid,
  616. pszLangDependentName,
  617. ppDataKeyAttribs);
  618. }
  619. SPDBG_REPORT_ON_FAIL(hr);
  620. return hr;
  621. }
  622. inline HRESULT SpCreateNewTokenEx(
  623. const WCHAR * pszTokenId,
  624. const CLSID * pclsid,
  625. const WCHAR * pszLangIndependentName,
  626. LANGID langid,
  627. const WCHAR * pszLangDependentName,
  628. ISpObjectToken ** ppToken,
  629. ISpDataKey ** ppDataKeyAttribs)
  630. {
  631. SPDBG_FUNC("SpCreateNewTokenEx");
  632. HRESULT hr;
  633. // Create the new token
  634. hr = SpCreateNewToken(pszTokenId, ppToken);
  635. // Now set the extra data
  636. if (SUCCEEDED(hr))
  637. {
  638. hr = SpSetCommonTokenData(
  639. *ppToken,
  640. pclsid,
  641. pszLangIndependentName,
  642. langid,
  643. pszLangDependentName,
  644. ppDataKeyAttribs);
  645. }
  646. SPDBG_REPORT_ON_FAIL(hr);
  647. return hr;
  648. }
  649. inline HRESULT SpEnumTokens(
  650. const WCHAR * pszCategoryId,
  651. const WCHAR * pszReqAttribs,
  652. const WCHAR * pszOptAttribs,
  653. IEnumSpObjectTokens ** ppEnum)
  654. {
  655. SPDBG_FUNC("SpEnumTokens");
  656. HRESULT hr = S_OK;
  657. CComPtr<ISpObjectTokenCategory> cpCategory;
  658. hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
  659. if (SUCCEEDED(hr))
  660. {
  661. hr = cpCategory->EnumTokens(
  662. pszReqAttribs,
  663. pszOptAttribs,
  664. ppEnum);
  665. }
  666. SPDBG_REPORT_ON_FAIL(hr);
  667. return hr;
  668. }
  669. inline HRESULT SpFindBestToken(
  670. const WCHAR * pszCategoryId,
  671. const WCHAR * pszReqAttribs,
  672. const WCHAR * pszOptAttribs,
  673. ISpObjectToken **ppObjectToken)
  674. {
  675. SPDBG_FUNC("SpFindBestToken");
  676. HRESULT hr = S_OK;
  677. const WCHAR *pszVendorPreferred = L"VendorPreferred";
  678. const size_t ulLenVendorPreferred = wcslen(pszVendorPreferred);
  679. // append VendorPreferred to the end of pszOptAttribs to force this preference
  680. size_t ulLen = pszOptAttribs ? wcslen(pszOptAttribs) + ulLenVendorPreferred + 1 : ulLenVendorPreferred;
  681. WCHAR *pszOptAttribsVendorPref = (WCHAR*)_alloca((ulLen+1)*sizeof(WCHAR));
  682. if (pszOptAttribsVendorPref)
  683. {
  684. if (pszOptAttribs)
  685. {
  686. wcscpy(pszOptAttribsVendorPref, pszOptAttribs);
  687. wcscat(pszOptAttribsVendorPref, L";");
  688. wcscat(pszOptAttribsVendorPref, pszVendorPreferred);
  689. }
  690. else
  691. {
  692. wcscpy(pszOptAttribsVendorPref, pszVendorPreferred);
  693. }
  694. }
  695. else
  696. {
  697. hr = E_OUTOFMEMORY;
  698. }
  699. CComPtr<IEnumSpObjectTokens> cpEnum;
  700. if (SUCCEEDED(hr))
  701. {
  702. hr = SpEnumTokens(pszCategoryId, pszReqAttribs, pszOptAttribsVendorPref, &cpEnum);
  703. }
  704. if (SUCCEEDED(hr))
  705. {
  706. hr = cpEnum->Next(1, ppObjectToken, NULL);
  707. if (hr == S_FALSE)
  708. {
  709. *ppObjectToken = NULL;
  710. hr = SPERR_NOT_FOUND;
  711. }
  712. }
  713. if (hr != SPERR_NOT_FOUND)
  714. {
  715. SPDBG_REPORT_ON_FAIL(hr);
  716. }
  717. return hr;
  718. }
  719. template<class T>
  720. HRESULT SpCreateObjectFromToken(ISpObjectToken * pToken, T ** ppObject,
  721. IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL)
  722. {
  723. SPDBG_FUNC("SpCreateObjectFromToken");
  724. HRESULT hr;
  725. hr = pToken->CreateInstance(pUnkOuter, dwClsCtxt, __uuidof(T), (void **)ppObject);
  726. SPDBG_REPORT_ON_FAIL(hr);
  727. return hr;
  728. }
  729. template<class T>
  730. HRESULT SpCreateObjectFromTokenId(const WCHAR * pszTokenId, T ** ppObject,
  731. IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL)
  732. {
  733. SPDBG_FUNC("SpCreateObjectFromTokenId");
  734. ISpObjectToken * pToken;
  735. HRESULT hr = SpGetTokenFromId(pszTokenId, &pToken);
  736. if (SUCCEEDED(hr))
  737. {
  738. hr = SpCreateObjectFromToken(pToken, ppObject, pUnkOuter, dwClsCtxt);
  739. pToken->Release();
  740. }
  741. SPDBG_REPORT_ON_FAIL(hr);
  742. return hr;
  743. }
  744. template<class T>
  745. HRESULT SpCreateDefaultObjectFromCategoryId(const WCHAR * pszCategoryId, T ** ppObject,
  746. IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL)
  747. {
  748. SPDBG_FUNC("SpCreateObjectFromTokenId");
  749. ISpObjectToken * pToken;
  750. HRESULT hr = SpGetDefaultTokenFromCategoryId(pszCategoryId, &pToken);
  751. if (SUCCEEDED(hr))
  752. {
  753. hr = SpCreateObjectFromToken(pToken, ppObject, pUnkOuter, dwClsCtxt);
  754. pToken->Release();
  755. }
  756. SPDBG_REPORT_ON_FAIL(hr);
  757. return hr;
  758. }
  759. template<class T>
  760. HRESULT SpCreateBestObject(
  761. const WCHAR * pszCategoryId,
  762. const WCHAR * pszReqAttribs,
  763. const WCHAR * pszOptAttribs,
  764. T ** ppObject,
  765. IUnknown * pUnkOuter = NULL,
  766. DWORD dwClsCtxt = CLSCTX_ALL)
  767. {
  768. SPDBG_FUNC("SpCreateBestObject");
  769. HRESULT hr;
  770. CComPtr<ISpObjectToken> cpToken;
  771. hr = SpFindBestToken(pszCategoryId, pszReqAttribs, pszOptAttribs, &cpToken);
  772. if (SUCCEEDED(hr))
  773. {
  774. hr = SpCreateObjectFromToken(cpToken, ppObject, pUnkOuter, dwClsCtxt);
  775. }
  776. if (hr != SPERR_NOT_FOUND)
  777. {
  778. SPDBG_REPORT_ON_FAIL(hr);
  779. }
  780. return hr;
  781. }
  782. inline HRESULT SpCreatePhoneConverter(
  783. LANGID LangID,
  784. const WCHAR * pszReqAttribs,
  785. const WCHAR * pszOptAttribs,
  786. ISpPhoneConverter ** ppPhoneConverter)
  787. {
  788. SPDBG_FUNC("SpCreatePhoneConverter");
  789. HRESULT hr;
  790. if (LangID == 0)
  791. {
  792. hr = E_INVALIDARG;
  793. }
  794. else
  795. {
  796. CSpDynamicString dstrReqAttribs;
  797. if (pszReqAttribs)
  798. {
  799. dstrReqAttribs = pszReqAttribs;
  800. dstrReqAttribs.Append(L";");
  801. }
  802. WCHAR szLang[MAX_PATH];
  803. SpHexFromUlong(szLang, LangID);
  804. WCHAR szLangCondition[MAX_PATH];
  805. wcscpy(szLangCondition, L"Language=");
  806. wcscat(szLangCondition, szLang);
  807. dstrReqAttribs.Append(szLangCondition);
  808. hr = SpCreateBestObject(SPCAT_PHONECONVERTERS, dstrReqAttribs, pszOptAttribs, ppPhoneConverter);
  809. }
  810. if (hr != SPERR_NOT_FOUND)
  811. {
  812. SPDBG_REPORT_ON_FAIL(hr);
  813. }
  814. return hr;
  815. }
  816. /****************************************************************************
  817. * SpHrFromWin32 *
  818. *---------------*
  819. * Description:
  820. * This inline function works around a basic problem with the macro
  821. * HRESULT_FROM_WIN32. The macro forces the expresion in ( ) to be evaluated
  822. * two times. By using this inline function, the expression will only be
  823. * evaluated once.
  824. *
  825. * Returns:
  826. * HRESULT of converted Win32 error code
  827. *
  828. *****************************************************************************/
  829. inline HRESULT SpHrFromWin32(DWORD dwErr)
  830. {
  831. return HRESULT_FROM_WIN32(dwErr);
  832. }
  833. /****************************************************************************
  834. * SpHrFromLastWin32Error *
  835. *------------------------*
  836. * Description:
  837. * This simple inline function is used to return a converted HRESULT
  838. * from the Win32 function ::GetLastError. Note that using HRESULT_FROM_WIN32
  839. * will evaluate the error code twice so we don't want to use:
  840. *
  841. * HRESULT_FROM_WIN32(::GetLastError())
  842. *
  843. * since that will call GetLastError twice.
  844. * On Win98 and WinMe ::GetLastError() returns 0 for some functions (see MSDN).
  845. * We therefore check for that and return E_FAIL. This function should only be
  846. * called in an error case since it will always return an error code!
  847. *
  848. * Returns:
  849. * HRESULT for ::GetLastError()
  850. *
  851. *****************************************************************************/
  852. inline HRESULT SpHrFromLastWin32Error()
  853. {
  854. DWORD dw = ::GetLastError();
  855. return (dw == 0) ? E_FAIL : SpHrFromWin32(dw);
  856. }
  857. /****************************************************************************
  858. * SpGetUserDefaultUILanguage *
  859. *----------------------------*
  860. * Description:
  861. * Returns the default user interface language, using a method
  862. * appropriate to the platform (Windows 9x, Windows NT, or Windows 2000)
  863. *
  864. * Returns:
  865. * Default UI language
  866. *
  867. *****************************************************************************/
  868. inline LANGID SpGetUserDefaultUILanguage(void)
  869. {
  870. HRESULT hr = S_OK;
  871. LANGID wUILang = 0;
  872. OSVERSIONINFO Osv ;
  873. Osv.dwOSVersionInfoSize = sizeof(Osv) ;
  874. if(!GetVersionEx(&Osv))
  875. {
  876. hr = SpHrFromLastWin32Error();
  877. }
  878. // Get the UI language by one of three methods, depending on the system
  879. else if(Osv.dwPlatformId != VER_PLATFORM_WIN32_NT)
  880. {
  881. // Case 1: Running on Windows 9x. Get the system UI language from registry:
  882. CHAR szData[32];
  883. DWORD dwSize = sizeof(szData) ;
  884. HKEY hKey;
  885. long lRet = RegOpenKeyEx(
  886. HKEY_USERS,
  887. _T(".Default\\Control Panel\\desktop\\ResourceLocale"),
  888. 0,
  889. KEY_READ,
  890. &hKey);
  891. #ifdef _WIN32_WCE_BUG_10655
  892. if (lRet == ERROR_INVALID_PARAMETER)
  893. {
  894. lRet = ERROR_FILE_NOT_FOUND;
  895. }
  896. #endif // _WIN32_WCE_BUG_10655
  897. hr = SpHrFromWin32(lRet);
  898. if (SUCCEEDED(hr))
  899. {
  900. lRet = RegQueryValueEx(
  901. hKey,
  902. _T(""),
  903. NULL,
  904. NULL,
  905. (BYTE *)szData,
  906. &dwSize);
  907. #ifdef _WIN32_WCE_BUG_10655
  908. if(lRet == ERROR_INVALID_PARAMETER)
  909. {
  910. lRet = ERROR_FILE_NOT_FOUND;
  911. }
  912. #endif //_WIN32_WCE_BUG_10655
  913. hr = SpHrFromWin32(lRet);
  914. ::RegCloseKey(hKey) ;
  915. }
  916. if (SUCCEEDED(hr))
  917. {
  918. // Convert string to number
  919. wUILang = (LANGID) strtol(szData, NULL, 16) ;
  920. }
  921. }
  922. else if (Osv.dwMajorVersion >= 5.0)
  923. {
  924. // Case 2: Running on Windows 2000 or later. Use GetUserDefaultUILanguage to find
  925. // the user's prefered UI language
  926. HMODULE hMKernel32 = ::LoadLibraryW(L"kernel32.dll") ;
  927. if (hMKernel32 == NULL)
  928. {
  929. hr = SpHrFromLastWin32Error();
  930. }
  931. else
  932. {
  933. LANGID (WINAPI *pfnGetUserDefaultUILanguage) () =
  934. (LANGID (WINAPI *)(void))
  935. #ifdef _WIN32_WCE
  936. GetProcAddress(hMKernel32, L"GetUserDefaultUILanguage") ;
  937. #else
  938. GetProcAddress(hMKernel32, "GetUserDefaultUILanguage") ;
  939. #endif
  940. if(NULL != pfnGetUserDefaultUILanguage)
  941. {
  942. wUILang = pfnGetUserDefaultUILanguage() ;
  943. }
  944. else
  945. { // GetProcAddress failed
  946. hr = SpHrFromLastWin32Error();
  947. }
  948. ::FreeLibrary(hMKernel32);
  949. }
  950. }
  951. else {
  952. // Case 3: Running on Windows NT 4.0 or earlier. Get UI language
  953. // from locale of .default user in registry:
  954. // HKEY_USERS\.DEFAULT\Control Panel\International\Locale
  955. WCHAR szData[32] ;
  956. DWORD dwSize = sizeof(szData) ;
  957. HKEY hKey ;
  958. LONG lRet = RegOpenKeyEx(HKEY_USERS,
  959. _T(".DEFAULT\\Control Panel\\International"),
  960. 0,
  961. KEY_READ,
  962. &hKey);
  963. #ifdef _WIN32_WCE_BUG_10655
  964. if(lRet == ERROR_INVALID_PARAMETER)
  965. {
  966. lRet = ERROR_FILE_NOT_FOUND;
  967. }
  968. #endif //_WIN32_WCE_BUG_10655
  969. hr = SpHrFromWin32(lRet);
  970. if (SUCCEEDED(hr))
  971. {
  972. lRet = RegQueryValueEx(
  973. hKey,
  974. _T("Locale"),
  975. NULL,
  976. NULL,
  977. (BYTE *)szData,
  978. &dwSize);
  979. #ifdef _WIN32_WCE_BUG_10655
  980. if(lRet == ERROR_INVALID_PARAMETER)
  981. {
  982. lRet = ERROR_FILE_NOT_FOUND;
  983. }
  984. #endif //_WIN32_WCE_BUG_10655
  985. hr = SpHrFromWin32(lRet);
  986. ::RegCloseKey(hKey);
  987. }
  988. if (SUCCEEDED(hr))
  989. {
  990. // Convert string to number
  991. wUILang = (LANGID) wcstol(szData, NULL, 16) ;
  992. if(0x0401 == wUILang || // Arabic
  993. 0x040d == wUILang || // Hebrew
  994. 0x041e == wUILang // Thai
  995. )
  996. {
  997. // Special case these to the English UI.
  998. // These versions of Windows NT 4.0 were enabled only, i.e., the
  999. // UI was English. However, the registry setting
  1000. // HKEY_USERS\.DEFAULT\Control Panel\International\Locale was set
  1001. // to the respective locale for application compatibility.
  1002. wUILang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) ;
  1003. }
  1004. }
  1005. }
  1006. return (wUILang ? wUILang : ::GetUserDefaultLangID()); // In failure case, try our best!
  1007. }
  1008. inline HRESULT SpGetDescription(ISpObjectToken * pObjToken, WCHAR ** ppszDescription, LANGID Language = SpGetUserDefaultUILanguage())
  1009. {
  1010. WCHAR szLangId[10];
  1011. SpHexFromUlong(szLangId, Language);
  1012. HRESULT hr = pObjToken->GetStringValue(szLangId, ppszDescription);
  1013. if (hr == SPERR_NOT_FOUND)
  1014. {
  1015. hr = pObjToken->GetStringValue(NULL, ppszDescription);
  1016. }
  1017. return hr;
  1018. }
  1019. inline HRESULT SpSetDescription(ISpObjectToken * pObjToken, const WCHAR * pszDescription, LANGID Language = SpGetUserDefaultUILanguage(), BOOL fSetLangIndependentId = TRUE)
  1020. {
  1021. WCHAR szLangId[10];
  1022. SpHexFromUlong(szLangId, Language);
  1023. HRESULT hr = pObjToken->SetStringValue(szLangId, pszDescription);
  1024. if (SUCCEEDED(hr) && fSetLangIndependentId)
  1025. {
  1026. hr = pObjToken->SetStringValue(NULL, pszDescription);
  1027. }
  1028. return hr;
  1029. }
  1030. /****************************************************************************
  1031. * SpConvertStreamFormatEnum *
  1032. *---------------------------*
  1033. * Description:
  1034. * This method converts the specified stream format into a wave format
  1035. * structure.
  1036. *
  1037. *****************************************************************************/
  1038. inline HRESULT SpConvertStreamFormatEnum(SPSTREAMFORMAT eFormat, GUID * pFormatId, WAVEFORMATEX ** ppCoMemWaveFormatEx)
  1039. {
  1040. HRESULT hr = S_OK;
  1041. if(pFormatId==NULL || ::IsBadWritePtr(pFormatId, sizeof(*pFormatId))
  1042. || ppCoMemWaveFormatEx==NULL || ::IsBadWritePtr(ppCoMemWaveFormatEx, sizeof(*ppCoMemWaveFormatEx)))
  1043. {
  1044. return E_INVALIDARG;
  1045. }
  1046. const GUID * pFmtGuid = &GUID_NULL; // Assume failure case
  1047. if( eFormat >= SPSF_8kHz8BitMono && eFormat <= SPSF_48kHz16BitStereo )
  1048. {
  1049. WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc(sizeof(WAVEFORMATEX));
  1050. *ppCoMemWaveFormatEx = pwfex;
  1051. if (pwfex)
  1052. {
  1053. DWORD dwIndex = eFormat - SPSF_8kHz8BitMono;
  1054. BOOL bIsStereo = dwIndex & 0x1;
  1055. BOOL bIs16 = dwIndex & 0x2;
  1056. DWORD dwKHZ = (dwIndex & 0x3c) >> 2;
  1057. static const DWORD adwKHZ[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 };
  1058. pwfex->wFormatTag = WAVE_FORMAT_PCM;
  1059. pwfex->nChannels = pwfex->nBlockAlign = (WORD)(bIsStereo ? 2 : 1);
  1060. pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
  1061. pwfex->wBitsPerSample = 8;
  1062. if (bIs16)
  1063. {
  1064. pwfex->wBitsPerSample *= 2;
  1065. pwfex->nBlockAlign *= 2;
  1066. }
  1067. pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nBlockAlign;
  1068. pwfex->cbSize = 0;
  1069. pFmtGuid = &SPDFID_WaveFormatEx;
  1070. }
  1071. else
  1072. {
  1073. hr = E_OUTOFMEMORY;
  1074. }
  1075. }
  1076. else if( eFormat == SPSF_TrueSpeech_8kHz1BitMono )
  1077. {
  1078. int NumBytes = sizeof( WAVEFORMATEX ) + 32;
  1079. WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( NumBytes );
  1080. *ppCoMemWaveFormatEx = pwfex;
  1081. if( pwfex )
  1082. {
  1083. memset( pwfex, 0, NumBytes );
  1084. pwfex->wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH;
  1085. pwfex->nChannels = 1;
  1086. pwfex->nSamplesPerSec = 8000;
  1087. pwfex->nAvgBytesPerSec = 1067;
  1088. pwfex->nBlockAlign = 32;
  1089. pwfex->wBitsPerSample = 1;
  1090. pwfex->cbSize = 32;
  1091. BYTE* pExtra = ((BYTE*)pwfex) + sizeof( WAVEFORMATEX );
  1092. pExtra[0] = 1;
  1093. pExtra[2] = 0xF0;
  1094. pFmtGuid = &SPDFID_WaveFormatEx;
  1095. }
  1096. else
  1097. {
  1098. hr = E_OUTOFMEMORY;
  1099. }
  1100. }
  1101. else if( (eFormat >= SPSF_CCITT_ALaw_8kHzMono ) &&
  1102. (eFormat <= SPSF_CCITT_ALaw_44kHzStereo ) )
  1103. {
  1104. WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( sizeof(WAVEFORMATEX) );
  1105. *ppCoMemWaveFormatEx = pwfex;
  1106. if( pwfex )
  1107. {
  1108. memset( pwfex, 0, sizeof(WAVEFORMATEX) );
  1109. DWORD dwIndex = eFormat - SPSF_CCITT_ALaw_8kHzMono;
  1110. DWORD dwKHZ = dwIndex / 2;
  1111. static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
  1112. BOOL bIsStereo = dwIndex & 0x1;
  1113. pwfex->wFormatTag = WAVE_FORMAT_ALAW;
  1114. pwfex->nChannels = pwfex->nBlockAlign = (WORD)(bIsStereo ? 2 : 1);
  1115. pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
  1116. pwfex->wBitsPerSample = 8;
  1117. pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nBlockAlign;
  1118. pwfex->cbSize = 0;
  1119. pFmtGuid = &SPDFID_WaveFormatEx;
  1120. }
  1121. else
  1122. {
  1123. hr = E_OUTOFMEMORY;
  1124. }
  1125. }
  1126. else if( (eFormat >= SPSF_CCITT_uLaw_8kHzMono ) &&
  1127. (eFormat <= SPSF_CCITT_uLaw_44kHzStereo ) )
  1128. {
  1129. WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( sizeof(WAVEFORMATEX) );
  1130. *ppCoMemWaveFormatEx = pwfex;
  1131. if( pwfex )
  1132. {
  1133. memset( pwfex, 0, sizeof(WAVEFORMATEX) );
  1134. DWORD dwIndex = eFormat - SPSF_CCITT_uLaw_8kHzMono;
  1135. DWORD dwKHZ = dwIndex / 2;
  1136. static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
  1137. BOOL bIsStereo = dwIndex & 0x1;
  1138. pwfex->wFormatTag = WAVE_FORMAT_MULAW;
  1139. pwfex->nChannels = pwfex->nBlockAlign = (WORD)(bIsStereo ? 2 : 1);
  1140. pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
  1141. pwfex->wBitsPerSample = 8;
  1142. pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nBlockAlign;
  1143. pwfex->cbSize = 0;
  1144. pFmtGuid = &SPDFID_WaveFormatEx;
  1145. }
  1146. else
  1147. {
  1148. hr = E_OUTOFMEMORY;
  1149. }
  1150. }
  1151. else if( (eFormat >= SPSF_ADPCM_8kHzMono ) &&
  1152. (eFormat <= SPSF_ADPCM_44kHzStereo ) )
  1153. {
  1154. int NumBytes = sizeof( WAVEFORMATEX ) + 32;
  1155. WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( NumBytes );
  1156. *ppCoMemWaveFormatEx = pwfex;
  1157. if( pwfex )
  1158. {
  1159. //--- Some of these values seem odd. We used what the codec told us.
  1160. static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
  1161. static const DWORD BytesPerSec[] = { 4096, 8192, 5644, 11289, 11155, 22311, 22179, 44359 };
  1162. static const DWORD BlockAlign[] = { 256, 256, 512, 1024 };
  1163. static const BYTE Extra811[32] =
  1164. {
  1165. 0xF4, 0x01, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00,
  1166. 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
  1167. 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00,
  1168. 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF
  1169. };
  1170. static const BYTE Extra22[32] =
  1171. {
  1172. 0xF4, 0x03, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00,
  1173. 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
  1174. 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00,
  1175. 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF
  1176. };
  1177. static const BYTE Extra44[32] =
  1178. {
  1179. 0xF4, 0x07, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00,
  1180. 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
  1181. 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00,
  1182. 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF
  1183. };
  1184. static const BYTE* Extra[4] = { Extra811, Extra811, Extra22, Extra44 };
  1185. memset( pwfex, 0, NumBytes );
  1186. DWORD dwIndex = eFormat - SPSF_ADPCM_8kHzMono;
  1187. DWORD dwKHZ = dwIndex / 2;
  1188. BOOL bIsStereo = dwIndex & 0x1;
  1189. pwfex->wFormatTag = WAVE_FORMAT_ADPCM;
  1190. pwfex->nChannels = (WORD)(bIsStereo ? 2 : 1);
  1191. pwfex->nSamplesPerSec = adwKHZ[dwKHZ];
  1192. pwfex->nAvgBytesPerSec = BytesPerSec[dwIndex];
  1193. pwfex->nBlockAlign = (WORD)(BlockAlign[dwKHZ] * pwfex->nChannels);
  1194. pwfex->wBitsPerSample = 4;
  1195. pwfex->cbSize = 32;
  1196. BYTE* pExtra = ((BYTE*)pwfex) + sizeof( WAVEFORMATEX );
  1197. memcpy( pExtra, Extra[dwKHZ], 32 );
  1198. pFmtGuid = &SPDFID_WaveFormatEx;
  1199. }
  1200. else
  1201. {
  1202. hr = E_OUTOFMEMORY;
  1203. }
  1204. }
  1205. else if( (eFormat >= SPSF_GSM610_8kHzMono ) &&
  1206. (eFormat <= SPSF_GSM610_44kHzMono ) )
  1207. {
  1208. int NumBytes = sizeof( WAVEFORMATEX ) + 2;
  1209. WAVEFORMATEX * pwfex = (WAVEFORMATEX *)::CoTaskMemAlloc( NumBytes );
  1210. *ppCoMemWaveFormatEx = pwfex;
  1211. if( pwfex )
  1212. {
  1213. //--- Some of these values seem odd. We used what the codec told us.
  1214. static const DWORD adwKHZ[] = { 8000, 11025, 22050, 44100 };
  1215. static const DWORD BytesPerSec[] = { 1625, 2239, 4478, 8957 };
  1216. memset( pwfex, 0, NumBytes );
  1217. DWORD dwIndex = eFormat - SPSF_GSM610_8kHzMono;
  1218. pwfex->wFormatTag = WAVE_FORMAT_GSM610;
  1219. pwfex->nChannels = 1;
  1220. pwfex->nSamplesPerSec = adwKHZ[dwIndex];
  1221. pwfex->nAvgBytesPerSec = BytesPerSec[dwIndex];
  1222. pwfex->nBlockAlign = 65;
  1223. pwfex->wBitsPerSample = 0;
  1224. pwfex->cbSize = 2;
  1225. BYTE* pExtra = ((BYTE*)pwfex) + sizeof( WAVEFORMATEX );
  1226. pExtra[0] = 0x40;
  1227. pExtra[1] = 0x01;
  1228. pFmtGuid = &SPDFID_WaveFormatEx;
  1229. }
  1230. else
  1231. {
  1232. hr = E_OUTOFMEMORY;
  1233. }
  1234. }
  1235. else
  1236. {
  1237. *ppCoMemWaveFormatEx = NULL;
  1238. switch (eFormat)
  1239. {
  1240. case SPSF_NoAssignedFormat:
  1241. break;
  1242. case SPSF_Text:
  1243. pFmtGuid = &SPDFID_Text;
  1244. break;
  1245. default:
  1246. hr = E_INVALIDARG;
  1247. break;
  1248. }
  1249. }
  1250. *pFormatId = *pFmtGuid;
  1251. return hr;
  1252. }
  1253. class CSpStreamFormat
  1254. {
  1255. public:
  1256. GUID m_guidFormatId;
  1257. WAVEFORMATEX * m_pCoMemWaveFormatEx;
  1258. static HRESULT CoMemCopyWFEX(const WAVEFORMATEX * pSrc, WAVEFORMATEX ** ppCoMemWFEX)
  1259. {
  1260. ULONG cb = sizeof(WAVEFORMATEX) + pSrc->cbSize;
  1261. *ppCoMemWFEX = (WAVEFORMATEX *)::CoTaskMemAlloc(cb);
  1262. if (*ppCoMemWFEX)
  1263. {
  1264. memcpy(*ppCoMemWFEX, pSrc, cb);
  1265. return S_OK;
  1266. }
  1267. else
  1268. {
  1269. return E_OUTOFMEMORY;
  1270. }
  1271. }
  1272. CSpStreamFormat()
  1273. {
  1274. m_guidFormatId = GUID_NULL;
  1275. m_pCoMemWaveFormatEx = NULL;
  1276. }
  1277. CSpStreamFormat(SPSTREAMFORMAT eFormat, HRESULT * phr)
  1278. {
  1279. *phr = SpConvertStreamFormatEnum(eFormat, &m_guidFormatId, &m_pCoMemWaveFormatEx);
  1280. }
  1281. CSpStreamFormat(const WAVEFORMATEX * pWaveFormatEx, HRESULT * phr)
  1282. {
  1283. SPDBG_ASSERT(pWaveFormatEx);
  1284. *phr = CoMemCopyWFEX(pWaveFormatEx, &m_pCoMemWaveFormatEx);
  1285. m_guidFormatId = SUCCEEDED(*phr) ? SPDFID_WaveFormatEx : GUID_NULL;
  1286. }
  1287. ~CSpStreamFormat()
  1288. {
  1289. ::CoTaskMemFree(m_pCoMemWaveFormatEx);
  1290. }
  1291. void Clear()
  1292. {
  1293. ::CoTaskMemFree(m_pCoMemWaveFormatEx);
  1294. m_pCoMemWaveFormatEx = NULL;
  1295. memset(&m_guidFormatId, 0, sizeof(m_guidFormatId));
  1296. }
  1297. const GUID & FormatId() const
  1298. {
  1299. return m_guidFormatId;
  1300. }
  1301. const WAVEFORMATEX * WaveFormatExPtr() const
  1302. {
  1303. return m_pCoMemWaveFormatEx;
  1304. }
  1305. HRESULT AssignFormat(SPSTREAMFORMAT eFormat)
  1306. {
  1307. ::CoTaskMemFree(m_pCoMemWaveFormatEx);
  1308. return SpConvertStreamFormatEnum(eFormat, &m_guidFormatId, &m_pCoMemWaveFormatEx);
  1309. }
  1310. HRESULT AssignFormat(ISpStreamFormat * pStream)
  1311. {
  1312. ::CoTaskMemFree(m_pCoMemWaveFormatEx);
  1313. m_pCoMemWaveFormatEx = NULL;
  1314. return pStream->GetFormat(&m_guidFormatId, &m_pCoMemWaveFormatEx);
  1315. }
  1316. HRESULT AssignFormat(const WAVEFORMATEX * pWaveFormatEx)
  1317. {
  1318. ::CoTaskMemFree(m_pCoMemWaveFormatEx);
  1319. HRESULT hr = CoMemCopyWFEX(pWaveFormatEx, &m_pCoMemWaveFormatEx);
  1320. m_guidFormatId = SUCCEEDED(hr) ? SPDFID_WaveFormatEx : GUID_NULL;
  1321. return hr;
  1322. }
  1323. HRESULT AssignFormat(REFGUID rguidFormatId, const WAVEFORMATEX * pWaveFormatEx)
  1324. {
  1325. HRESULT hr = S_OK;
  1326. m_guidFormatId = rguidFormatId;
  1327. ::CoTaskMemFree(m_pCoMemWaveFormatEx);
  1328. m_pCoMemWaveFormatEx = NULL;
  1329. if (rguidFormatId == SPDFID_WaveFormatEx)
  1330. {
  1331. if (::IsBadReadPtr(pWaveFormatEx, sizeof(*pWaveFormatEx)))
  1332. {
  1333. hr = E_INVALIDARG;
  1334. }
  1335. else
  1336. {
  1337. hr = CoMemCopyWFEX(pWaveFormatEx, &m_pCoMemWaveFormatEx);
  1338. }
  1339. if (FAILED(hr))
  1340. {
  1341. m_guidFormatId = GUID_NULL;
  1342. }
  1343. }
  1344. return hr;
  1345. }
  1346. BOOL IsEqual(REFGUID rguidFormatId, const WAVEFORMATEX * pwfex) const
  1347. {
  1348. if (rguidFormatId == m_guidFormatId)
  1349. {
  1350. if (m_pCoMemWaveFormatEx)
  1351. {
  1352. if (pwfex &&
  1353. pwfex->cbSize == m_pCoMemWaveFormatEx->cbSize &&
  1354. memcmp(m_pCoMemWaveFormatEx, pwfex, sizeof(WAVEFORMATEX) + pwfex->cbSize) == 0)
  1355. {
  1356. return TRUE;
  1357. }
  1358. }
  1359. else
  1360. {
  1361. return (pwfex == NULL);
  1362. }
  1363. }
  1364. return FALSE;
  1365. }
  1366. HRESULT ParamValidateAssignFormat(REFGUID rguidFormatId, const WAVEFORMATEX * pWaveFormatEx, BOOL fRequireWaveFormat = FALSE)
  1367. {
  1368. if ((pWaveFormatEx && (::IsBadReadPtr(pWaveFormatEx, sizeof(*pWaveFormatEx)) || rguidFormatId != SPDFID_WaveFormatEx)) ||
  1369. (fRequireWaveFormat && pWaveFormatEx == NULL))
  1370. {
  1371. return E_INVALIDARG;
  1372. }
  1373. return AssignFormat(rguidFormatId, pWaveFormatEx);
  1374. }
  1375. SPSTREAMFORMAT ComputeFormatEnum()
  1376. {
  1377. if (m_guidFormatId == GUID_NULL)
  1378. {
  1379. return SPSF_NoAssignedFormat;
  1380. }
  1381. if (m_guidFormatId == SPDFID_Text)
  1382. {
  1383. return SPSF_Text;
  1384. }
  1385. if (m_guidFormatId != SPDFID_WaveFormatEx)
  1386. {
  1387. return SPSF_NonStandardFormat;
  1388. }
  1389. //
  1390. // It is a WAVEFORMATEX. Now determine which type it is and convert.
  1391. //
  1392. DWORD dwIndex = 0;
  1393. switch (m_pCoMemWaveFormatEx->wFormatTag)
  1394. {
  1395. case WAVE_FORMAT_PCM:
  1396. {
  1397. switch (m_pCoMemWaveFormatEx->nChannels)
  1398. {
  1399. case 1:
  1400. break;
  1401. case 2:
  1402. dwIndex |= 1;
  1403. break;
  1404. default:
  1405. return SPSF_ExtendedAudioFormat;
  1406. }
  1407. switch (m_pCoMemWaveFormatEx->wBitsPerSample)
  1408. {
  1409. case 8:
  1410. break;
  1411. case 16:
  1412. dwIndex |= 2;
  1413. break;
  1414. default:
  1415. return SPSF_ExtendedAudioFormat;
  1416. }
  1417. switch (m_pCoMemWaveFormatEx->nSamplesPerSec)
  1418. {
  1419. case 48000:
  1420. dwIndex += 4; // Fall through
  1421. case 44100:
  1422. dwIndex += 4; // Fall through
  1423. case 32000:
  1424. dwIndex += 4; // Fall through
  1425. case 24000:
  1426. dwIndex += 4; // Fall through
  1427. case 22050:
  1428. dwIndex += 4; // Fall through
  1429. case 16000:
  1430. dwIndex += 4; // Fall through
  1431. case 12000:
  1432. dwIndex += 4; // Fall through
  1433. case 11025:
  1434. dwIndex += 4; // Fall through
  1435. case 8000:
  1436. break;
  1437. default:
  1438. return SPSF_ExtendedAudioFormat;
  1439. }
  1440. return static_cast<SPSTREAMFORMAT>(SPSF_8kHz8BitMono + dwIndex);
  1441. }
  1442. case WAVE_FORMAT_DSPGROUP_TRUESPEECH:
  1443. {
  1444. return SPSF_TrueSpeech_8kHz1BitMono;
  1445. }
  1446. case WAVE_FORMAT_ALAW: // fall through
  1447. case WAVE_FORMAT_MULAW:
  1448. case WAVE_FORMAT_ADPCM:
  1449. {
  1450. switch (m_pCoMemWaveFormatEx->nChannels)
  1451. {
  1452. case 1:
  1453. break;
  1454. case 2:
  1455. dwIndex |= 1;
  1456. break;
  1457. default:
  1458. return SPSF_ExtendedAudioFormat;
  1459. }
  1460. if(m_pCoMemWaveFormatEx->wFormatTag == WAVE_FORMAT_ADPCM)
  1461. {
  1462. if(m_pCoMemWaveFormatEx->wBitsPerSample != 4)
  1463. {
  1464. return SPSF_ExtendedAudioFormat;
  1465. }
  1466. }
  1467. else if(m_pCoMemWaveFormatEx->wBitsPerSample != 8)
  1468. {
  1469. return SPSF_ExtendedAudioFormat;
  1470. }
  1471. switch (m_pCoMemWaveFormatEx->nSamplesPerSec)
  1472. {
  1473. case 44100:
  1474. dwIndex += 2; // Fall through
  1475. case 22050:
  1476. dwIndex += 2; // Fall through
  1477. case 11025:
  1478. dwIndex += 2; // Fall through
  1479. case 8000:
  1480. break;
  1481. default:
  1482. return SPSF_ExtendedAudioFormat;
  1483. }
  1484. switch( m_pCoMemWaveFormatEx->wFormatTag )
  1485. {
  1486. case WAVE_FORMAT_ALAW:
  1487. return static_cast<SPSTREAMFORMAT>(SPSF_CCITT_ALaw_8kHzMono + dwIndex);
  1488. case WAVE_FORMAT_MULAW:
  1489. return static_cast<SPSTREAMFORMAT>(SPSF_CCITT_uLaw_8kHzMono + dwIndex);
  1490. case WAVE_FORMAT_ADPCM:
  1491. return static_cast<SPSTREAMFORMAT>(SPSF_ADPCM_8kHzMono + dwIndex);
  1492. }
  1493. }
  1494. case WAVE_FORMAT_GSM610:
  1495. {
  1496. if( m_pCoMemWaveFormatEx->nChannels != 1 )
  1497. {
  1498. return SPSF_ExtendedAudioFormat;
  1499. }
  1500. switch (m_pCoMemWaveFormatEx->nSamplesPerSec)
  1501. {
  1502. case 44100:
  1503. dwIndex = 3;
  1504. break;
  1505. case 22050:
  1506. dwIndex = 2;
  1507. break;
  1508. case 11025:
  1509. dwIndex = 1;
  1510. break;
  1511. case 8000:
  1512. dwIndex = 0;
  1513. break;
  1514. default:
  1515. return SPSF_ExtendedAudioFormat;
  1516. }
  1517. return static_cast<SPSTREAMFORMAT>(SPSF_GSM610_8kHzMono + dwIndex);
  1518. }
  1519. default:
  1520. return SPSF_ExtendedAudioFormat;
  1521. break;
  1522. }
  1523. }
  1524. void DetachTo(CSpStreamFormat & Other)
  1525. {
  1526. ::CoTaskMemFree(Other.m_pCoMemWaveFormatEx);
  1527. Other.m_guidFormatId = m_guidFormatId;
  1528. Other.m_pCoMemWaveFormatEx = m_pCoMemWaveFormatEx;
  1529. m_pCoMemWaveFormatEx = NULL;
  1530. memset(&m_guidFormatId, 0, sizeof(m_guidFormatId));
  1531. }
  1532. void DetachTo(GUID * pFormatId, WAVEFORMATEX ** ppCoMemWaveFormatEx)
  1533. {
  1534. *pFormatId = m_guidFormatId;
  1535. *ppCoMemWaveFormatEx = m_pCoMemWaveFormatEx;
  1536. m_pCoMemWaveFormatEx = NULL;
  1537. memset(&m_guidFormatId, 0, sizeof(m_guidFormatId));
  1538. }
  1539. HRESULT CopyTo(GUID * pFormatId, WAVEFORMATEX ** ppCoMemWFEX) const
  1540. {
  1541. HRESULT hr = S_OK;
  1542. *pFormatId = m_guidFormatId;
  1543. if (m_pCoMemWaveFormatEx)
  1544. {
  1545. hr = CoMemCopyWFEX(m_pCoMemWaveFormatEx, ppCoMemWFEX);
  1546. if (FAILED(hr))
  1547. {
  1548. memset(pFormatId, 0, sizeof(*pFormatId));
  1549. }
  1550. }
  1551. else
  1552. {
  1553. *ppCoMemWFEX = NULL;
  1554. }
  1555. return hr;
  1556. }
  1557. HRESULT CopyTo(CSpStreamFormat & Other) const
  1558. {
  1559. ::CoTaskMemFree(Other.m_pCoMemWaveFormatEx);
  1560. return CopyTo(&Other.m_guidFormatId, &Other.m_pCoMemWaveFormatEx);
  1561. }
  1562. HRESULT AssignFormat(const CSpStreamFormat & Src)
  1563. {
  1564. return Src.CopyTo(*this);
  1565. }
  1566. HRESULT ParamValidateCopyTo(GUID * pFormatId, WAVEFORMATEX ** ppCoMemWFEX) const
  1567. {
  1568. if (::IsBadWritePtr(pFormatId, sizeof(*pFormatId)) ||
  1569. ::IsBadWritePtr(ppCoMemWFEX, sizeof(*ppCoMemWFEX)))
  1570. {
  1571. return E_POINTER;
  1572. }
  1573. return CopyTo(pFormatId, ppCoMemWFEX);
  1574. }
  1575. BOOL operator==(const CSpStreamFormat & Other) const
  1576. {
  1577. return IsEqual(Other.m_guidFormatId, Other.m_pCoMemWaveFormatEx);
  1578. }
  1579. BOOL operator!=(const CSpStreamFormat & Other) const
  1580. {
  1581. return !IsEqual(Other.m_guidFormatId, Other.m_pCoMemWaveFormatEx);
  1582. }
  1583. ULONG SerializeSize() const
  1584. {
  1585. ULONG cb = sizeof(ULONG) + sizeof(m_guidFormatId);
  1586. if (m_pCoMemWaveFormatEx)
  1587. {
  1588. cb += sizeof(WAVEFORMATEX) + m_pCoMemWaveFormatEx->cbSize + 3; // Add 3 to round up
  1589. cb -= cb % 4; // Round to DWORD
  1590. }
  1591. return cb;
  1592. }
  1593. ULONG Serialize(BYTE * pBuffer) const
  1594. {
  1595. ULONG cb = SerializeSize();
  1596. *((UNALIGNED ULONG *)pBuffer) = cb;
  1597. pBuffer += sizeof(ULONG);
  1598. *((UNALIGNED GUID *)pBuffer) = m_guidFormatId;
  1599. if (m_pCoMemWaveFormatEx)
  1600. {
  1601. pBuffer += sizeof(m_guidFormatId);
  1602. memcpy(pBuffer, m_pCoMemWaveFormatEx, sizeof(WAVEFORMATEX) + m_pCoMemWaveFormatEx->cbSize);
  1603. }
  1604. return cb;
  1605. }
  1606. HRESULT Deserialize(const BYTE * pBuffer, ULONG * pcbUsed)
  1607. {
  1608. HRESULT hr = S_OK;
  1609. ::CoTaskMemFree(m_pCoMemWaveFormatEx);
  1610. m_pCoMemWaveFormatEx = NULL;
  1611. *pcbUsed = *((UNALIGNED ULONG *)pBuffer);
  1612. pBuffer += sizeof(ULONG);
  1613. // Misaligment exception is generated for SHx platform.
  1614. // Marking pointer as UNALIGNED does not help.
  1615. #ifndef _WIN32_WCE
  1616. m_guidFormatId = *((UNALIGNED GUID *)pBuffer);
  1617. #else
  1618. memcpy(&m_guidFormatId, pBuffer, sizeof(GUID));
  1619. #endif
  1620. if (*pcbUsed > sizeof(GUID) + sizeof(ULONG))
  1621. {
  1622. pBuffer += sizeof(m_guidFormatId);
  1623. hr = CoMemCopyWFEX((const WAVEFORMATEX *)pBuffer, &m_pCoMemWaveFormatEx);
  1624. if (FAILED(hr))
  1625. {
  1626. m_guidFormatId = GUID_NULL;
  1627. }
  1628. }
  1629. return hr;
  1630. }
  1631. };
  1632. // Return the default codepage given a LCID.
  1633. // Note some of the newer locales do not have associated Windows codepages. For these, we return UTF-8.
  1634. inline UINT SpCodePageFromLcid(LCID lcid)
  1635. {
  1636. char achCodePage[6];
  1637. return (0 != GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, achCodePage, sizeof(achCodePage))) ? atoi(achCodePage) : 65001;
  1638. }
  1639. inline HRESULT SPBindToFile( LPCWSTR pFileName, SPFILEMODE eMode, ISpStream ** ppStream,
  1640. const GUID * pFormatId = NULL, const WAVEFORMATEX * pWaveFormatEx = NULL,
  1641. ULONGLONG ullEventInterest = SPFEI_ALL_EVENTS)
  1642. {
  1643. HRESULT hr = ::CoCreateInstance(CLSID_SpStream, NULL, CLSCTX_ALL, __uuidof(*ppStream), (void **)ppStream);
  1644. if (SUCCEEDED(hr))
  1645. {
  1646. hr = (*ppStream)->BindToFile(pFileName, eMode, pFormatId, pWaveFormatEx, ullEventInterest);
  1647. if (FAILED(hr))
  1648. {
  1649. (*ppStream)->Release();
  1650. *ppStream = NULL;
  1651. }
  1652. }
  1653. return hr;
  1654. } /* SPBindToFile */
  1655. #ifndef _UNICODE
  1656. inline HRESULT SPBindToFile( const TCHAR * pFileName, SPFILEMODE eMode, ISpStream** ppStream,
  1657. const GUID * pFormatId = NULL, const WAVEFORMATEX * pWaveFormatEx = NULL,
  1658. ULONGLONG ullEventInterest = SPFEI_ALL_EVENTS)
  1659. {
  1660. WCHAR szWcharFileName[MAX_PATH];
  1661. ::MultiByteToWideChar(CP_ACP, 0, pFileName, -1, szWcharFileName, sp_countof(szWcharFileName));
  1662. return SPBindToFile(szWcharFileName, eMode, ppStream, pFormatId, pWaveFormatEx, ullEventInterest);
  1663. }
  1664. #endif
  1665. /****************************************************************************
  1666. * SpClearEvent *
  1667. *--------------*
  1668. * Description:
  1669. * Helper function that can be used by clients that do not use the CSpEvent
  1670. * class.
  1671. *
  1672. * Returns:
  1673. *
  1674. *****************************************************************************/
  1675. inline void SpClearEvent(SPEVENT * pe)
  1676. {
  1677. if( pe->elParamType != SPEI_UNDEFINED)
  1678. {
  1679. if( pe->elParamType == SPET_LPARAM_IS_POINTER ||
  1680. pe->elParamType == SPET_LPARAM_IS_STRING)
  1681. {
  1682. ::CoTaskMemFree((void *)pe->lParam);
  1683. }
  1684. else if (pe->elParamType == SPET_LPARAM_IS_TOKEN ||
  1685. pe->elParamType == SPET_LPARAM_IS_OBJECT)
  1686. {
  1687. ((IUnknown*)pe->lParam)->Release();
  1688. }
  1689. }
  1690. memset(pe, 0, sizeof(*pe));
  1691. }
  1692. /****************************************************************************
  1693. * SpInitEvent *
  1694. *-------------*
  1695. * Description:
  1696. *
  1697. * Returns:
  1698. *
  1699. *****************************************************************************/
  1700. inline void SpInitEvent(SPEVENT * pe)
  1701. {
  1702. memset(pe, 0, sizeof(*pe));
  1703. }
  1704. /****************************************************************************
  1705. * SpEventSerializeSize *
  1706. *----------------------*
  1707. * Description:
  1708. * Computes the required size of a buffer to serialize an event. The caller
  1709. * must specify which type of serialized event is desired -- either SPSERIALIZEDEVENT
  1710. * or SPSERIALIZEDEVENT64.
  1711. *
  1712. * Returns:
  1713. * Size in bytes required to seriailze the event.
  1714. *
  1715. ****************************************************************************/
  1716. // WCE compiler does not work propertly with template
  1717. #ifndef _WIN32_WCE
  1718. template <class T>
  1719. inline ULONG SpEventSerializeSize(const SPEVENT * pEvent)
  1720. {
  1721. ULONG ulSize = sizeof(T);
  1722. #else
  1723. inline ULONG SpEventSerializeSize(const SPEVENT * pEvent, ULONG ulSize)
  1724. {
  1725. #endif //_WIN32_WCE
  1726. if( ( pEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pEvent->lParam )
  1727. {
  1728. ulSize += ULONG(pEvent->wParam);
  1729. }
  1730. else if ((pEvent->elParamType == SPET_LPARAM_IS_STRING) && pEvent->lParam != NULL)
  1731. {
  1732. ulSize += (wcslen((WCHAR*)pEvent->lParam) + 1) * sizeof( WCHAR );
  1733. }
  1734. else if( pEvent->elParamType == SPET_LPARAM_IS_TOKEN )
  1735. {
  1736. CSpDynamicString dstrObjectId;
  1737. if( ((ISpObjectToken*)(pEvent->lParam))->GetId( &dstrObjectId ) == S_OK )
  1738. {
  1739. ulSize += (dstrObjectId.Length() + 1) * sizeof( WCHAR );
  1740. }
  1741. }
  1742. // Round up to nearest DWORD
  1743. ulSize += 3;
  1744. ulSize -= ulSize % 4;
  1745. return ulSize;
  1746. }
  1747. /****************************************************************************
  1748. * SpSerializedEventSize *
  1749. *-----------------------*
  1750. * Description:
  1751. * Returns the size, in bytes, used by a serialized event. The caller can
  1752. * pass a pointer to either a SPSERIAILZEDEVENT or SPSERIALIZEDEVENT64 structure.
  1753. *
  1754. * Returns:
  1755. * Number of bytes used by serizlied event
  1756. *
  1757. ********************************************************************* RAL ***/
  1758. // WCE compiler does not work propertly with template
  1759. #ifndef _WIN32_WCE
  1760. template <class T>
  1761. inline ULONG SpSerializedEventSize(const T * pSerEvent)
  1762. {
  1763. ULONG ulSize = sizeof(T);
  1764. if( ( pSerEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pSerEvent->SerializedlParam )
  1765. {
  1766. ulSize += ULONG(pSerEvent->SerializedwParam);
  1767. }
  1768. else if ((pSerEvent->elParamType == SPET_LPARAM_IS_STRING || pSerEvent->elParamType == SPET_LPARAM_IS_TOKEN) &&
  1769. pSerEvent->SerializedlParam != NULL)
  1770. {
  1771. ulSize += (wcslen((WCHAR*)(pSerEvent + 1)) + 1) * sizeof( WCHAR );
  1772. }
  1773. // Round up to nearest DWORD
  1774. ulSize += 3;
  1775. ulSize -= ulSize % 4;
  1776. return ulSize;
  1777. }
  1778. #else //_WIN32_WCE
  1779. inline ULONG SpSerializedEventSize(const SPSERIALIZEDEVENT * pSerEvent, ULONG ulSize)
  1780. {
  1781. if( ( pSerEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pSerEvent->SerializedlParam )
  1782. {
  1783. ulSize += ULONG(pSerEvent->SerializedwParam);
  1784. }
  1785. else if ((pSerEvent->elParamType == SPET_LPARAM_IS_STRING || pSerEvent->elParamType == SPET_LPARAM_IS_TOKEN) &&
  1786. pSerEvent->SerializedlParam != NULL)
  1787. {
  1788. ulSize += (wcslen((WCHAR*)(pSerEvent + 1)) + 1) * sizeof( WCHAR );
  1789. }
  1790. // Round up to nearest DWORD
  1791. ulSize += 3;
  1792. ulSize -= ulSize % 4;
  1793. return ulSize;
  1794. }
  1795. inline ULONG SpSerializedEventSize(const SPSERIALIZEDEVENT64 * pSerEvent, ULONG ulSize)
  1796. {
  1797. if( ( pSerEvent->elParamType == SPET_LPARAM_IS_POINTER ) && pSerEvent->SerializedlParam )
  1798. {
  1799. ulSize += ULONG(pSerEvent->SerializedwParam);
  1800. }
  1801. else if ((pSerEvent->elParamType == SPET_LPARAM_IS_STRING || pSerEvent->elParamType == SPET_LPARAM_IS_TOKEN) &&
  1802. pSerEvent->SerializedlParam != NULL)
  1803. {
  1804. ulSize += (wcslen((WCHAR*)(pSerEvent + 1)) + 1) * sizeof( WCHAR );
  1805. }
  1806. // Round up to nearest DWORD
  1807. ulSize += 3;
  1808. ulSize -= ulSize % 4;
  1809. return ulSize;
  1810. }
  1811. #endif //_WIN32_WCE
  1812. /*** CSpEvent helper class
  1813. *
  1814. */
  1815. class CSpEvent : public SPEVENT
  1816. {
  1817. public:
  1818. CSpEvent()
  1819. {
  1820. SpInitEvent(this);
  1821. }
  1822. ~CSpEvent()
  1823. {
  1824. SpClearEvent(this);
  1825. }
  1826. // If you need to take the address of a CSpEvent that is not const, use the AddrOf() method
  1827. // which will do debug checking of parameters. If you encounter this problem when calling
  1828. // GetEvents from an event source, you may want to use the GetFrom() method of this class.
  1829. const SPEVENT * operator&()
  1830. {
  1831. return this;
  1832. }
  1833. CSpEvent * AddrOf()
  1834. {
  1835. // Note: This method does not ASSERT since we assume the caller knows what they are doing.
  1836. return this;
  1837. }
  1838. void Clear()
  1839. {
  1840. SpClearEvent(this);
  1841. }
  1842. HRESULT CopyTo(SPEVENT * pDestEvent) const
  1843. {
  1844. memcpy(pDestEvent, this, sizeof(*pDestEvent));
  1845. if ((elParamType == SPET_LPARAM_IS_POINTER) && lParam)
  1846. {
  1847. SPDBG_ASSERT(wParam && (wParam < 0x100000)); // this is too big!
  1848. pDestEvent->lParam = (LPARAM)::CoTaskMemAlloc(wParam);
  1849. if (pDestEvent->lParam)
  1850. {
  1851. memcpy((void *)pDestEvent->lParam, (void *)lParam, wParam);
  1852. }
  1853. else
  1854. {
  1855. pDestEvent->eEventId = SPEI_UNDEFINED;
  1856. return E_OUTOFMEMORY;
  1857. }
  1858. }
  1859. else if (elParamType == SPET_LPARAM_IS_STRING && lParam != NULL)
  1860. {
  1861. pDestEvent->lParam = (LPARAM)::CoTaskMemAlloc((wcslen((WCHAR*)lParam) + 1) * sizeof(WCHAR));
  1862. if (pDestEvent->lParam)
  1863. {
  1864. wcscpy((WCHAR*)pDestEvent->lParam, (WCHAR*)lParam);
  1865. }
  1866. else
  1867. {
  1868. pDestEvent->eEventId = SPEI_UNDEFINED;
  1869. return E_OUTOFMEMORY;
  1870. }
  1871. }
  1872. else if (elParamType == SPET_LPARAM_IS_TOKEN ||
  1873. elParamType == SPET_LPARAM_IS_OBJECT)
  1874. {
  1875. ((IUnknown*)lParam)->AddRef();
  1876. }
  1877. return S_OK;
  1878. }
  1879. HRESULT GetFrom(ISpEventSource * pEventSrc)
  1880. {
  1881. SpClearEvent(this);
  1882. return pEventSrc->GetEvents(1, this, NULL);
  1883. }
  1884. HRESULT CopyFrom(const SPEVENT * pSrcEvent)
  1885. {
  1886. SpClearEvent(this);
  1887. return static_cast<const CSpEvent *>(pSrcEvent)->CopyTo(this);
  1888. }
  1889. void Detach(SPEVENT * pDestEvent = NULL)
  1890. {
  1891. if (pDestEvent)
  1892. {
  1893. memcpy(pDestEvent, this, sizeof(*pDestEvent));
  1894. }
  1895. memset(this, 0, sizeof(*this));
  1896. }
  1897. template <class T>
  1898. ULONG SerializeSize() const
  1899. {
  1900. return SpEventSerializeSize<T>(this);
  1901. }
  1902. // Call this method with either SPSERIALIZEDEVENT or SPSERIALIZEDEVENT64
  1903. template <class T>
  1904. void Serialize(T * pSerEvent) const
  1905. {
  1906. SPDBG_ASSERT(elParamType != SPET_LPARAM_IS_OBJECT);
  1907. pSerEvent->eEventId = this->eEventId;
  1908. pSerEvent->elParamType = this->elParamType;
  1909. pSerEvent->ulStreamNum = this->ulStreamNum;
  1910. pSerEvent->ullAudioStreamOffset = this->ullAudioStreamOffset;
  1911. pSerEvent->SerializedwParam = static_cast<ULONG>(this->wParam);
  1912. pSerEvent->SerializedlParam = static_cast<LONG>(this->lParam);
  1913. if (lParam)
  1914. {
  1915. switch(elParamType)
  1916. {
  1917. case SPET_LPARAM_IS_POINTER:
  1918. memcpy(pSerEvent + 1, (void *)lParam, wParam);
  1919. pSerEvent->SerializedlParam = sizeof(T);
  1920. break;
  1921. case SPET_LPARAM_IS_STRING:
  1922. wcscpy((WCHAR *)(pSerEvent + 1), (WCHAR*)lParam);
  1923. pSerEvent->SerializedlParam = sizeof(T);
  1924. break;
  1925. case SPET_LPARAM_IS_TOKEN:
  1926. {
  1927. CSpDynamicString dstrObjectId;
  1928. if( SUCCEEDED( ((ISpObjectToken*)lParam)->GetId( &dstrObjectId ) ) )
  1929. {
  1930. pSerEvent->SerializedwParam = (dstrObjectId.Length() + 1) * sizeof( WCHAR );;
  1931. memcpy( pSerEvent + 1, (void *)dstrObjectId.m_psz, static_cast<ULONG>(pSerEvent->SerializedwParam) );
  1932. }
  1933. pSerEvent->SerializedlParam = sizeof(T);
  1934. }
  1935. break;
  1936. default:
  1937. break;
  1938. }
  1939. }
  1940. }
  1941. template <class T>
  1942. HRESULT Serialize(T ** ppCoMemSerEvent, ULONG * pcbSerEvent) const
  1943. {
  1944. // WCE compiler does not work propertly with template
  1945. #ifndef _WIN32_WCE
  1946. *pcbSerEvent = SpEventSerializeSize<T>(this);
  1947. #else
  1948. *pcbSerEvent = SpEventSerializeSize(this, sizeof(** ppCoMemSerEvent));
  1949. #endif
  1950. *ppCoMemSerEvent = (T *)::CoTaskMemAlloc(*pcbSerEvent);
  1951. if (*ppCoMemSerEvent)
  1952. {
  1953. Serialize(*ppCoMemSerEvent);
  1954. return S_OK;
  1955. }
  1956. else
  1957. {
  1958. *pcbSerEvent = 0;
  1959. return E_OUTOFMEMORY;
  1960. }
  1961. }
  1962. // Call this method with either SPSERIALIZEDEVENT or SPSERIALIZEDEVENT64
  1963. template <class T>
  1964. HRESULT Deserialize(const T * pSerEvent, ULONG * pcbUsed = NULL)
  1965. {
  1966. Clear();
  1967. HRESULT hr = S_OK;
  1968. const UNALIGNED T * pTemp = pSerEvent;
  1969. this->eEventId = pTemp->eEventId;
  1970. this->elParamType = pTemp->elParamType;
  1971. this->ulStreamNum = pTemp->ulStreamNum;
  1972. this->ullAudioStreamOffset = pTemp->ullAudioStreamOffset;
  1973. this->wParam = static_cast<WPARAM>(pTemp->SerializedwParam);
  1974. this->lParam = static_cast<LPARAM>(pTemp->SerializedlParam);
  1975. if (pTemp->SerializedlParam)
  1976. {
  1977. ULONG cbAlloc = 0;
  1978. switch (pTemp->elParamType)
  1979. {
  1980. case SPET_LPARAM_IS_POINTER:
  1981. cbAlloc = static_cast<ULONG>(wParam);
  1982. break;
  1983. case SPET_LPARAM_IS_STRING:
  1984. cbAlloc = sizeof(WCHAR) * (1 + wcslen((const WCHAR *)(pTemp + 1)));
  1985. break;
  1986. case SPET_LPARAM_IS_TOKEN:
  1987. {
  1988. ULONG ulDataOffset = ULONG(lParam);
  1989. hr = SpGetTokenFromId( (const WCHAR*)(pTemp + 1),
  1990. (ISpObjectToken **)&lParam );
  1991. wParam = 0;
  1992. }
  1993. break;
  1994. }
  1995. if (cbAlloc)
  1996. {
  1997. void * pvBuff = ::CoTaskMemAlloc(cbAlloc);
  1998. this->lParam = (LPARAM)pvBuff;
  1999. if (pvBuff)
  2000. {
  2001. memcpy(pvBuff, pTemp + 1, cbAlloc);
  2002. }
  2003. else
  2004. {
  2005. hr = E_OUTOFMEMORY;
  2006. }
  2007. }
  2008. }
  2009. if( SUCCEEDED( hr ) && pcbUsed )
  2010. {
  2011. // WCE compiler does not work propertly with template
  2012. #ifndef _WIN32_WCE
  2013. *pcbUsed = SpEventSerializeSize<T>(this);
  2014. #else
  2015. *pcbUsed = SpEventSerializeSize(this, sizeof(*pTemp));
  2016. #endif
  2017. }
  2018. return hr;
  2019. }
  2020. //
  2021. // Helpers for access to events. Performs run-time checks in debug and casts
  2022. // data to the appropriate types
  2023. //
  2024. SPPHONEID Phoneme() const
  2025. {
  2026. SPDBG_ASSERT(eEventId == SPEI_PHONEME);
  2027. return (SPPHONEID)LOWORD(lParam);
  2028. }
  2029. SPVISEMES Viseme() const
  2030. {
  2031. SPDBG_ASSERT(eEventId == SPEI_VISEME);
  2032. return (SPVISEMES)LOWORD(lParam);
  2033. }
  2034. ULONG InputWordPos() const
  2035. {
  2036. SPDBG_ASSERT(eEventId == SPEI_WORD_BOUNDARY);
  2037. return ULONG(lParam);
  2038. }
  2039. ULONG InputWordLen() const
  2040. {
  2041. SPDBG_ASSERT(eEventId == SPEI_WORD_BOUNDARY);
  2042. return ULONG(wParam);
  2043. }
  2044. ULONG InputSentPos() const
  2045. {
  2046. SPDBG_ASSERT(eEventId == SPEI_SENTENCE_BOUNDARY);
  2047. return ULONG(lParam);
  2048. }
  2049. ULONG InputSentLen() const
  2050. {
  2051. SPDBG_ASSERT(eEventId == SPEI_SENTENCE_BOUNDARY);
  2052. return ULONG(wParam);
  2053. }
  2054. ISpObjectToken * ObjectToken() const
  2055. {
  2056. SPDBG_ASSERT(elParamType == SPET_LPARAM_IS_TOKEN);
  2057. return (ISpObjectToken *)lParam;
  2058. }
  2059. ISpObjectToken * VoiceToken() const // More explicit check than ObjectToken()
  2060. {
  2061. SPDBG_ASSERT(eEventId == SPEI_VOICE_CHANGE);
  2062. return ObjectToken();
  2063. }
  2064. BOOL PersistVoiceChange() const
  2065. {
  2066. SPDBG_ASSERT(eEventId == SPEI_VOICE_CHANGE);
  2067. return (BOOL)wParam;
  2068. }
  2069. IUnknown * Object() const
  2070. {
  2071. SPDBG_ASSERT(elParamType == SPET_LPARAM_IS_OBJECT);
  2072. return (IUnknown*)lParam;
  2073. }
  2074. ISpRecoResult * RecoResult() const
  2075. {
  2076. SPDBG_ASSERT(eEventId == SPEI_RECOGNITION || eEventId == SPEI_FALSE_RECOGNITION || eEventId == SPEI_HYPOTHESIS);
  2077. return (ISpRecoResult *)Object();
  2078. }
  2079. BOOL IsPaused()
  2080. {
  2081. SPDBG_ASSERT(eEventId == SPEI_RECOGNITION || eEventId == SPEI_SR_BOOKMARK);
  2082. return (BOOL)(wParam & SPREF_AutoPause);
  2083. }
  2084. BOOL IsEmulated()
  2085. {
  2086. SPDBG_ASSERT(eEventId == SPEI_RECOGNITION);
  2087. return (BOOL)(wParam & SPREF_Emulated);
  2088. }
  2089. const WCHAR * String() const
  2090. {
  2091. SPDBG_ASSERT(elParamType == SPET_LPARAM_IS_STRING);
  2092. return (const WCHAR*)lParam;
  2093. }
  2094. const WCHAR * BookmarkName() const
  2095. {
  2096. SPDBG_ASSERT(eEventId == SPEI_TTS_BOOKMARK);
  2097. return String();
  2098. }
  2099. const WCHAR * RequestTypeOfUI() const
  2100. {
  2101. SPDBG_ASSERT(eEventId == SPEI_REQUEST_UI);
  2102. return String();
  2103. }
  2104. SPRECOSTATE RecoState() const
  2105. {
  2106. SPDBG_ASSERT(eEventId == SPEI_RECO_STATE_CHANGE);
  2107. return static_cast<SPRECOSTATE>(wParam);
  2108. }
  2109. const WCHAR * PropertyName() const
  2110. {
  2111. SPDBG_ASSERT((eEventId == SPEI_PROPERTY_NUM_CHANGE && elParamType == SPET_LPARAM_IS_STRING) ||
  2112. (eEventId == SPEI_PROPERTY_STRING_CHANGE && elParamType == SPET_LPARAM_IS_POINTER));
  2113. // Note: Don't use String() method here since in the case of string attributes, the elParamType
  2114. // field specifies LPARAM_IS_POINTER, but the attribute name IS the first string in this buffer
  2115. return (const WCHAR*)lParam;
  2116. }
  2117. const LONG PropertyNumValue() const
  2118. {
  2119. SPDBG_ASSERT(eEventId == SPEI_PROPERTY_NUM_CHANGE);
  2120. return static_cast<LONG>(wParam);
  2121. }
  2122. const WCHAR * PropertyStringValue() const
  2123. {
  2124. // Search for the first NULL and return pointer to the char past it.
  2125. SPDBG_ASSERT(eEventId == SPEI_PROPERTY_STRING_CHANGE);
  2126. const WCHAR * psz;
  2127. for (psz = (const WCHAR *)lParam; *psz; psz++) {}
  2128. return psz + 1;
  2129. }
  2130. SPINTERFERENCE Interference() const
  2131. {
  2132. SPDBG_ASSERT(eEventId == SPEI_INTERFERENCE);
  2133. return static_cast<SPINTERFERENCE>(lParam);
  2134. }
  2135. HRESULT EndStreamResult() const
  2136. {
  2137. SPDBG_ASSERT(eEventId == SPEI_END_SR_STREAM);
  2138. return static_cast<HRESULT>(lParam);
  2139. }
  2140. BOOL InputStreamReleased() const
  2141. {
  2142. SPDBG_ASSERT(eEventId == SPEI_END_SR_STREAM);
  2143. return (wParam & SPESF_STREAM_RELEASED) ? TRUE : FALSE;
  2144. }
  2145. };
  2146. class CSpPhrasePtr
  2147. {
  2148. public:
  2149. SPPHRASE * m_pPhrase;
  2150. CSpPhrasePtr() : m_pPhrase(NULL) {}
  2151. CSpPhrasePtr(ISpPhrase * pPhraseObj, HRESULT * phr)
  2152. {
  2153. *phr = pPhraseObj->GetPhrase(&m_pPhrase);
  2154. }
  2155. ~CSpPhrasePtr()
  2156. {
  2157. ::CoTaskMemFree(m_pPhrase);
  2158. }
  2159. //The assert on operator& usually indicates a bug. If this is really
  2160. //what is needed, however, take the address of the m_pPhrase member explicitly.
  2161. SPPHRASE ** operator&()
  2162. {
  2163. SPDBG_ASSERT(m_pPhrase == NULL);
  2164. return &m_pPhrase;
  2165. }
  2166. operator SPPHRASE *() const
  2167. {
  2168. return m_pPhrase;
  2169. }
  2170. SPPHRASE & operator*() const
  2171. {
  2172. SPDBG_ASSERT(m_pPhrase);
  2173. return *m_pPhrase;
  2174. }
  2175. SPPHRASE * operator->() const
  2176. {
  2177. return m_pPhrase;
  2178. }
  2179. bool operator!() const
  2180. {
  2181. return (m_pPhrase == NULL);
  2182. }
  2183. void Clear()
  2184. {
  2185. if (m_pPhrase)
  2186. {
  2187. ::CoTaskMemFree(m_pPhrase);
  2188. m_pPhrase = NULL;
  2189. }
  2190. }
  2191. HRESULT GetFrom(ISpPhrase * pPhraseObj)
  2192. {
  2193. Clear();
  2194. return pPhraseObj->GetPhrase(&m_pPhrase);
  2195. }
  2196. };
  2197. template <class T>
  2198. class CSpCoTaskMemPtr
  2199. {
  2200. public:
  2201. T * m_pT;
  2202. CSpCoTaskMemPtr() : m_pT(NULL) {}
  2203. CSpCoTaskMemPtr(void * pv) : m_pT((T *)pv) {}
  2204. CSpCoTaskMemPtr(ULONG cElements, HRESULT * phr)
  2205. {
  2206. m_pT = (T *)::CoTaskMemAlloc(cElements * sizeof(T));
  2207. *phr = m_pT ? S_OK : E_OUTOFMEMORY;
  2208. }
  2209. ~CSpCoTaskMemPtr()
  2210. {
  2211. ::CoTaskMemFree(m_pT);
  2212. }
  2213. void Clear()
  2214. {
  2215. if (m_pT)
  2216. {
  2217. ::CoTaskMemFree(m_pT);
  2218. m_pT = NULL;
  2219. }
  2220. }
  2221. HRESULT Alloc(ULONG cArrayElements = 1)
  2222. {
  2223. m_pT = (T *)::CoTaskMemRealloc(m_pT, sizeof(T) * cArrayElements);
  2224. SPDBG_ASSERT(m_pT);
  2225. return (m_pT ? S_OK : E_OUTOFMEMORY);
  2226. }
  2227. void Attach(void * pv)
  2228. {
  2229. Clear();
  2230. m_pT = (T *)pv;
  2231. }
  2232. T * Detatch()
  2233. {
  2234. T * pT = m_pT;
  2235. m_pT = NULL;
  2236. return pT;
  2237. }
  2238. //The assert on operator& usually indicates a bug. If this is really
  2239. //what is needed, however, take the address of the m_pT member explicitly.
  2240. T ** operator&()
  2241. {
  2242. SPDBG_ASSERT(m_pT == NULL);
  2243. return &m_pT;
  2244. }
  2245. T * operator->()
  2246. {
  2247. SPDBG_ASSERT(m_pT != NULL);
  2248. return m_pT;
  2249. }
  2250. operator T *()
  2251. {
  2252. return m_pT;
  2253. }
  2254. bool operator!() const
  2255. {
  2256. return (m_pT == NULL);
  2257. }
  2258. };
  2259. /**** Helper function used to create a new phrase object from an array of
  2260. test words. Each word in the string is converted to a phrase element.
  2261. This is useful to create a phrase to pass to the EmulateRecognition method.
  2262. The method can convert standard words as well as words with the
  2263. "/display_text/lexical_form/pronounciation;" word format.
  2264. You can also specify the DisplayAttributes for each element if desired.
  2265. If prgDispAttribs is NULL then the DisplayAttribs for each element default to
  2266. SPAF_ONE_TRAILING_SPACE. ****/
  2267. inline HRESULT CreatePhraseFromWordArray(const WCHAR ** ppWords, ULONG cWords,
  2268. SPDISPLYATTRIBUTES * prgDispAttribs,
  2269. ISpPhraseBuilder **ppResultPhrase,
  2270. LANGID LangId = 0,
  2271. CComPtr<ISpPhoneConverter> cpPhoneConv = NULL)
  2272. {
  2273. SPDBG_FUNC("CreatePhraseFromWordArray");
  2274. HRESULT hr = S_OK;
  2275. if ( cWords == 0 || ppWords == NULL || ::IsBadReadPtr(ppWords, sizeof(*ppWords) * cWords ) )
  2276. {
  2277. return E_INVALIDARG;
  2278. }
  2279. if ( prgDispAttribs != NULL && ::IsBadReadPtr(prgDispAttribs, sizeof(*prgDispAttribs) * cWords ) )
  2280. {
  2281. return E_INVALIDARG;
  2282. }
  2283. size_t cTotalChars = 0;
  2284. ULONG i;
  2285. WCHAR** pStringPtrArray = (WCHAR**)::CoTaskMemAlloc( cWords * sizeof(WCHAR *));
  2286. if ( !pStringPtrArray )
  2287. {
  2288. return E_OUTOFMEMORY;
  2289. }
  2290. for (i = 0; i < cWords; i++)
  2291. {
  2292. cTotalChars += wcslen(ppWords[i])+1;
  2293. }
  2294. CSpDynamicString dsText(cTotalChars);
  2295. if(dsText.m_psz == NULL)
  2296. {
  2297. ::CoTaskMemFree(pStringPtrArray);
  2298. return E_OUTOFMEMORY;
  2299. }
  2300. CSpDynamicString dsPhoneId(cTotalChars);
  2301. if(dsPhoneId.m_psz == NULL)
  2302. {
  2303. ::CoTaskMemFree(pStringPtrArray);
  2304. return E_OUTOFMEMORY;
  2305. }
  2306. SPPHONEID* pphoneId = (SPPHONEID*)dsPhoneId.m_psz;
  2307. SPPHRASE Phrase;
  2308. memset(&Phrase, 0, sizeof(Phrase));
  2309. Phrase.cbSize = sizeof(Phrase);
  2310. if(LangId == 0)
  2311. {
  2312. LangId = SpGetUserDefaultUILanguage();
  2313. }
  2314. if(cpPhoneConv == NULL)
  2315. {
  2316. hr = SpCreatePhoneConverter(LangId, NULL, NULL, &cpPhoneConv);
  2317. if(FAILED(hr))
  2318. {
  2319. ::CoTaskMemFree(pStringPtrArray);
  2320. return hr;
  2321. }
  2322. }
  2323. SPPHRASEELEMENT *pPhraseElement = new SPPHRASEELEMENT[cWords];
  2324. if(pPhraseElement == NULL)
  2325. {
  2326. ::CoTaskMemFree(pStringPtrArray);
  2327. return E_OUTOFMEMORY;
  2328. }
  2329. memset(pPhraseElement, 0, sizeof(SPPHRASEELEMENT) * cWords); // !!!
  2330. WCHAR * pText = dsText;
  2331. for (i = 0; SUCCEEDED(hr) && i < cWords; i++)
  2332. {
  2333. WCHAR *p = pText;
  2334. pStringPtrArray[i] = pText;
  2335. wcscpy( pText, ppWords[i] );
  2336. pText += wcslen( p ) + 1;
  2337. if (*p == L'/')
  2338. {
  2339. //This is a compound word
  2340. WCHAR* pszFirstPart = ++p;
  2341. WCHAR* pszSecondPart = NULL;
  2342. WCHAR* pszThirdPart = NULL;
  2343. while (*p && *p != L'/')
  2344. {
  2345. p++;
  2346. }
  2347. if (*p == L'/')
  2348. {
  2349. //It means we stop at the second '/'
  2350. *p = L'\0';
  2351. pszSecondPart = ++p;
  2352. while (*p && *p != L'/')
  2353. {
  2354. p++;
  2355. }
  2356. if (*p == L'/')
  2357. {
  2358. //It means we stop at the third '/'
  2359. *p = L'\0';
  2360. pszThirdPart = ++p;
  2361. }
  2362. }
  2363. pPhraseElement[i].pszDisplayText = pszFirstPart;
  2364. pPhraseElement[i].pszLexicalForm = pszSecondPart ? pszSecondPart : pszFirstPart;
  2365. if ( pszThirdPart)
  2366. {
  2367. hr = cpPhoneConv->PhoneToId(pszThirdPart, pphoneId);
  2368. if (SUCCEEDED(hr))
  2369. {
  2370. pPhraseElement[i].pszPronunciation = pphoneId;
  2371. pphoneId += wcslen( (wchar_t*)pphoneId ) + 1;
  2372. }
  2373. }
  2374. }
  2375. else
  2376. {
  2377. //It is the simple format, only have one form, use it for everything.
  2378. pPhraseElement[i].pszDisplayText = NULL;
  2379. pPhraseElement[i].pszLexicalForm = p;
  2380. pPhraseElement[i].pszPronunciation = NULL;
  2381. }
  2382. pPhraseElement[i].bDisplayAttributes = (BYTE)(prgDispAttribs ? prgDispAttribs[i] : SPAF_ONE_TRAILING_SPACE);
  2383. pPhraseElement[i].RequiredConfidence = SP_NORMAL_CONFIDENCE;
  2384. pPhraseElement[i].ActualConfidence = SP_NORMAL_CONFIDENCE;
  2385. }
  2386. Phrase.Rule.ulCountOfElements = cWords;
  2387. Phrase.pElements = pPhraseElement;
  2388. Phrase.LangID = LangId;
  2389. CComPtr<ISpPhraseBuilder> cpPhrase;
  2390. if (SUCCEEDED(hr))
  2391. {
  2392. hr = cpPhrase.CoCreateInstance(CLSID_SpPhraseBuilder);
  2393. }
  2394. if (SUCCEEDED(hr))
  2395. {
  2396. hr = cpPhrase->InitFromPhrase(&Phrase);
  2397. }
  2398. if (SUCCEEDED(hr))
  2399. {
  2400. *ppResultPhrase = cpPhrase.Detach();
  2401. }
  2402. delete [] pPhraseElement;
  2403. ::CoTaskMemFree(pStringPtrArray);
  2404. return hr;
  2405. }
  2406. /**** Helper function used to create a new phrase object from a
  2407. test string. Each word in the string is converted to a phrase element.
  2408. This is useful to create a phrase to pass to the EmulateRecognition method.
  2409. The method can convert standard words as well as words with the
  2410. "/display_text/lexical_form/pronounciation;" word format ****/
  2411. inline HRESULT CreatePhraseFromText(const WCHAR *pszOriginalText,
  2412. ISpPhraseBuilder **ppResultPhrase,
  2413. LANGID LangId = 0,
  2414. CComPtr<ISpPhoneConverter> cpPhoneConv = NULL)
  2415. {
  2416. SPDBG_FUNC("CreatePhraseFromText");
  2417. HRESULT hr = S_OK;
  2418. //We first trim the input text
  2419. CSpDynamicString dsText(pszOriginalText);
  2420. if(dsText.m_psz == NULL)
  2421. {
  2422. return E_OUTOFMEMORY;
  2423. }
  2424. dsText.TrimBoth();
  2425. ULONG cWords = 0;
  2426. BOOL fInCompoundword = FALSE;
  2427. // Set first array pointer (if *p).
  2428. WCHAR *p = dsText;
  2429. while (*p)
  2430. {
  2431. if( iswspace(*p) && !fInCompoundword)
  2432. {
  2433. cWords++;
  2434. *p++ = L'\0';
  2435. while (*p && iswspace(*p))
  2436. {
  2437. *p++ = L'\0';
  2438. }
  2439. // Add new array pointer. Use vector.
  2440. }
  2441. else if (*p == L'/' && !fInCompoundword)
  2442. {
  2443. fInCompoundword = TRUE;
  2444. }
  2445. else if (*p == L';' && fInCompoundword)
  2446. {
  2447. fInCompoundword = FALSE;
  2448. *p++ = L'\0';
  2449. // Add new array element.
  2450. }
  2451. else
  2452. {
  2453. p++;
  2454. }
  2455. }
  2456. cWords++;
  2457. WCHAR** pStringPtrArray = (WCHAR**)::CoTaskMemAlloc( cWords * sizeof(WCHAR *));
  2458. if ( !pStringPtrArray )
  2459. {
  2460. hr = E_OUTOFMEMORY;
  2461. }
  2462. if ( SUCCEEDED( hr ) )
  2463. {
  2464. p = dsText;
  2465. for (ULONG i=0; i<cWords; i++)
  2466. {
  2467. pStringPtrArray[i] = p;
  2468. p += wcslen(p)+1;
  2469. }
  2470. hr = CreatePhraseFromWordArray((const WCHAR **)pStringPtrArray, cWords, NULL, ppResultPhrase, LangId, cpPhoneConv);
  2471. ::CoTaskMemFree(pStringPtrArray);
  2472. }
  2473. return hr;
  2474. }
  2475. #endif /* This must be the last line in the file */