sphelper.h
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:80k
源码类别:

模拟服务器

开发平台:

C/C++

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