mlstr.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 49k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. // MLStr.cpp : Implementation of CMLStr
  2. #include "private.h"
  3. #ifndef NEWMLSTR
  4. #include "mlstr.h"
  5. #ifdef ASTRIMPL
  6. #include "mlsbwalk.h"
  7. #endif
  8. /////////////////////////////////////////////////////////////////////////////
  9. // CMLStr Helper functions
  10. HRESULT RegularizePosLen(long lStrLen, long* plPos, long* plLen)
  11. {
  12.     ASSERT_WRITE_PTR(plPos);
  13.     ASSERT_WRITE_PTR(plLen);
  14.     long lPos = *plPos;
  15.     long lLen = *plLen;
  16.     if (lPos < 0)
  17.         lPos = lStrLen;
  18.     else
  19.         lPos = min(lPos, lStrLen);
  20.     if (lLen < 0)
  21.         lLen = lStrLen - lPos;
  22.     else
  23.         lLen = min(lLen, lStrLen - lPos);
  24.     *plPos = lPos;
  25.     *plLen = lLen;
  26.     return S_OK;
  27. }
  28. #ifdef ASTRIMPL
  29. HRESULT LocaleToCodePage(LCID locale, UINT* puCodePage)
  30. {
  31.     HRESULT hr = S_OK;
  32.     if (puCodePage)
  33.     {
  34.         TCHAR szCodePage[8];
  35.         if (::GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, szCodePage, ARRAYSIZE(szCodePage)) > 0)
  36.             *puCodePage = _ttoi(szCodePage);
  37.         else
  38.             hr = E_FAIL; // NLS failed
  39.     }
  40.     return hr;
  41. }
  42. #endif
  43. /////////////////////////////////////////////////////////////////////////////
  44. // CMLStr
  45. CMLStr::CMLStr(void) :
  46.     m_pMLStrBufW(NULL),
  47.     m_pMLStrBufA(NULL),
  48.     m_lBufFlags(0),
  49.     m_cchBuf(0),
  50.     m_locale(0),
  51. #ifdef ASTRIMPL
  52.     m_LockInfo(this)
  53. #else
  54.     m_lLockFlags(0)
  55. #endif
  56. {
  57.     m_dwThreadID = ::GetCurrentThreadId();
  58. }
  59. CMLStr::~CMLStr(void)
  60. {
  61.     if (m_pMLStrBufW)
  62.         m_pMLStrBufW->Release();
  63.     if (m_pMLStrBufA)
  64.         m_pMLStrBufA->Release();
  65. }
  66. STDMETHODIMP CMLStr::Sync(BOOL)
  67. {
  68.     ASSERT_THIS;
  69.     return S_OK; // No multithread supported; Always synchronized
  70. }
  71. STDMETHODIMP CMLStr::GetLength(long* plLen)
  72. {
  73.     ASSERT_THIS;
  74.     ASSERT_WRITE_PTR_OR_NULL(plLen);
  75.     HRESULT hr = CheckThread();
  76. #ifdef ASTRIMPL
  77.     CLock Lock(FALSE, this, hr);
  78. #endif
  79.     long lLen;
  80.     if (SUCCEEDED(hr))
  81.         hr = GetLen(0, GetBufCCh(), &lLen);
  82.     if (plLen)
  83.     {
  84.         if (SUCCEEDED(hr))
  85.             *plLen = lLen;
  86.         else
  87.             *plLen = 0;
  88.     }
  89.     return hr;
  90. }
  91. STDMETHODIMP CMLStr::SetMLStr(long, long, IUnknown*, long, long)
  92. {
  93.     return E_NOTIMPL; // IMLangString::SetMLStr()
  94. }
  95. STDMETHODIMP CMLStr::GetMLStr(long, long, IUnknown*, DWORD, const IID*, IUnknown**, long*, long*)
  96. {
  97.     return E_NOTIMPL; // IMLangString::GetMLStr()
  98. }
  99. #ifndef ASTRIMPL
  100. STDMETHODIMP CMLStr::SetWStr(long lDestPos, long lDestLen, const WCHAR* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
  101. {
  102.     return E_NOTIMPL; // !ASTRIMPL
  103. }
  104. STDMETHODIMP CMLStr::SetStrBufW(long lDestPos, long lDestLen, IMLangStringBufW* pSrcBuf, long* pcchActual, long* plActualLen)
  105. {
  106.     return SetStrBufCommon(NULL, lDestPos, lDestLen, 0, pSrcBuf, NULL, pcchActual, plActualLen);
  107. }
  108. #endif
  109. HRESULT CMLStr::SetStrBufCommon(void* pMLStrX, long lDestPos, long lDestLen, UINT uCodePage, IMLangStringBufW* pSrcBufW, IMLangStringBufA* pSrcBufA, long* pcchActual, long* plActualLen)
  110. {
  111.     ASSERT_THIS;
  112.     ASSERT_READ_PTR_OR_NULL(pSrcBufW);
  113.     ASSERT_READ_PTR_OR_NULL(pSrcBufA);
  114.     ASSERT(!pSrcBufW || !pSrcBufA); // Either one or both should be NULL
  115.     ASSERT_WRITE_PTR_OR_NULL(pcchActual);
  116.     ASSERT_WRITE_PTR_OR_NULL(plActualLen);
  117.     HRESULT hr = CheckThread();
  118. #ifdef ASTRIMPL
  119.     CLock Lock(TRUE, this, hr);
  120. #endif
  121.     long lBufFlags = 0; // '= 0' for in case of both of pSrcBufW and pSrcBufA are NULL
  122.     long cchBuf = 0;
  123.     long cchDestPos;
  124.     long cchDestLen;
  125.     long lActualLen = 0;
  126. #ifndef ASTRIMPL
  127.     if (SUCCEEDED(hr) && IsLocked())
  128.         hr = E_INVALIDARG; // This MLStr is locked
  129. #endif
  130.     if (SUCCEEDED(hr) &&
  131.         (!pSrcBufW || SUCCEEDED(hr = pSrcBufW->GetStatus(&lBufFlags, &cchBuf))) &&
  132.         (!pSrcBufA || SUCCEEDED(hr = pSrcBufA->GetStatus(&lBufFlags, &cchBuf))) &&
  133.         SUCCEEDED(hr = RegularizePosLen(&lDestPos, &lDestLen)) &&
  134.         SUCCEEDED(hr = GetCCh(0, lDestPos, &cchDestPos)) &&
  135.         SUCCEEDED(hr = GetCCh(cchDestPos, lDestLen, &cchDestLen)))
  136.     {
  137.         if (!cchDestPos && cchDestLen == GetBufCCh()) // Replacing entire string
  138.         {
  139.             IMLangStringBufW* const pOldBufW = GetMLStrBufW();
  140.             IMLangStringBufA* const pOldBufA = GetMLStrBufA();
  141.             if (pOldBufW)
  142.                 pOldBufW->Release();
  143.             else if (pOldBufA)
  144.                 pOldBufA->Release();
  145.             if (pSrcBufW)
  146.                 pSrcBufW->AddRef();
  147.             else if (pSrcBufA)
  148.                 pSrcBufA->AddRef();
  149.             SetMLStrBufW(pSrcBufW);
  150.             SetMLStrBufA(pSrcBufA);
  151.             SetCodePage(uCodePage);
  152.             SetBufFlags(lBufFlags);
  153.             SetBufCCh(cchBuf);
  154.             if (plActualLen)
  155.                 hr = GetLen(0, GetBufCCh(), &lActualLen);
  156.         }
  157.         else
  158.         {
  159. #ifdef ASTRIMPL
  160.             if (pSrcBufW)
  161.             {
  162.                 CMLStrBufWalkW BufWalk(pSrcBufW, 0, cchBuf, (pcchActual || plActualLen));
  163.                 while (BufWalk.Lock(hr))
  164.                 {
  165.                     long cchSet;
  166.                     long lSetLen;
  167.                     hr = ((IMLangStringWStr*)pMLStrX)->SetWStr(lDestPos, lDestLen, BufWalk.GetStr(), BufWalk.GetCCh(), &cchSet, (plActualLen) ? &lSetLen : NULL);
  168.                     lActualLen += lSetLen;
  169.                     BufWalk.Unlock(hr, cchSet);
  170.                 }
  171.                 cchBuf = BufWalk.GetDoneCCh();
  172.                 pSrcBufW->Release();
  173.             }
  174.             else if (pSrcBufA && pMLStrX)
  175.             {
  176.                 CMLStrBufWalkA BufWalk(pSrcBufA, 0, cchBuf, (pcchActual || plActualLen));
  177.                 while (BufWalk.Lock(hr))
  178.                 {
  179.                     long cchSet;
  180.                     long lSetLen;
  181.                     hr = ((IMLangStringAStr*)pMLStrX)->SetAStr(lDestPos, lDestLen, uCodePage, BufWalk.GetStr(), BufWalk.GetCCh(), &cchSet, (plActualLen) ? &lSetLen : NULL);
  182.                     lActualLen += lSetLen;
  183.                     BufWalk.Unlock(hr, cchSet);
  184.                 }
  185.                 cchBuf = BufWalk.GetDoneCCh();
  186.                 pSrcBufA->Release();
  187.             }
  188.             else
  189.             {
  190.                 hr = SetMLStr(lDestPos, lDestLen, NULL, 0, 0);
  191.             }
  192. #else
  193.             hr = E_INVALIDARG; // !ASTRIMPL
  194. #endif
  195.         }
  196.     }
  197.     if (SUCCEEDED(hr))
  198.     {
  199.         if (pcchActual)
  200.             *pcchActual = cchBuf;
  201.         if (plActualLen)
  202.             *plActualLen = lActualLen;
  203.     }
  204.     else
  205.     {
  206.         if (pcchActual)
  207.             *pcchActual = 0;
  208.         if (plActualLen)
  209.             *plActualLen = 0;
  210.     }
  211.     return hr;
  212. }
  213. #ifndef ASTRIMPL
  214. STDMETHODIMP CMLStr::GetWStr(long lSrcPos, long lSrcLen, WCHAR* pszDest, long cchDest, long* pcchActual, long* plActualLen)
  215. {
  216.     ASSERT_THIS;
  217.     ASSERT_WRITE_BLOCK_OR_NULL(pszDest, cchDest);
  218.     ASSERT_WRITE_PTR_OR_NULL(pcchActual);
  219.     ASSERT_WRITE_PTR_OR_NULL(plActualLen);
  220.     HRESULT hr = CheckThread();
  221.     long cchSrcPos;
  222.     long cchSrcLen;
  223.     long cchActual;
  224.     long lActualLen;
  225.     if (SUCCEEDED(hr) && IsLocked())
  226.         hr = E_INVALIDARG; // This MLStr is locked
  227.     if (SUCCEEDED(hr) &&
  228.         SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcLen)) &&
  229.         SUCCEEDED(hr = GetCCh(0, lSrcPos, &cchSrcPos)) &&
  230.         SUCCEEDED(hr = GetCCh(cchSrcPos, lSrcLen, &cchSrcLen)))
  231.     {
  232.         if (pszDest)
  233.         {
  234.             long cchActualTemp = min(cchSrcLen, cchDest);
  235.             cchActual = cchActualTemp;
  236.             while (SUCCEEDED(hr) && cchActualTemp > 0)
  237.             {
  238.                 WCHAR* pszBuf;
  239.                 long cchBuf;
  240.                 if (m_pMLStrBufW)
  241.                 {
  242.                     if (SUCCEEDED(hr = m_pMLStrBufW->LockBuf(cchSrcPos, cchActualTemp, &pszBuf, &cchBuf)))
  243.                     {
  244.                         ::memcpy(pszDest, pszBuf, sizeof(WCHAR) * cchBuf);
  245.                         hr = m_pMLStrBufW->UnlockBuf(pszBuf, 0, 0);
  246.                         cchSrcPos += cchBuf;
  247.                         cchActualTemp -= cchBuf;
  248.                         pszDest += cchBuf;
  249.                     }
  250.                 }
  251.                 else // m_pMLStrBufW
  252.                 {
  253.                     hr = E_FAIL;  // !ASTRIMPL
  254.                 }
  255.             }
  256.             if (FAILED(hr) && cchActualTemp < cchActual && (pcchActual || plActualLen))
  257.             {
  258.                 cchActual -= cchActualTemp;
  259.                 hr = S_OK;
  260.             }
  261.         }
  262.         else
  263.         {
  264.             cchActual = cchSrcLen;
  265.         }
  266.     }
  267.     if (SUCCEEDED(hr) && plActualLen)
  268.         hr = CalcLenW(0, cchActual, &lActualLen);
  269.     if (SUCCEEDED(hr))
  270.     {
  271.         if (pcchActual)
  272.             *pcchActual = cchActual;
  273.         if (plActualLen)
  274.             *plActualLen = lActualLen;
  275.     }
  276.     else
  277.     {
  278.         if (pcchActual)
  279.             *pcchActual = 0;
  280.         if (plActualLen)
  281.             *plActualLen = 0;
  282.     }
  283.     return hr;
  284. }
  285. STDMETHODIMP CMLStr::GetStrBufW(long, long, IMLangStringBufW**, long*)
  286. {
  287.     return E_NOTIMPL; // !ASTRIMPL
  288. }
  289. STDMETHODIMP CMLStr::LockWStr(long lSrcPos, long lSrcLen, long lFlags, long cchRequest, WCHAR** ppszDest, long* pcchDest, long* plDestLen)
  290. {
  291.     ASSERT_THIS;
  292.     ASSERT_WRITE_PTR_OR_NULL(ppszDest);
  293.     ASSERT_WRITE_PTR_OR_NULL(pcchDest);
  294.     ASSERT_WRITE_PTR_OR_NULL(plDestLen);
  295.     HRESULT hr = CheckThread();
  296.     long cchSrcPos;
  297.     long cchSrcLen;
  298.     WCHAR* pszBuf = NULL;
  299.     long cchBuf;
  300.     long lLockLen;
  301.     if (SUCCEEDED(hr) && (IsLocked() || !lFlags || (lFlags & ~GetBufFlags() & MLSTR_WRITE)))
  302.         hr = E_INVALIDARG; // This MLStr is locked, no flags specified or not writable
  303.     if (!(lFlags & MLSTR_WRITE))
  304.         cchRequest = 0;
  305.     if (SUCCEEDED(hr) &&
  306.         SUCCEEDED(hr = PrepareMLStrBuf()) &&
  307.         SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcLen)) &&
  308.         SUCCEEDED(hr = GetCCh(0, lSrcPos, &cchSrcPos)) &&
  309.         SUCCEEDED(hr = GetCCh(cchSrcPos, lSrcLen, &cchSrcLen)))
  310.     {
  311.         IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
  312.         SetDirectLockFlag(pMLStrBufW != 0);
  313.         if (IsDirectLock())
  314.         {
  315.             long cchInserted;
  316.             long cchLockLen = cchSrcLen;
  317.             if (cchRequest > cchSrcLen &&
  318.                 SUCCEEDED(hr = pMLStrBufW->Insert(cchSrcPos + cchSrcLen, cchRequest - cchSrcLen, &cchInserted)))
  319.             {
  320.                 SetBufCCh(GetBufCCh() + cchInserted);
  321.                 cchLockLen += cchInserted;
  322.                 if (!pcchDest && cchLockLen < cchRequest)
  323.                     hr = E_OUTOFMEMORY; // Can't insert in StrBuf
  324.             }
  325.             if (SUCCEEDED(hr) &&
  326.                 SUCCEEDED(hr = pMLStrBufW->LockBuf(cchSrcPos, cchLockLen, &pszBuf, &cchBuf)) &&
  327.                 !pcchDest && cchBuf < max(cchSrcLen, cchRequest))
  328.             {
  329.                 hr = E_OUTOFMEMORY; // Can't lock StrBuf
  330.             }
  331.         }
  332.         else if (m_pMLStrBufA)
  333.         {
  334.             long cchSize;
  335.             if (SUCCEEDED(hr = CalcBufSizeW(lSrcLen, &cchSize)))
  336.             {
  337.                 cchBuf = max(cchSize, cchRequest);
  338.                 hr = MemAlloc(sizeof(*pszBuf) * cchBuf, (void**)&pszBuf);
  339.             }
  340.             if (SUCCEEDED(hr) && (lFlags & MLSTR_READ))
  341.                 hr = ConvertMLStrBufAToWStr(m_uCodePage, m_pMLStrBufA, cchSrcPos, cchSrcLen, pszBuf, cchBuf, (pcchDest) ? &cchBuf : NULL);
  342.         }
  343.         else
  344.         {
  345.             hr = E_FAIL; // !ASTRIMPL
  346.         }
  347.     }
  348.     if (plDestLen && SUCCEEDED(hr))
  349.         hr = CalcLenW(pszBuf, cchBuf, &lLockLen);
  350.     if (SUCCEEDED(hr))
  351.     {
  352.         SetLockFlags(lFlags);
  353.         m_pszLockBuf = pszBuf;
  354.         m_cchLockPos = cchSrcPos;
  355.         m_cchLockLen = cchBuf;
  356.         m_lLockPos = lSrcPos;
  357.         m_lLockLen = lSrcLen;
  358.         if (ppszDest)
  359.             *ppszDest = pszBuf;
  360.         if (pcchDest)
  361.             *pcchDest = cchBuf;
  362.         if (plDestLen)
  363.             *plDestLen = lLockLen;
  364.     }
  365.     else
  366.     {
  367.         if (pszBuf)
  368.         {
  369.             if (IsDirectLock())
  370.                 GetMLStrBufW()->UnlockBuf(pszBuf, 0, 0);
  371.             else
  372.                 MemFree(pszBuf);
  373.         }
  374.         if (ppszDest)
  375.             *ppszDest = NULL;
  376.         if (pcchDest)
  377.             *pcchDest = 0;
  378.         if (plDestLen)
  379.             *plDestLen = 0;
  380.     }
  381.     return hr;
  382. }
  383. #endif
  384. #ifdef ASTRIMPL
  385. HRESULT CMLStr::UnlockWStrDirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
  386. {
  387.     HRESULT hr;
  388.     IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
  389.     const long cchLockLen = GetLockInfo()->GetCChLen(pKey);
  390.     if (SUCCEEDED(hr = pMLStrBufW->UnlockBuf((WCHAR*)pszSrc, 0, cchSrc)) &&
  391.         (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE))
  392.     {
  393.         if (cchSrc < cchLockLen)
  394.         {
  395.             if (SUCCEEDED(hr = pMLStrBufW->Delete(GetLockInfo()->GetCChPos(pKey) + cchSrc, cchLockLen - cchSrc)))
  396.                 SetBufCCh(GetBufCCh() - (cchLockLen - cchSrc));
  397.         }
  398.         if (SUCCEEDED(hr) && plActualLen)
  399.             hr = CalcLenW((WCHAR*)pszSrc, cchSrc, plActualLen);
  400.         if (pcchActual)
  401.             *pcchActual = cchSrc;
  402.     }
  403.     return hr;
  404. }
  405. HRESULT CMLStr::UnlockWStrIndirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
  406. {
  407.     HRESULT hr = S_OK;
  408.     if (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE)
  409.     {
  410.         CComQIPtr<IMLangStringWStr, &IID_IMLangStringWStr> pMLStrW(this);
  411.         ASSERT(pMLStrW);
  412.         hr = pMLStrW->SetWStr(GetLockInfo()->GetPos(pKey), GetLockInfo()->GetLen(pKey), (WCHAR*)pszSrc, cchSrc, pcchActual, plActualLen);
  413.     }
  414.     ASSIGN_IF_FAILED(hr, MemFree((void*)pszSrc));
  415.     return hr;
  416. }
  417. HRESULT CMLStr::UnlockAStrDirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
  418. {
  419.     HRESULT hr;
  420.     IMLangStringBufA* const pMLStrBufA = GetMLStrBufA();
  421.     const long cchLockLen = GetLockInfo()->GetCChLen(pKey);
  422.     if (SUCCEEDED(hr = pMLStrBufA->UnlockBuf((CHAR*)pszSrc, 0, cchSrc)) &&
  423.         (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE))
  424.     {
  425.         if (cchSrc < cchLockLen)
  426.         {
  427.             if (SUCCEEDED(hr = pMLStrBufA->Delete(GetLockInfo()->GetCChPos(pKey) + cchSrc, cchLockLen - cchSrc)))
  428.                 SetBufCCh(GetBufCCh() - (cchLockLen - cchSrc));
  429.         }
  430.         if (SUCCEEDED(hr) && plActualLen)
  431.             hr = CalcLenA(GetCodePage(), (CHAR*)pszSrc, cchSrc, plActualLen);
  432.         if (pcchActual)
  433.             *pcchActual = cchSrc;
  434.     }
  435.     return hr;
  436. }
  437. HRESULT CMLStr::UnlockAStrIndirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
  438. {
  439.     HRESULT hr = S_OK;
  440.     if (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE)
  441.     {
  442.         CComQIPtr<IMLangStringAStr, &IID_IMLangStringAStr> pMLStrA(this);
  443.         ASSERT(pMLStrA);
  444.         hr = pMLStrA->SetAStr(GetLockInfo()->GetPos(pKey), GetLockInfo()->GetLen(pKey), GetLockInfo()->GetCodePage(pKey), (CHAR*)pszSrc, cchSrc, pcchActual, plActualLen);
  445.     }
  446.     ASSIGN_IF_FAILED(hr, MemFree((void*)pszSrc));
  447.     return hr;
  448. }
  449. #endif
  450. #ifndef ASTRIMPL
  451. STDMETHODIMP CMLStr::UnlockWStr(const WCHAR* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
  452. {
  453.     ASSERT_THIS;
  454.     ASSERT_READ_BLOCK(pszSrc, cchSrc);
  455.     ASSERT_WRITE_PTR_OR_NULL(pcchActual);
  456.     ASSERT_WRITE_PTR_OR_NULL(plActualLen);
  457.     HRESULT hr = CheckThread();
  458.     long lSrcLen;
  459.     const long lLockFlags = GetLockFlags();
  460.     if (SUCCEEDED(hr) && (!IsLocked() || pszSrc != m_pszLockBuf))
  461.         hr = E_INVALIDARG; // This MLStr is not locked
  462.     if (!(lLockFlags & MLSTR_WRITE))
  463.     {
  464.         cchSrc = 0;
  465.         lSrcLen = 0;
  466.     }
  467.     if (SUCCEEDED(hr))
  468.     {
  469.         IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
  470.         if (IsDirectLock())
  471.         {
  472.             if (SUCCEEDED(hr = pMLStrBufW->UnlockBuf(pszSrc, 0, cchSrc)) &&
  473.                 (lLockFlags & MLSTR_WRITE))
  474.             {
  475.                 if (cchSrc < m_cchLockLen)
  476.                 {
  477.                     if (SUCCEEDED(hr = pMLStrBufW->Delete(m_cchLockPos + cchSrc, m_cchLockLen - cchSrc)))
  478.                         SetBufCCh(GetBufCCh() - (m_cchLockLen - cchSrc));
  479.                 }
  480.                 if (SUCCEEDED(hr) && plActualLen)
  481.                     hr = CalcLenW(pszSrc, cchSrc, &lSrcLen);
  482.             }
  483.         }
  484.         else
  485.         {
  486.             if (lLockFlags & MLSTR_WRITE)
  487.                 hr = SetWStr(m_lLockPos, m_lLockLen, pszSrc, cchSrc, (pcchActual) ? &cchSrc : NULL, (plActualLen) ? &lSrcLen : NULL);
  488.             HRESULT hrTemp = MemFree((void*)pszSrc);
  489.             if (FAILED(hrTemp) && SUCCEEDED(hr))
  490.                 hr = hrTemp;
  491.         }
  492.     }
  493.     if (SUCCEEDED(hr))
  494.     {
  495.         if (pcchActual)
  496.             *pcchActual = cchSrc;
  497.         if (plActualLen)
  498.             *plActualLen = lSrcLen;
  499.     }
  500.     else
  501.     {
  502.         if (pcchActual)
  503.             *pcchActual = 0;
  504.         if (plActualLen)
  505.             *plActualLen = 0;
  506.     }
  507.     SetLockFlags(0); // Unlock it anyway
  508.     return hr;
  509. }
  510. #endif
  511. #ifdef ASTRIMPL
  512. HRESULT CMLStr::UnlockStrCommon(const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
  513. {
  514.     HRESULT hr = CheckThread();
  515.     void* pLockKey;
  516.     long lSrcLen;
  517.     if (SUCCEEDED(hr))
  518.         hr = GetLockInfo()->Find(pszSrc, cchSrc, &pLockKey);
  519.     if (SUCCEEDED(hr))
  520.         hr = GetLockInfo()->Unlock(pLockKey, pszSrc, cchSrc, (pcchActual) ? &cchSrc : NULL, (plActualLen) ? &lSrcLen : NULL);
  521.     if (SUCCEEDED(hr))
  522.     {
  523.         if (pcchActual)
  524.             *pcchActual = cchSrc;
  525.         if (plActualLen)
  526.             *plActualLen = lSrcLen;
  527.     }
  528.     else
  529.     {
  530.         if (pcchActual)
  531.             *pcchActual = 0;
  532.         if (plActualLen)
  533.             *plActualLen = 0;
  534.     }
  535.     return hr;
  536. }
  537. #endif
  538. STDMETHODIMP CMLStr::SetLocale(long lDestPos, long lDestLen, LCID locale)
  539. {
  540.     ASSERT_THIS;
  541.     HRESULT hr = CheckThread();
  542. #ifdef ASTRIMPL
  543.     CLock Lock(TRUE, this, hr);
  544. #endif
  545.     long cchDestPos;
  546.     long cchDestLen;
  547.     if (SUCCEEDED(hr) &&
  548.         SUCCEEDED(hr = RegularizePosLen(&lDestPos, &lDestLen)) &&
  549.         SUCCEEDED(hr = GetCCh(0, lDestPos, &cchDestPos)) &&
  550.         SUCCEEDED(hr = GetCCh(cchDestPos, lDestLen, &cchDestLen)))
  551.     {
  552.         //if (!cchDestPos && cchDestLen == GetBufCCh())
  553.             SetLocale(locale);
  554.         //else
  555.         //    hr = E_NOTIMPL; // Cannot set the locale to a part of string in this version.
  556.     }
  557.     return hr;
  558. }
  559. STDMETHODIMP CMLStr::GetLocale(long lSrcPos, long lSrcMaxLen, LCID* plocale, long* plLocalePos, long* plLocaleLen)
  560. {
  561.     ASSERT_THIS;
  562.     ASSERT_WRITE_PTR_OR_NULL(plocale);
  563.     ASSERT_WRITE_PTR_OR_NULL(plLocalePos);
  564.     ASSERT_WRITE_PTR_OR_NULL(plLocaleLen);
  565.     HRESULT hr = CheckThread();
  566. #ifdef ASTRIMPL
  567.     CLock Lock(FALSE, this, hr);
  568. #endif
  569.     long lStrLen;
  570.     if (SUCCEEDED(hr) &&
  571.         SUCCEEDED(hr = GetLen(0, GetBufCCh(), &lStrLen)) &&
  572.         SUCCEEDED(hr = ::RegularizePosLen(lStrLen, &lSrcPos, &lSrcMaxLen)))
  573.     {
  574.         if (plocale)
  575.             *plocale = GetLocale();
  576.         if (plLocalePos)
  577.             *plLocalePos = 0;
  578.         if (plLocaleLen)
  579.         {
  580.             if (plLocalePos)
  581.                 *plLocaleLen = lStrLen;
  582.             else
  583.                 *plLocaleLen = lSrcMaxLen;
  584.         }
  585.     }
  586.     else
  587.     {
  588.         if (plocale)
  589.             *plocale = 0;
  590.         if (plLocalePos)
  591.             *plLocalePos = 0;
  592.         if (plLocaleLen)
  593.             *plLocaleLen = 0;
  594.     }
  595.     return hr;
  596. }
  597. HRESULT CMLStr::PrepareMLStrBuf(void)
  598. {
  599.     if (GetMLStrBufW() || GetMLStrBufA())
  600.         return S_OK;
  601. #ifdef ASTRIMPL
  602.     IMLangStringBufW* pBuf = new CMLStr::CMLStrBufStandardW;
  603.     if (pBuf)
  604.     {
  605.         SetMLStrBufW(pBuf);
  606.         return S_OK;
  607.     }
  608.     else
  609.     {
  610.         return E_OUTOFMEMORY;
  611.     }
  612. #else
  613.     else
  614.         return E_NOTIMPL; //!ASTRIMPL
  615. #endif
  616. }
  617. HRESULT CMLStr::RegularizePosLen(long* plPos, long* plLen)
  618. {
  619.     HRESULT hr;
  620.     long lStrLen;
  621.     if (SUCCEEDED(hr = GetLen(0, GetBufCCh(), &lStrLen)))
  622.         hr = ::RegularizePosLen(lStrLen, plPos, plLen);
  623.     return hr;
  624. }
  625. HRESULT CMLStr::GetCCh(long cchOffset, long lLen, long* pcchLen)
  626. {
  627.     if (GetMLStrBufW())
  628.     {
  629.         if (pcchLen)
  630.             *pcchLen = lLen; // The number of characters is equal to the length
  631.         return S_OK;
  632.     }
  633.     else if (GetMLStrBufA())
  634.     {
  635.         HRESULT hr = S_OK;
  636. #ifdef ASTRIMPL
  637.         CMLStrBufWalkA BufWalk(GetMLStrBufA(), cchOffset, GetBufCCh() - cchOffset);
  638.         while (lLen > 0 && BufWalk.Lock(hr))
  639.         {
  640.             for (LPCSTR pszTemp = BufWalk.GetStr(); lLen > 0 && *pszTemp; lLen--)
  641.                 pszTemp = ::CharNextExA((WORD)GetCodePage(), pszTemp, 0);
  642.             if (!*pszTemp)
  643.                 lLen = 0; // String terminated
  644.             BufWalk.Unlock(hr);
  645.         }
  646. #else
  647.         long cchDone = 0;
  648.         long cchRest = GetBufCCh() - cchOffset;
  649.         while (SUCCEEDED(hr) && lLen > 0)
  650.         {
  651.             CHAR* pszBuf;
  652.             long cchBuf;
  653.             if (SUCCEEDED(hr = m_pMLStrBufA->LockBuf(cchOffset, cchRest, &pszBuf, &cchBuf)))
  654.             {
  655.                 for (LPCSTR pszTemp = pszBuf; lLen > 0 && *pszTemp; lLen--)
  656.                     pszTemp = ::CharNextExA((WORD)m_uCodePage, pszTemp, 0);
  657.                 if (!*pszBuf)
  658.                     lLen = 0; // String terminated
  659.                 hr = m_pMLStrBufA->UnlockBuf(pszBuf, 0, 0);
  660.                 cchOffset += cchBuf;
  661.                 cchRest -= cchBuf;
  662.                 cchDone += (int)(pszTemp - pszBuf);
  663.             }
  664.         }
  665. #endif
  666.         if (pcchLen)
  667.         {
  668.             if (SUCCEEDED(hr))
  669. #ifdef ASTRIMPL
  670.                 *pcchLen = BufWalk.GetDoneCCh();
  671. #else
  672.                 *pcchLen = cchDone;
  673. #endif
  674.             else
  675.                 *pcchLen = 0;
  676.         }
  677.         return hr;
  678.     }
  679.     else
  680.     {
  681.         if (pcchLen)
  682.             *pcchLen = 0; // No string
  683.         return S_OK;
  684.     }
  685. }
  686. HRESULT CMLStr::GetLen(long cchOffset, long cchLen, long* plLen)
  687. {
  688.     if (GetMLStrBufW())
  689.     {
  690.         if (plLen)
  691.             *plLen = cchLen; // The length is equal to the number of characters
  692.         return S_OK;
  693.     }
  694.     else if (GetMLStrBufA())
  695.     {
  696.         HRESULT hr = S_OK;
  697.         long lDoneLen = 0;
  698. #ifdef ASTRIMPL
  699.         CMLStrBufWalkA BufWalk(GetMLStrBufA(), cchOffset, cchLen);
  700.         while (BufWalk.Lock(hr))
  701.         {
  702.             long lTempLen;
  703.             hr = CalcLenA(GetCodePage(), BufWalk.GetStr(), BufWalk.GetCCh(), &lTempLen);
  704.             if (hr == S_FALSE)
  705.                 cchLen = 0; // String terminated
  706.             lDoneLen += lTempLen;
  707.             BufWalk.Unlock(hr);
  708.         }
  709. #else
  710.         while (SUCCEEDED(hr) && cchLen > 0)
  711.         {
  712.             CHAR* pszBuf;
  713.             long cchBuf;
  714.             if (SUCCEEDED(hr = m_pMLStrBufA->LockBuf(cchOffset, cchLen, &pszBuf, &cchBuf)))
  715.             {
  716.                 long lTempLen;
  717.                 hr = CalcLenA(GetCodePage(), pszBuf, cchBuf, &lTempLen);
  718.                 if (hr == S_FALSE)
  719.                     cchLen = 0; // String terminated
  720.                 lDoneLen += lTempLen;
  721.                 hr = m_pMLStrBufA->UnlockBuf(pszBuf, 0, 0);
  722.                 cchOffset += cchBuf;
  723.                 cchLen -= cchBuf;
  724.             }
  725.         }
  726. #endif
  727.         if (plLen)
  728.         {
  729.             if (SUCCEEDED(hr))
  730.                 *plLen = lDoneLen;
  731.             else
  732.                 *plLen = 0;
  733.         }
  734.         return hr;
  735.     }
  736.     else
  737.     {
  738.         if (plLen)
  739.             *plLen = 0; // No string
  740.         return S_OK;
  741.     }
  742. }
  743. HRESULT CMLStr::CalcLenA(UINT uCodePage, const CHAR* psz, long cchLen, long* plLen)
  744. {
  745.     long lLen = 0;
  746.     const CHAR* const pszEnd = psz + cchLen;
  747.     for (; psz < pszEnd && *psz; lLen++)
  748.     {
  749.         const CHAR* const pszNew = ::CharNextExA((WORD)uCodePage, psz, 0);
  750.         if (pszNew > pszEnd) // Overrun out of buffer
  751.             break;
  752.         psz = pszNew;
  753.     }
  754.     if (plLen)
  755.         *plLen = lLen;
  756.     if (*psz)
  757.         return S_OK;
  758.     else
  759.         return S_FALSE;
  760. }
  761. #ifdef ASTRIMPL
  762. HRESULT CMLStr::CalcCChA(UINT uCodePage, const CHAR* psz, long lLen, long* pcchLen)
  763. {
  764.     const CHAR* const pszStart = psz;
  765.     for (; lLen > 0 && *psz; lLen--)
  766.         psz = ::CharNextExA((WORD)uCodePage, psz, 0);
  767.     if (pcchLen)
  768.         *pcchLen = psz - pszStart;
  769.     if (*psz)
  770.         return S_OK;
  771.     else
  772.         return S_FALSE;
  773. }
  774. HRESULT CMLStr::ConvAStrToWStr(UINT uCodePage, const CHAR* pszSrc, long cchSrc, WCHAR* pszDest, long cchDest, long* pcchActualA, long* pcchActualW, long* plActualLen)
  775. {
  776.     HRESULT hr = S_OK;
  777.     long lWrittenLen;
  778.     long cchWrittenA;
  779.     long cchWrittenW = ::MultiByteToWideChar(uCodePage, 0, pszSrc, cchSrc, pszDest, (pszDest) ? cchDest : 0);
  780.     if (!cchWrittenW)
  781.         hr = E_FAIL; // NLS failed
  782.     if ((pcchActualA || plActualLen) && SUCCEEDED(hr))
  783.         hr = CalcLenW(pszDest, cchWrittenW, &lWrittenLen); // BOGUS: pszDest may be NULL
  784.     if (pcchActualA && SUCCEEDED(hr))
  785.         hr = CalcCChA(uCodePage, pszSrc, lWrittenLen, &cchWrittenA);
  786.     if (SUCCEEDED(hr))
  787.     {
  788.         if (pcchActualA)
  789.             *pcchActualA = cchWrittenA;
  790.         if (pcchActualW)
  791.             *pcchActualW = cchWrittenW;
  792.         if (plActualLen)
  793.             *plActualLen = lWrittenLen;
  794.     }
  795.     else
  796.     {
  797.         if (pcchActualA)
  798.             *pcchActualA = 0;
  799.         if (pcchActualW)
  800.             *pcchActualW = 0;
  801.         if (plActualLen)
  802.             *plActualLen = 0;
  803.     }
  804.     return hr;
  805. }
  806. HRESULT CMLStr::ConvWStrToAStr(BOOL fCanStopAtMiddle, UINT uCodePage, const WCHAR* pszSrc, long cchSrc, CHAR* pszDest, long cchDest, long* pcchActualA, long* pcchActualW, long* plActualLen)
  807. {
  808.     HRESULT hr = S_OK;
  809.     long lWrittenLen;
  810.     long cchWrittenW;
  811.     long cchWrittenA = ::WideCharToMultiByte(uCodePage, (fCanStopAtMiddle) ? 0 : WC_DEFAULTCHAR, pszSrc, cchSrc, pszDest, (pszDest) ? cchDest : 0, NULL, NULL);
  812.     if (!cchWrittenA)
  813.         hr = E_FAIL; // NLS failed
  814.     if ((pcchActualW || plActualLen) && SUCCEEDED(hr))
  815.     {
  816.         if (pszDest)
  817.             hr = CalcLenA(uCodePage, pszDest, cchWrittenA, &lWrittenLen);
  818.         else
  819.             hr = E_NOTIMPL; // Can't retrieve pcchActualW and plActualLen
  820.     }
  821.     if (pcchActualW && SUCCEEDED(hr))
  822.         hr = CalcCChW(pszSrc, lWrittenLen, &cchWrittenW);
  823.     if (SUCCEEDED(hr))
  824.     {
  825.         if (pcchActualA)
  826.             *pcchActualA = cchWrittenA;
  827.         if (pcchActualW)
  828.             *pcchActualW = cchWrittenW;
  829.         if (plActualLen)
  830.             *plActualLen = lWrittenLen;
  831.     }
  832.     else
  833.     {
  834.         if (pcchActualA)
  835.             *pcchActualA = 0;
  836.         if (pcchActualW)
  837.             *pcchActualW = 0;
  838.         if (plActualLen)
  839.             *plActualLen = 0;
  840.     }
  841.     return hr;
  842. }
  843. #endif
  844. #ifndef ASTRIMPL
  845. HRESULT CMLStr::ConvertMLStrBufAToWStr(UINT uCodePage, IMLangStringBufA* pMLStrBufA, long cchSrcPos, long cchSrcLen, WCHAR* pszBuf, long cchBuf, long* pcchActual)
  846. {
  847.     HRESULT hr = S_OK;
  848.     long cchDone = 0;
  849.     while (SUCCEEDED(hr) && cchSrcLen > 0)
  850.     {
  851.         CHAR* pszBufA;
  852.         long cchBufA;
  853.         if (SUCCEEDED(hr = pMLStrBufA->LockBuf(cchSrcPos, cchSrcLen, &pszBufA, &cchBufA)))
  854.         {
  855.             long cchWritten = ::MultiByteToWideChar(uCodePage, 0, pszBufA, cchBufA, pszBuf, cchBuf);
  856.             if (!cchWritten)
  857.                 hr = E_FAIL; // NLS failed
  858.             HRESULT hrTemp = pMLStrBufA->UnlockBuf(pszBufA, 0, 0);
  859.             if (FAILED(hrTemp) && SUCCEEDED(hr))
  860.                 hr = hrTemp;
  861.             cchSrcPos += cchBufA;
  862.             cchSrcLen -= cchBufA;
  863.             pszBuf += cchWritten;
  864.             cchBuf -= cchWritten;
  865.             cchDone += cchWritten;
  866.             ASSERT(cchBuf >= 0);
  867.         }
  868.     }
  869.     if (pcchActual)
  870.     {
  871.         *pcchActual = cchDone;
  872.         if (FAILED(hr) && cchDone > 0)
  873.             hr = S_OK;
  874.     }
  875.     return hr;
  876. }
  877. HRESULT CMLStr::ConvertWStrToMLStrBufA(const WCHAR*, long, UINT, IMLangStringBufA*, long, long)
  878. {
  879.     return E_NOTIMPL; // !ASTRIMPL
  880. }
  881. #endif
  882. #ifdef ASTRIMPL
  883. /////////////////////////////////////////////////////////////////////////////
  884. // CMLStr::CLockInfo
  885. HRESULT CMLStr::CLockInfo::UnlockAll(void)
  886. {
  887.     if (m_pLockArray)
  888.     {
  889.         for (int n = 0; n < MAX_LOCK_COUNT; n++)
  890.         {
  891.             if (m_pLockArray[n].m_psz)
  892.                 Unlock(&m_pLockArray[n], m_pLockArray[n].m_psz, m_pLockArray[n].m_cchLen, NULL, NULL);
  893.         }
  894.     }
  895.     return S_OK;
  896. }
  897. HRESULT CMLStr::CLockInfo::Lock(PFNUNLOCKPROC pfnUnlockProc, long lFlags, UINT uCodePage, void* psz, long lPos, long lLen, long cchPos, long cchLen)
  898. {
  899.     HRESULT hr = S_OK;
  900.     int nIndex;
  901.     if (!m_pLockArray)
  902.     {
  903.         m_pLockArray = new CLockInfoEntry[MAX_LOCK_COUNT];
  904.         if (m_pLockArray)
  905.         {
  906.             for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++)
  907.                 m_pLockArray[nIndex].m_psz = NULL;
  908.         }
  909.         else
  910.         {
  911.             hr = E_OUTOFMEMORY;
  912.         }
  913.     }
  914.     if (SUCCEEDED(hr))
  915.     {
  916.         for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++)
  917.         {
  918.             if (!m_pLockArray[nIndex].m_psz)
  919.                 break;
  920.         }
  921.         if (nIndex >= MAX_LOCK_COUNT)
  922.             hr = MLSTR_E_TOOMANYNESTOFLOCK;
  923.     }
  924.     if (SUCCEEDED(hr))
  925.     {
  926.         m_pLockArray[nIndex].m_psz = psz;
  927.         m_pLockArray[nIndex].m_pfnUnlockProc = pfnUnlockProc;
  928.         m_pLockArray[nIndex].m_lFlags = lFlags;
  929.         m_pLockArray[nIndex].m_uCodePage = uCodePage;
  930.         m_pLockArray[nIndex].m_lPos = lPos;
  931.         m_pLockArray[nIndex].m_lLen = lLen;
  932.         m_pLockArray[nIndex].m_cchPos = cchPos;
  933.         m_pLockArray[nIndex].m_cchLen = cchLen;
  934.     }
  935.     return hr;
  936. }
  937. HRESULT CMLStr::CLockInfo::Find(const void* psz, long, void** ppKey)
  938. {
  939.     HRESULT hr = S_OK;
  940.     int nIndex;
  941.     if (m_pLockArray)
  942.     {
  943.         for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++)
  944.         {
  945.             if (psz == m_pLockArray[nIndex].m_psz)
  946.                 break;
  947.         }
  948.     }
  949.     if (!m_pLockArray || nIndex >= MAX_LOCK_COUNT)
  950.         hr = E_INVALIDARG;
  951.     if (ppKey)
  952.     {
  953.         if (SUCCEEDED(hr))
  954.             *ppKey = &m_pLockArray[nIndex];
  955.         else
  956.             *ppKey = NULL;
  957.     }
  958.     return hr;
  959. }
  960. HRESULT CMLStr::CLockInfo::Unlock(void* pKey, const void* psz, long cch, long* pcchActual, long* plActualLen)
  961. {
  962.     CLockInfoEntry* const pEntry = (CLockInfoEntry*)pKey;
  963.     HRESULT hr;
  964.     if (!(pEntry->m_lFlags & MLSTR_WRITE))
  965.     {
  966.         cch = 0;
  967.         if (plActualLen)
  968.             *plActualLen = 0;
  969.     }
  970.     hr = (m_pMLStr->*(pEntry->m_pfnUnlockProc))(pKey, psz, cch, pcchActual, plActualLen);
  971.     if (SUCCEEDED(hr))
  972.         hr = EndLock(pEntry->m_lFlags & MLSTR_WRITE);
  973.     pEntry->m_psz = NULL; // Remove from lock array anyway
  974.     if (FAILED(hr))
  975.     {
  976.         if (pcchActual)
  977.             *pcchActual = 0;
  978.         if (plActualLen)
  979.             *plActualLen = 0;
  980.     }
  981.     return hr;
  982. }
  983. /////////////////////////////////////////////////////////////////////////////
  984. // CMLStr::CMLStrBufStandardW
  985. long CMLStr::CMLStrBufStandardW::RoundBufSize(long cchStr)
  986. {
  987.     for (int n = 8; n < 12; n++)
  988.     {
  989.         if (cchStr < (1L << n))
  990.             break;
  991.     }
  992.     const long cchTick = (1L << (n - 4));
  993.     return (cchStr + cchTick - 1) / cchTick * cchTick;
  994. }
  995. #endif
  996. #else // NEWMLSTR
  997. #include "mlstr.h"
  998. /////////////////////////////////////////////////////////////////////////////
  999. // CMLStr
  1000. CMLStr::CMLStr(void) :
  1001.     m_lLen(0),
  1002.     m_hUnlockEvent(NULL),
  1003.     m_hZeroEvent(NULL)
  1004. {
  1005. }
  1006. CMLStr::~CMLStr(void)
  1007. {
  1008.     void* pv;
  1009.     if (m_hZeroEvent)
  1010.         ::CloseHandle(m_hZeroEvent);
  1011.     if (m_hUnlockEvent)
  1012.         ::CloseHandle(m_hUnlockEvent);
  1013.     // m_lock should be empty
  1014.     ASSERT(SUCCEEDED(m_lock.Top(&pv)));
  1015.     ASSERT(!pv);
  1016.     // Release all attributes in m_attr
  1017.     VERIFY(SUCCEEDED(m_attr.Top(&pv)));
  1018.     while (pv)
  1019.     {
  1020.         IMLStrAttr* const pAttr = m_attr.GetAttr(pv);
  1021.         ASSERT(pAttr);
  1022.         VERIFY(SUCCEEDED(pAttr->SetClient(NULL))); // Reset
  1023.         VERIFY(SUCCEEDED(StartEndConnectionAttr(pAttr, NULL, m_attr.GetCookie(pv)))); // Disconnect
  1024.         pAttr->Release();
  1025.         VERIFY(SUCCEEDED(m_attr.Next(pv, &pv)));
  1026.     }
  1027. }
  1028. STDMETHODIMP CMLStr::LockMLStr(long lPos, long lLen, DWORD dwFlags, DWORD* pdwCookie, long* plActualPos, long* plActualLen)
  1029. {
  1030.     ASSERT_WRITE_PTR_OR_NULL(pdwCookie);
  1031.     ASSERT_WRITE_PTR_OR_NULL(plActualPos);
  1032.     ASSERT_WRITE_PTR_OR_NULL(plActualLen);
  1033.     HRESULT hr;
  1034.     void* pv;
  1035.     Lock();
  1036.     if (SUCCEEDED(hr = ::RegularizePosLen(m_lLen, &lPos, &lLen)))
  1037.     {
  1038.         const DWORD dwThrd = ::GetCurrentThreadId();
  1039.         if (SUCCEEDED(hr = CheckAccessValidation(lPos, lLen, dwFlags, dwThrd, plActualPos, plActualLen)) &&
  1040.             SUCCEEDED(hr = m_lock.Add(&pv)))
  1041.         {
  1042.             if (plActualPos && !plActualLen)
  1043.                 lLen -= *plActualPos - lPos;
  1044.             else if (plActualLen)
  1045.                 lLen = *plActualLen;
  1046.             if (plActualPos)
  1047.                 lPos = *plActualPos;
  1048.             hr = m_lock.SetLock(pv, lPos, lLen, dwFlags, dwThrd);
  1049.             if (FAILED(hr))
  1050.                 VERIFY(SUCCEEDED(m_lock.Remove(pv)));
  1051.         }
  1052.     }
  1053.     else
  1054.     {
  1055.         if (plActualPos)
  1056.             *plActualPos = 0;
  1057.         if (plActualLen)
  1058.             *plActualLen = 0;
  1059.     }
  1060.     Unlock();
  1061.     if (pdwCookie)
  1062.     {
  1063.         if (SUCCEEDED(hr))
  1064.             *pdwCookie = (DWORD)pv;
  1065.         else
  1066.             *pdwCookie = 0;
  1067.     }
  1068.     return hr;
  1069. }
  1070. HRESULT CMLStr::CheckAccessValidation(long lPos, long lLen, DWORD dwFlags, DWORD dwThrd, long* plActualPos, long* plActualLen)
  1071. {
  1072.     HRESULT hr;
  1073.     DWORD dwStartTime = 0;
  1074.     long lActualPos;
  1075.     long lActualLen;
  1076.     for (;;) // Waiting unlock loop
  1077.     {
  1078.         void* pv;
  1079.         HRESULT hrValidation = S_OK;
  1080.         lActualPos = lPos;
  1081.         lActualLen = lLen;
  1082.         hr = m_lock.Top(&pv);
  1083.         while (SUCCEEDED(hr) && pv) // Enumerate all locks
  1084.         {
  1085.             LOCKINFO* plinfo;
  1086.             if (SUCCEEDED(hr = m_lock.GetLockInfo(pv, &plinfo))) // Retrieve info of a lock
  1087.             {
  1088.                 if ((dwFlags & MLSTR_MOVE) && // Moving this lock
  1089.                     lPos < plinfo->lPos + plinfo->lLen && // Overwrap or left of this lock
  1090.                     (dwThrd != plinfo->dwThrd || // Another thread
  1091.                      (plinfo->dwFlags & (MLSTR_READ | MLSTR_WRITE)))) // Same thread and has read or write access
  1092.                 {
  1093.                     if (dwThrd == plinfo->dwThrd)
  1094.                         hr = MLSTR_E_ACCESSDENIED;
  1095.                     else
  1096.                         hr = MLSTR_E_BUSY;
  1097.                 }
  1098.                 if (SUCCEEDED(hr) &&
  1099.                     lActualPos < plinfo->lPos + plinfo->lLen &&
  1100.                     lActualPos + lActualLen >= plinfo->lPos) // Overwraping with this lock
  1101.                 {
  1102.                     DWORD dwShareMask = 0;
  1103.                     if (dwThrd == plinfo->dwThrd) // Same thread
  1104.                         dwShareMask = ~(MLSTR_SHARE_DENYREAD | MLSTR_SHARE_DENYWRITE); // Ignore share flags
  1105.                     if (((dwFlags & MLSTR_WRITE) && (plinfo->dwFlags & (MLSTR_READ | MLSTR_WRITE | MLSTR_SHARE_DENYWRITE) & dwShareMask)) || // Write on read/write
  1106.                         ((dwFlags & MLSTR_READ)  && (plinfo->dwFlags & (             MLSTR_WRITE | MLSTR_SHARE_DENYREAD ) & dwShareMask)) || // Read on write
  1107.                         ((dwFlags & MLSTR_SHARE_DENYWRITE & dwShareMask) && (plinfo->dwFlags & MLSTR_WRITE)) || // Share deny on write
  1108.                         ((dwFlags & MLSTR_SHARE_DENYREAD  & dwShareMask) && (plinfo->dwFlags & MLSTR_READ)))    // Share deny on read
  1109.                     {
  1110.                         // Conflicting access
  1111.                         if ((plinfo->lPos <= lActualPos && plinfo->lPos + plinfo->lLen >= lActualPos + lActualLen) || // No valid range left
  1112.                             (!plActualPos && !plActualLen)) // Needs to lock entire range
  1113.                         {
  1114.                             lActualPos = 0;
  1115.                             lActualLen = 0;
  1116.                             if (dwThrd == plinfo->dwThrd)
  1117.                                 hr = MLSTR_E_ACCESSDENIED;
  1118.                             else
  1119.                                 hr = MLSTR_E_BUSY;
  1120.                         }
  1121.                         else if ((!plActualPos && plinfo->lPos <= lActualPos) || // Forward processing, Starting from invalid range
  1122.                                  (!plActualLen && plinfo->lPos + plinfo->lLen < lActualPos + lActualLen) || // Backward processing, Trancate valid range
  1123.                                  (plActualPos && plActualLen && plinfo->lPos - lActualPos >= (lActualPos + lActualLen) - (plinfo->lPos + plinfo->lLen))) // Maximum valid range, Right valid range is bigger
  1124.                         {
  1125.                             lActualLen += lActualPos;
  1126.                             lActualPos = plinfo->lPos + plinfo->lLen;
  1127.                             lActualLen -= lActualPos;
  1128.                             if (!plActualPos) // Forward processing
  1129.                             {
  1130.                                 if (dwThrd == plinfo->dwThrd)
  1131.                                     hrValidation = MLSTR_E_ACCESSDENIED;
  1132.                                 else
  1133.                                     hrValidation = MLSTR_E_BUSY;
  1134.                             }
  1135.                         }
  1136.                         else
  1137.                         {
  1138.                             lActualLen = plinfo->lPos - lActualPos;
  1139.                             if (!plActualLen) // Backward processing
  1140.                             {
  1141.                                 if (dwThrd == plinfo->dwThrd)
  1142.                                     hrValidation = MLSTR_E_ACCESSDENIED;
  1143.                                 else
  1144.                                     hrValidation = MLSTR_E_BUSY;
  1145.                             }
  1146.                         }
  1147.                     }
  1148.                 }
  1149.             }
  1150.             if (SUCCEEDED(hr))
  1151.                 hr = m_lock.Next(pv, &pv);
  1152.         }
  1153.         if (SUCCEEDED(hr) && FAILED(hrValidation))
  1154.         {
  1155.             hr = hrValidation;
  1156.             if (plActualLen && lPos < lActualPos) // Forward processing
  1157.             {
  1158.                 lActualLen = lActualPos - lPos;
  1159.                 lActualPos = lPos;
  1160.             }
  1161.             else if (plActualPos && lPos + lLen != lActualPos + lActualLen) // Backward processing
  1162.             {
  1163.                 lActualPos += lActualLen;
  1164.                 lActualLen = lPos + lLen - lActualPos;
  1165.             }
  1166.         }
  1167.         if (hr != MLSTR_E_BUSY || (dwFlags | MLSTR_NOWAIT)) // No busy state, or don't want to wait even if busy
  1168.             break;
  1169.         // Now, let's wait another thread run UnlockMLStr. Then, try validation again.
  1170.         if (!dwStartTime) // Not initialized yet
  1171.             dwStartTime = ::GetTickCount(); // Remember starting time
  1172.         const DWORD dwElapsedTime = ::GetTickCount() - dwStartTime;
  1173.         if (dwElapsedTime >= MLSTR_LOCK_TIMELIMIT) // Already elapsed long time
  1174.             break;
  1175.         if (!m_hUnlockEvent) // We don't have event object yet
  1176.         {
  1177.             m_hUnlockEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); // Manual reset, initial reset
  1178.             if (!m_hUnlockEvent)
  1179.                 break;
  1180.             m_cWaitUnlock = -1; // Initialize
  1181.         }
  1182.         else // After second time
  1183.         {
  1184.             ASSERT(m_cWaitUnlock == 0 || m_cWaitUnlock == -1 || m_cWaitUnlock >= 1);
  1185.             if (m_cWaitUnlock == 0) // Don't reset if m_cWaitUnlock is not zero
  1186.             {
  1187.                 ::ResetEvent(m_hUnlockEvent);
  1188.                 m_cWaitUnlock = -1;
  1189.             }
  1190.             else
  1191.             {
  1192.                 if (!m_hZeroEvent)
  1193.                 {
  1194.                     m_hZeroEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial reset
  1195.                     if (!m_hZeroEvent)
  1196.                         break;
  1197.                 }
  1198.                 if (m_cWaitUnlock == -1)
  1199.                     m_cWaitUnlock = 2;
  1200.                 else
  1201.                     m_cWaitUnlock++;
  1202.             }
  1203.         }
  1204.         ASSERT(m_cWaitUnlock == -1 || m_cWaitUnlock >= 2);
  1205.         // CAUTION: Don't leave here until we make sure m_cWaitUnlock gets zero.
  1206.         Unlock();
  1207.         // === The story of m_cWaitUnlock ===
  1208.         // If we don't have m_cWaitUnlock, the following scenario can be considered.
  1209.         // (1) Thread A: ResetEvent(m_hUnlockEvent)
  1210.         // (2) Thread A: Unlock()
  1211.         // (3) Thread B: SetEvent(m_hUnlockEvent) // UnlockMLStr!!!
  1212.         // (4) Thread C: Lock()
  1213.         // (5) Thread C: ResetEvent(m_hUnlockEvent) // Problem!!!
  1214.         // (6) Thread C: Unlock()
  1215.         // (7) Thread A: WaitForSingleObject(m_hUnlockEvent)
  1216.         // In this scenario, thread A is missing a event of (3). This situation should not happen.
  1217.         // m_cWaitUnlock solves the problem.
  1218.         const DWORD dwWaitResult = ::WaitForSingleObject(m_hUnlockEvent, MLSTR_LOCK_TIMELIMIT - dwElapsedTime); // Now wait unlock
  1219.         Lock();
  1220.         ASSERT(m_cWaitUnlock == -1 || m_cWaitUnlock >= 1);
  1221.         if (m_cWaitUnlock == -1)
  1222.         {
  1223.             m_cWaitUnlock = 0;
  1224.         }
  1225.         else // m_cWaitUnlock >= 1
  1226.         {
  1227.             m_cWaitUnlock--;
  1228.             // Here, let's wait until m_cWaitUnlock gets zero.
  1229.             // Unless this, it may not good for performance.
  1230.             // In worst case, it makes thousands of loops in this function because it never reset m_hUnlockEvent.
  1231.             // m_hUnlockEvent will be signaled even though UnlockMLStr is called yet.
  1232.             if (m_cWaitUnlock > 0)
  1233.             {
  1234.                 Unlock();
  1235.                 ::WaitForSingleObject(m_hZeroEvent, INFINITE); // Wait until m_cWaitUnlock gets zero, auto-reset
  1236.                 Lock();
  1237.             }
  1238.             else // Now it's zero! Yeah!
  1239.             {
  1240.                 ::SetEvent(m_hZeroEvent); // Release other threads
  1241.             }
  1242.         }
  1243.         // ASSERT(m_cWaitUnlock == 0); This is not true. Maybe non-zero for next time.
  1244.         // Now we may leave here.
  1245.         if (dwWaitResult != WAIT_OBJECT_0) // Time expired or an error occurred
  1246.             break;
  1247.     }
  1248.     if (plActualPos)
  1249.         *plActualPos = lActualPos;
  1250.     if (plActualLen)
  1251.         *plActualLen = lActualLen;
  1252.     return hr;
  1253. }
  1254. STDMETHODIMP CMLStr::UnlockMLStr(DWORD dwCookie)
  1255. {
  1256.     Lock();
  1257.     void* const pv = (void*)dwCookie;
  1258.     const HRESULT hr = m_lock.Remove(pv);
  1259.     if (m_hUnlockEvent)
  1260.         ::SetEvent(m_hUnlockEvent);
  1261.     Unlock();
  1262.     return hr;
  1263. }
  1264. STDMETHODIMP CMLStr::GetLength(long* plLen)
  1265. {
  1266.     ASSERT_THIS;
  1267.     ASSERT_WRITE_PTR_OR_NULL(plLen);
  1268.     if (plLen)
  1269.         *plLen = m_lLen;
  1270.     return S_OK;
  1271. }
  1272. STDMETHODIMP CMLStr::SetMLStr(long, long, IUnknown*, long, long)
  1273. {
  1274.     return E_NOTIMPL; // IMLangString::SetMLStr()
  1275. }
  1276. STDMETHODIMP CMLStr::RegisterAttr(IUnknown* pUnk, DWORD* pdwCookie)
  1277. {
  1278.     ASSERT_THIS;
  1279.     ASSERT_READ_PTR(pUnk);
  1280.     ASSERT_WRITE_PTR_OR_NULL(pdwCookie);
  1281.     HRESULT hr;
  1282.     void* pv;
  1283.     IMLStrAttr* pAttr = NULL;
  1284.     BOOL fConnStarted = FALSE;
  1285.     DWORD dwConnCookie;
  1286.     Lock();
  1287.     if (SUCCEEDED(hr = m_attr.Add(&pv)) &&
  1288.         SUCCEEDED(hr = pUnk->QueryInterface(IID_IMLStrAttr, (void**)&pAttr)))
  1289.     {
  1290.         ASSERT_READ_PTR(pAttr);
  1291.     }
  1292.     if (SUCCEEDED(hr) &&
  1293.         SUCCEEDED(hr = StartEndConnectionAttr(pAttr, &dwConnCookie, 0))) // Connect
  1294.     {
  1295.         fConnStarted = TRUE;
  1296.         if (SUCCEEDED(hr = pAttr->SetClient((IMLangString*)this)))
  1297.         {
  1298.             CFire fire(hr, this);
  1299.             while (fire.Next())
  1300.                 hr = fire.Sink()->OnRegisterAttr(pAttr);
  1301.         }
  1302.     }
  1303.     if (SUCCEEDED(hr) &&
  1304.         SUCCEEDED(hr = pAttr->SetMLStr(0, -1, (IMLangString*)this, 0, m_lLen)))
  1305.     {
  1306.         m_attr.SetAttr(pv, pAttr);
  1307.         m_attr.SetCookie(pv, dwConnCookie);
  1308.         if (pdwCookie)
  1309.             *pdwCookie = (DWORD)pv;
  1310.     }
  1311.     else
  1312.     {
  1313.         if (pAttr)
  1314.         {
  1315.             pAttr->SetClient(NULL);
  1316.             if (fConnStarted)
  1317.                 VERIFY(SUCCEEDED(StartEndConnectionAttr(pAttr, NULL, dwConnCookie))); // Disconnect
  1318.             pAttr->Release();
  1319.         }
  1320.         if (pv)
  1321.             m_attr.Remove(pv);
  1322.         if (pdwCookie)
  1323.             *pdwCookie = NULL;
  1324.     }
  1325.     Unlock();
  1326.     return hr;
  1327. }
  1328. STDMETHODIMP CMLStr::UnregisterAttr(DWORD dwCookie)
  1329. {
  1330.     ASSERT_THIS;
  1331.     void* const pv = (void*)dwCookie;
  1332.     Lock();
  1333.     IMLStrAttr* const pAttr = m_attr.GetAttr(pv);
  1334.     ASSERT(pAttr);
  1335.     // Fire OnUnregisterAttr
  1336.     HRESULT hr;
  1337.     CFire fire(hr, this);
  1338.     while (fire.Next())
  1339.         hr = fire.Sink()->OnUnregisterAttr(pAttr);
  1340.     // Release attribute
  1341.     if (SUCCEEDED(hr) &&
  1342.         SUCCEEDED(hr = pAttr->SetClient(NULL))) // Reset
  1343.     {
  1344.         VERIFY(SUCCEEDED(hr = StartEndConnectionAttr(pAttr, NULL, m_attr.GetCookie(pv)))); // Disconnect
  1345.         pAttr->Release();
  1346.         // Remove entry from attr table
  1347.         m_attr.Remove(pv);
  1348.     }
  1349.     Unlock();
  1350.     return hr;
  1351. }
  1352. STDMETHODIMP CMLStr::EnumAttr(IEnumUnknown** ppEnumUnk)
  1353. {
  1354.     ASSERT_THIS;
  1355.     ASSERT_WRITE_PTR_OR_NULL(ppEnumUnk);
  1356.     if (!ppEnumUnk)
  1357.         return S_OK;
  1358.     CEnumAttr* const pEnum = new CComObject<CEnumAttr>;
  1359.     *ppEnumUnk = pEnum;
  1360.     if (pEnum)
  1361.     {
  1362.         pEnum->Init(this);
  1363.         return S_OK;
  1364.     }
  1365.     else
  1366.     {
  1367.         return E_OUTOFMEMORY;
  1368.     }
  1369. }
  1370. STDMETHODIMP CMLStr::FindAttr(REFIID riid, LPARAM lParam, IUnknown** ppUnk)
  1371. {
  1372.     ASSERT_THIS;
  1373.     ASSERT_WRITE_PTR_OR_NULL(ppUnk);
  1374.     HRESULT hr;
  1375.     void* pv;
  1376.     IUnknown* pMaxUnk = NULL;
  1377.     long lMaxConf = 0;
  1378.     Lock();
  1379.     for (hr = m_attr.Top(&pv); SUCCEEDED(hr) && pv; hr = m_attr.Next(pv, &pv))
  1380.     {
  1381.         IMLStrAttr* const pIMLStrAttr = m_attr.GetAttr(pv);
  1382.         IUnknown* pUnk;
  1383.         long lConf;
  1384.         hr = pIMLStrAttr->QueryAttr(riid, lParam, &pUnk, &lConf);
  1385.         if (SUCCEEDED(hr))
  1386.         {
  1387.             if (lConf > lMaxConf)
  1388.             {
  1389.                 lMaxConf = lConf;
  1390.                 if (pMaxUnk)
  1391.                     pMaxUnk->Release();
  1392.                 pMaxUnk = pUnk;
  1393.             }
  1394.             else
  1395.             {
  1396.                 if (pUnk)
  1397.                     pUnk->Release();
  1398.             }
  1399.             if (lMaxConf == MLSTR_CONF_MAX)
  1400.                 break;
  1401.         }
  1402.     }
  1403.     if (SUCCEEDED(hr))
  1404.     {
  1405.         if (ppUnk)
  1406.             *ppUnk = pMaxUnk;
  1407.         else if (pMaxUnk)
  1408.             pMaxUnk->Release();
  1409.     }
  1410.     else
  1411.     {
  1412.         if (pMaxUnk)
  1413.             pMaxUnk->Release();
  1414.         if (ppUnk)
  1415.             *ppUnk = NULL;
  1416.     }
  1417.     Unlock();
  1418.     return hr;
  1419. }
  1420. STDMETHODIMP CMLStr::OnRequestEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk)
  1421. {
  1422.     HRESULT hr;
  1423.     CFire fire(hr, this);
  1424.     while (fire.Next())
  1425.         hr = fire.Sink()->OnRequestEdit(lDestPos, lDestLen, lNewLen, riid, lParam, pUnk);
  1426.     return hr;
  1427. }
  1428. STDMETHODIMP CMLStr::OnCanceledEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk)
  1429. {
  1430.     HRESULT hr;
  1431.     CFire fire(hr, this);
  1432.     while (fire.Next())
  1433.         hr = fire.Sink()->OnCanceledEdit(lDestPos, lDestLen, lNewLen, riid, lParam, pUnk);
  1434.     return hr;
  1435. }
  1436. STDMETHODIMP CMLStr::OnChanged(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk)
  1437. {
  1438.     HRESULT hr;
  1439.     CFire fire(hr, this);
  1440.     while (fire.Next())
  1441.         hr = fire.Sink()->OnChanged(lDestPos, lDestLen, lNewLen, riid, lParam, pUnk);
  1442.     return hr;
  1443. }
  1444. /////////////////////////////////////////////////////////////////////////////
  1445. // CMLStr::CEnumAttr
  1446. CMLStr::CEnumAttr::CEnumAttr(void) :
  1447.     m_pMLStr(NULL),
  1448.     m_pv(NULL)
  1449. {
  1450. }
  1451. CMLStr::CEnumAttr::~CEnumAttr(void)
  1452. {
  1453.     if (m_pMLStr)
  1454.         m_pMLStr->Unlock();
  1455. }
  1456. void CMLStr::CEnumAttr::Init(CMLStr* pMLStr)
  1457. {
  1458.     ASSERT_THIS;
  1459.     ASSERT_READ_PTR(pMLStr);
  1460.     if (m_pMLStr)
  1461.         m_pMLStr->Unlock();
  1462.     m_pMLStr = pMLStr;
  1463.     m_pMLStr->Lock();
  1464.     VERIFY(SUCCEEDED(Reset()));
  1465. }
  1466. HRESULT CMLStr::CEnumAttr::Next(ULONG celt, IUnknown** rgelt, ULONG* pceltFetched)
  1467. {
  1468.     ASSERT_THIS;
  1469.     ASSERT_WRITE_BLOCK_OR_NULL(rgelt, celt);
  1470.     ASSERT_WRITE_PTR_OR_NULL(pceltFetched);
  1471.     ULONG c = 0;
  1472.     if (rgelt && m_pMLStr)
  1473.     {
  1474.         for (; m_pv && c < celt; c++)
  1475.         {
  1476.             *rgelt = m_pMLStr->m_attr.GetAttr(m_pv);
  1477.             ASSERT(*rgelt);
  1478.             (*rgelt)->AddRef();
  1479.             VERIFY(SUCCEEDED(m_pMLStr->m_attr.Next(m_pv, &m_pv)));
  1480.             rgelt++;
  1481.         }
  1482.     }
  1483.     if (pceltFetched)
  1484.         *pceltFetched = c;
  1485.     return S_OK;
  1486. }
  1487. HRESULT CMLStr::CEnumAttr::Skip(ULONG celt)
  1488. {
  1489.     ASSERT_THIS;
  1490.     for (ULONG c = 0; m_pv && c < celt; c++)
  1491.         VERIFY(SUCCEEDED(m_pMLStr->m_attr.Next(m_pv, &m_pv)));
  1492.     return S_OK;
  1493. }
  1494. HRESULT CMLStr::CEnumAttr::Reset(void)
  1495. {
  1496.     ASSERT_THIS;
  1497.     ASSERT_READ_PTR(m_pMLStr);
  1498.     VERIFY(SUCCEEDED(m_pMLStr->m_attr.Top(&m_pv)));
  1499.     return S_OK;
  1500. }
  1501. HRESULT CMLStr::CEnumAttr::Clone(IEnumUnknown** ppEnum)
  1502. {
  1503.     ASSERT_THIS;
  1504.     ASSERT_WRITE_PTR_OR_NULL(ppEnum);
  1505.     ASSERT_READ_PTR(m_pMLStr);
  1506.     return m_pMLStr->EnumAttr(ppEnum);
  1507. }
  1508. #endif // NEWMLSTR