|
|
// MLStr.cpp : Implementation of CMLStr
#include "private.h"
#ifndef NEWMLSTR
#include "mlstr.h"
#ifdef ASTRIMPL
#include "mlsbwalk.h"
#endif
/////////////////////////////////////////////////////////////////////////////
// CMLStr Helper functions
HRESULT RegularizePosLen(long lStrLen, long* plPos, long* plLen) { ASSERT_WRITE_PTR(plPos); ASSERT_WRITE_PTR(plLen);
long lPos = *plPos; long lLen = *plLen;
if (lPos < 0) lPos = lStrLen; else lPos = min(lPos, lStrLen);
if (lLen < 0) lLen = lStrLen - lPos; else lLen = min(lLen, lStrLen - lPos);
*plPos = lPos; *plLen = lLen;
return S_OK; }
#ifdef ASTRIMPL
HRESULT LocaleToCodePage(LCID locale, UINT* puCodePage) { HRESULT hr = S_OK;
if (puCodePage) { TCHAR szCodePage[8];
if (::GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, szCodePage, ARRAYSIZE(szCodePage)) > 0) *puCodePage = _ttoi(szCodePage); else hr = E_FAIL; // NLS failed
}
return hr; } #endif
/////////////////////////////////////////////////////////////////////////////
// CMLStr
CMLStr::CMLStr(void) : m_pMLStrBufW(NULL), m_pMLStrBufA(NULL), m_lBufFlags(0), m_cchBuf(0), m_locale(0), #ifdef ASTRIMPL
m_LockInfo(this) #else
m_lLockFlags(0) #endif
{ DllAddRef(); m_dwThreadID = ::GetCurrentThreadId(); }
CMLStr::~CMLStr(void) { if (m_pMLStrBufW) m_pMLStrBufW->Release(); if (m_pMLStrBufA) m_pMLStrBufA->Release(); DllRelease(); }
STDMETHODIMP CMLStr::Sync(BOOL) { ASSERT_THIS; return S_OK; // No multithread supported; Always synchronized
}
STDMETHODIMP CMLStr::GetLength(long* plLen) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(plLen);
HRESULT hr = CheckThread(); #ifdef ASTRIMPL
CLock Lock(FALSE, this, hr); #endif
long lLen;
if (SUCCEEDED(hr)) hr = GetLen(0, GetBufCCh(), &lLen);
if (plLen) { if (SUCCEEDED(hr)) *plLen = lLen; else *plLen = 0; }
return hr; }
STDMETHODIMP CMLStr::SetMLStr(long, long, IUnknown*, long, long) { return E_NOTIMPL; // IMLangString::SetMLStr()
}
STDMETHODIMP CMLStr::GetMLStr(long, long, IUnknown*, DWORD, const IID*, IUnknown**, long*, long*) { return E_NOTIMPL; // IMLangString::GetMLStr()
}
#ifndef ASTRIMPL
STDMETHODIMP CMLStr::SetWStr(long lDestPos, long lDestLen, const WCHAR* pszSrc, long cchSrc, long* pcchActual, long* plActualLen) { return E_NOTIMPL; // !ASTRIMPL
}
STDMETHODIMP CMLStr::SetStrBufW(long lDestPos, long lDestLen, IMLangStringBufW* pSrcBuf, long* pcchActual, long* plActualLen) { return SetStrBufCommon(NULL, lDestPos, lDestLen, 0, pSrcBuf, NULL, pcchActual, plActualLen); } #endif
HRESULT CMLStr::SetStrBufCommon(void* pMLStrX, long lDestPos, long lDestLen, UINT uCodePage, IMLangStringBufW* pSrcBufW, IMLangStringBufA* pSrcBufA, long* pcchActual, long* plActualLen) { ASSERT_THIS; ASSERT_READ_PTR_OR_NULL(pSrcBufW); ASSERT_READ_PTR_OR_NULL(pSrcBufA); ASSERT(!pSrcBufW || !pSrcBufA); // Either one or both should be NULL
ASSERT_WRITE_PTR_OR_NULL(pcchActual); ASSERT_WRITE_PTR_OR_NULL(plActualLen);
HRESULT hr = CheckThread(); #ifdef ASTRIMPL
CLock Lock(TRUE, this, hr); #endif
long lBufFlags = 0; // '= 0' for in case of both of pSrcBufW and pSrcBufA are NULL
long cchBuf = 0; long cchDestPos; long cchDestLen; long lActualLen = 0;
#ifndef ASTRIMPL
if (SUCCEEDED(hr) && IsLocked()) hr = E_INVALIDARG; // This MLStr is locked
#endif
if (SUCCEEDED(hr) && (!pSrcBufW || SUCCEEDED(hr = pSrcBufW->GetStatus(&lBufFlags, &cchBuf))) && (!pSrcBufA || SUCCEEDED(hr = pSrcBufA->GetStatus(&lBufFlags, &cchBuf))) && SUCCEEDED(hr = RegularizePosLen(&lDestPos, &lDestLen)) && SUCCEEDED(hr = GetCCh(0, lDestPos, &cchDestPos)) && SUCCEEDED(hr = GetCCh(cchDestPos, lDestLen, &cchDestLen))) { if (!cchDestPos && cchDestLen == GetBufCCh()) // Replacing entire string
{ IMLangStringBufW* const pOldBufW = GetMLStrBufW(); IMLangStringBufA* const pOldBufA = GetMLStrBufA();
if (pOldBufW) pOldBufW->Release(); else if (pOldBufA) pOldBufA->Release();
if (pSrcBufW) pSrcBufW->AddRef(); else if (pSrcBufA) pSrcBufA->AddRef();
SetMLStrBufW(pSrcBufW); SetMLStrBufA(pSrcBufA); SetCodePage(uCodePage); SetBufFlags(lBufFlags); SetBufCCh(cchBuf);
if (plActualLen) hr = GetLen(0, GetBufCCh(), &lActualLen); } else { #ifdef ASTRIMPL
if (pSrcBufW) { CMLStrBufWalkW BufWalk(pSrcBufW, 0, cchBuf, (pcchActual || plActualLen));
while (BufWalk.Lock(hr)) { long cchSet; long lSetLen;
hr = ((IMLangStringWStr*)pMLStrX)->SetWStr(lDestPos, lDestLen, BufWalk.GetStr(), BufWalk.GetCCh(), &cchSet, (plActualLen) ? &lSetLen : NULL); lActualLen += lSetLen; BufWalk.Unlock(hr, cchSet); }
cchBuf = BufWalk.GetDoneCCh();
pSrcBufW->Release(); } else if (pSrcBufA && pMLStrX) { CMLStrBufWalkA BufWalk(pSrcBufA, 0, cchBuf, (pcchActual || plActualLen));
while (BufWalk.Lock(hr)) { long cchSet; long lSetLen;
hr = ((IMLangStringAStr*)pMLStrX)->SetAStr(lDestPos, lDestLen, uCodePage, BufWalk.GetStr(), BufWalk.GetCCh(), &cchSet, (plActualLen) ? &lSetLen : NULL); lActualLen += lSetLen; BufWalk.Unlock(hr, cchSet); }
cchBuf = BufWalk.GetDoneCCh();
pSrcBufA->Release(); } else { hr = SetMLStr(lDestPos, lDestLen, NULL, 0, 0); } #else
hr = E_INVALIDARG; // !ASTRIMPL
#endif
} }
if (SUCCEEDED(hr)) { if (pcchActual) *pcchActual = cchBuf; if (plActualLen) *plActualLen = lActualLen; } else { if (pcchActual) *pcchActual = 0; if (plActualLen) *plActualLen = 0; }
return hr; }
#ifndef ASTRIMPL
STDMETHODIMP CMLStr::GetWStr(long lSrcPos, long lSrcLen, WCHAR* pszDest, long cchDest, long* pcchActual, long* plActualLen) { ASSERT_THIS; ASSERT_WRITE_BLOCK_OR_NULL(pszDest, cchDest); ASSERT_WRITE_PTR_OR_NULL(pcchActual); ASSERT_WRITE_PTR_OR_NULL(plActualLen);
HRESULT hr = CheckThread(); long cchSrcPos; long cchSrcLen; long cchActual; long lActualLen;
if (SUCCEEDED(hr) && IsLocked()) hr = E_INVALIDARG; // This MLStr is locked
if (SUCCEEDED(hr) && SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcLen)) && SUCCEEDED(hr = GetCCh(0, lSrcPos, &cchSrcPos)) && SUCCEEDED(hr = GetCCh(cchSrcPos, lSrcLen, &cchSrcLen))) { if (pszDest) { long cchActualTemp = min(cchSrcLen, cchDest); cchActual = cchActualTemp;
while (SUCCEEDED(hr) && cchActualTemp > 0) { WCHAR* pszBuf; long cchBuf;
if (m_pMLStrBufW) { if (SUCCEEDED(hr = m_pMLStrBufW->LockBuf(cchSrcPos, cchActualTemp, &pszBuf, &cchBuf))) { ::memcpy(pszDest, pszBuf, sizeof(WCHAR) * cchBuf); hr = m_pMLStrBufW->UnlockBuf(pszBuf, 0, 0);
cchSrcPos += cchBuf; cchActualTemp -= cchBuf; pszDest += cchBuf; } } else // m_pMLStrBufW
{ hr = E_FAIL; // !ASTRIMPL
} }
if (FAILED(hr) && cchActualTemp < cchActual && (pcchActual || plActualLen)) { cchActual -= cchActualTemp; hr = S_OK; } } else { cchActual = cchSrcLen; } }
if (SUCCEEDED(hr) && plActualLen) hr = CalcLenW(0, cchActual, &lActualLen);
if (SUCCEEDED(hr)) { if (pcchActual) *pcchActual = cchActual; if (plActualLen) *plActualLen = lActualLen; } else { if (pcchActual) *pcchActual = 0; if (plActualLen) *plActualLen = 0; } return hr; }
STDMETHODIMP CMLStr::GetStrBufW(long, long, IMLangStringBufW**, long*) { return E_NOTIMPL; // !ASTRIMPL
}
STDMETHODIMP CMLStr::LockWStr(long lSrcPos, long lSrcLen, long lFlags, long cchRequest, WCHAR** ppszDest, long* pcchDest, long* plDestLen) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(ppszDest); ASSERT_WRITE_PTR_OR_NULL(pcchDest); ASSERT_WRITE_PTR_OR_NULL(plDestLen);
HRESULT hr = CheckThread(); long cchSrcPos; long cchSrcLen; WCHAR* pszBuf = NULL; long cchBuf; long lLockLen;
if (SUCCEEDED(hr) && (IsLocked() || !lFlags || (lFlags & ~GetBufFlags() & MLSTR_WRITE))) hr = E_INVALIDARG; // This MLStr is locked, no flags specified or not writable
if (!(lFlags & MLSTR_WRITE)) cchRequest = 0;
if (SUCCEEDED(hr) && SUCCEEDED(hr = PrepareMLStrBuf()) && SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcLen)) && SUCCEEDED(hr = GetCCh(0, lSrcPos, &cchSrcPos)) && SUCCEEDED(hr = GetCCh(cchSrcPos, lSrcLen, &cchSrcLen))) { IMLangStringBufW* const pMLStrBufW = GetMLStrBufW(); SetDirectLockFlag(pMLStrBufW != 0);
if (IsDirectLock()) { long cchInserted; long cchLockLen = cchSrcLen;
if (cchRequest > cchSrcLen && SUCCEEDED(hr = pMLStrBufW->Insert(cchSrcPos + cchSrcLen, cchRequest - cchSrcLen, &cchInserted))) { SetBufCCh(GetBufCCh() + cchInserted); cchLockLen += cchInserted;
if (!pcchDest && cchLockLen < cchRequest) hr = E_OUTOFMEMORY; // Can't insert in StrBuf
}
if (SUCCEEDED(hr) && SUCCEEDED(hr = pMLStrBufW->LockBuf(cchSrcPos, cchLockLen, &pszBuf, &cchBuf)) && !pcchDest && cchBuf < max(cchSrcLen, cchRequest)) { hr = E_OUTOFMEMORY; // Can't lock StrBuf
}
} else if (m_pMLStrBufA) { long cchSize;
if (SUCCEEDED(hr = CalcBufSizeW(lSrcLen, &cchSize))) { cchBuf = max(cchSize, cchRequest); hr = MemAlloc(sizeof(*pszBuf) * cchBuf, (void**)&pszBuf); }
if (SUCCEEDED(hr) && (lFlags & MLSTR_READ)) hr = ConvertMLStrBufAToWStr(m_uCodePage, m_pMLStrBufA, cchSrcPos, cchSrcLen, pszBuf, cchBuf, (pcchDest) ? &cchBuf : NULL); } else { hr = E_FAIL; // !ASTRIMPL
} }
if (plDestLen && SUCCEEDED(hr)) hr = CalcLenW(pszBuf, cchBuf, &lLockLen);
if (SUCCEEDED(hr)) { SetLockFlags(lFlags); m_pszLockBuf = pszBuf; m_cchLockPos = cchSrcPos; m_cchLockLen = cchBuf; m_lLockPos = lSrcPos; m_lLockLen = lSrcLen;
if (ppszDest) *ppszDest = pszBuf; if (pcchDest) *pcchDest = cchBuf; if (plDestLen) *plDestLen = lLockLen; } else { if (pszBuf) { if (IsDirectLock()) GetMLStrBufW()->UnlockBuf(pszBuf, 0, 0); else MemFree(pszBuf); }
if (ppszDest) *ppszDest = NULL; if (pcchDest) *pcchDest = 0; if (plDestLen) *plDestLen = 0; }
return hr; } #endif
#ifdef ASTRIMPL
HRESULT CMLStr::UnlockWStrDirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen) { HRESULT hr; IMLangStringBufW* const pMLStrBufW = GetMLStrBufW(); const long cchLockLen = GetLockInfo()->GetCChLen(pKey);
if (SUCCEEDED(hr = pMLStrBufW->UnlockBuf((WCHAR*)pszSrc, 0, cchSrc)) && (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE)) { if (cchSrc < cchLockLen) { if (SUCCEEDED(hr = pMLStrBufW->Delete(GetLockInfo()->GetCChPos(pKey) + cchSrc, cchLockLen - cchSrc))) SetBufCCh(GetBufCCh() - (cchLockLen - cchSrc)); }
if (SUCCEEDED(hr) && plActualLen) hr = CalcLenW((WCHAR*)pszSrc, cchSrc, plActualLen);
if (pcchActual) *pcchActual = cchSrc; }
return hr; }
HRESULT CMLStr::UnlockWStrIndirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen) { HRESULT hr = S_OK;
if (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE) { CComQIPtr<IMLangStringWStr, &IID_IMLangStringWStr> pMLStrW(this); ASSERT(pMLStrW); hr = pMLStrW->SetWStr(GetLockInfo()->GetPos(pKey), GetLockInfo()->GetLen(pKey), (WCHAR*)pszSrc, cchSrc, pcchActual, plActualLen); }
ASSIGN_IF_FAILED(hr, MemFree((void*)pszSrc));
return hr; }
HRESULT CMLStr::UnlockAStrDirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen) { HRESULT hr; IMLangStringBufA* const pMLStrBufA = GetMLStrBufA(); const long cchLockLen = GetLockInfo()->GetCChLen(pKey);
if (SUCCEEDED(hr = pMLStrBufA->UnlockBuf((CHAR*)pszSrc, 0, cchSrc)) && (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE)) { if (cchSrc < cchLockLen) { if (SUCCEEDED(hr = pMLStrBufA->Delete(GetLockInfo()->GetCChPos(pKey) + cchSrc, cchLockLen - cchSrc))) SetBufCCh(GetBufCCh() - (cchLockLen - cchSrc)); }
if (SUCCEEDED(hr) && plActualLen) hr = CalcLenA(GetCodePage(), (CHAR*)pszSrc, cchSrc, plActualLen);
if (pcchActual) *pcchActual = cchSrc; }
return hr; }
HRESULT CMLStr::UnlockAStrIndirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen) { HRESULT hr = S_OK;
if (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE) { CComQIPtr<IMLangStringAStr, &IID_IMLangStringAStr> pMLStrA(this); ASSERT(pMLStrA); hr = pMLStrA->SetAStr(GetLockInfo()->GetPos(pKey), GetLockInfo()->GetLen(pKey), GetLockInfo()->GetCodePage(pKey), (CHAR*)pszSrc, cchSrc, pcchActual, plActualLen); }
ASSIGN_IF_FAILED(hr, MemFree((void*)pszSrc));
return hr; } #endif
#ifndef ASTRIMPL
STDMETHODIMP CMLStr::UnlockWStr(const WCHAR* pszSrc, long cchSrc, long* pcchActual, long* plActualLen) { ASSERT_THIS; ASSERT_READ_BLOCK(pszSrc, cchSrc); ASSERT_WRITE_PTR_OR_NULL(pcchActual); ASSERT_WRITE_PTR_OR_NULL(plActualLen);
HRESULT hr = CheckThread(); long lSrcLen = 0; const long lLockFlags = GetLockFlags();
if (SUCCEEDED(hr) && (!IsLocked() || pszSrc != m_pszLockBuf)) hr = E_INVALIDARG; // This MLStr is not locked
if (!(lLockFlags & MLSTR_WRITE)) { cchSrc = 0; lSrcLen = 0; }
if (SUCCEEDED(hr)) { IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
if (IsDirectLock()) { if (SUCCEEDED(hr = pMLStrBufW->UnlockBuf(pszSrc, 0, cchSrc)) && (lLockFlags & MLSTR_WRITE)) { if (cchSrc < m_cchLockLen) { if (SUCCEEDED(hr = pMLStrBufW->Delete(m_cchLockPos + cchSrc, m_cchLockLen - cchSrc))) SetBufCCh(GetBufCCh() - (m_cchLockLen - cchSrc)); }
if (SUCCEEDED(hr) && plActualLen) hr = CalcLenW(pszSrc, cchSrc, &lSrcLen); } } else { if (lLockFlags & MLSTR_WRITE) hr = SetWStr(m_lLockPos, m_lLockLen, pszSrc, cchSrc, (pcchActual) ? &cchSrc : NULL, (plActualLen) ? &lSrcLen : NULL);
HRESULT hrTemp = MemFree((void*)pszSrc); if (FAILED(hrTemp) && SUCCEEDED(hr)) hr = hrTemp; } }
if (SUCCEEDED(hr)) { if (pcchActual) *pcchActual = cchSrc; if (plActualLen) *plActualLen = lSrcLen; } else { if (pcchActual) *pcchActual = 0; if (plActualLen) *plActualLen = 0; }
SetLockFlags(0); // Unlock it anyway
return hr; } #endif
#ifdef ASTRIMPL
HRESULT CMLStr::UnlockStrCommon(const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen) { HRESULT hr = CheckThread(); void* pLockKey; long lSrcLen;
if (SUCCEEDED(hr)) hr = GetLockInfo()->Find(pszSrc, cchSrc, &pLockKey);
if (SUCCEEDED(hr)) hr = GetLockInfo()->Unlock(pLockKey, pszSrc, cchSrc, (pcchActual) ? &cchSrc : NULL, (plActualLen) ? &lSrcLen : NULL);
if (SUCCEEDED(hr)) { if (pcchActual) *pcchActual = cchSrc; if (plActualLen) *plActualLen = lSrcLen; } else { if (pcchActual) *pcchActual = 0; if (plActualLen) *plActualLen = 0; }
return hr; } #endif
STDMETHODIMP CMLStr::SetLocale(long lDestPos, long lDestLen, LCID locale) { ASSERT_THIS;
HRESULT hr = CheckThread(); #ifdef ASTRIMPL
CLock Lock(TRUE, this, hr); #endif
long cchDestPos; long cchDestLen;
if (SUCCEEDED(hr) && SUCCEEDED(hr = RegularizePosLen(&lDestPos, &lDestLen)) && SUCCEEDED(hr = GetCCh(0, lDestPos, &cchDestPos)) && SUCCEEDED(hr = GetCCh(cchDestPos, lDestLen, &cchDestLen))) { //if (!cchDestPos && cchDestLen == GetBufCCh())
SetLocale(locale); //else
// hr = E_NOTIMPL; // Cannot set the locale to a part of string in this version.
}
return hr; }
STDMETHODIMP CMLStr::GetLocale(long lSrcPos, long lSrcMaxLen, LCID* plocale, long* plLocalePos, long* plLocaleLen) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(plocale); ASSERT_WRITE_PTR_OR_NULL(plLocalePos); ASSERT_WRITE_PTR_OR_NULL(plLocaleLen);
HRESULT hr = CheckThread(); #ifdef ASTRIMPL
CLock Lock(FALSE, this, hr); #endif
long lStrLen;
if (SUCCEEDED(hr) && SUCCEEDED(hr = GetLen(0, GetBufCCh(), &lStrLen)) && SUCCEEDED(hr = ::RegularizePosLen(lStrLen, &lSrcPos, &lSrcMaxLen))) { if (plocale) *plocale = GetLocale(); if (plLocalePos) *plLocalePos = 0; if (plLocaleLen) { if (plLocalePos) *plLocaleLen = lStrLen; else *plLocaleLen = lSrcMaxLen; } } else { if (plocale) *plocale = 0; if (plLocalePos) *plLocalePos = 0; if (plLocaleLen) *plLocaleLen = 0; }
return hr; }
HRESULT CMLStr::PrepareMLStrBuf(void) { if (GetMLStrBufW() || GetMLStrBufA()) return S_OK; #ifdef ASTRIMPL
IMLangStringBufW* pBuf = new CMLStr::CMLStrBufStandardW; if (pBuf) { SetMLStrBufW(pBuf); return S_OK; } else { return E_OUTOFMEMORY; } #else
else return E_NOTIMPL; //!ASTRIMPL
#endif
}
HRESULT CMLStr::RegularizePosLen(long* plPos, long* plLen) { HRESULT hr; long lStrLen;
if (SUCCEEDED(hr = GetLen(0, GetBufCCh(), &lStrLen))) hr = ::RegularizePosLen(lStrLen, plPos, plLen);
return hr; }
HRESULT CMLStr::GetCCh(long cchOffset, long lLen, long* pcchLen) { if (GetMLStrBufW()) { if (pcchLen) *pcchLen = lLen; // The number of characters is equal to the length
return S_OK; } else if (GetMLStrBufA()) { HRESULT hr = S_OK; #ifdef ASTRIMPL
CMLStrBufWalkA BufWalk(GetMLStrBufA(), cchOffset, GetBufCCh() - cchOffset);
while (lLen > 0 && BufWalk.Lock(hr)) { for (LPCSTR pszTemp = BufWalk.GetStr(); lLen > 0 && *pszTemp; lLen--) pszTemp = ::CharNextExA((WORD)GetCodePage(), pszTemp, 0);
if (!*pszTemp) lLen = 0; // String terminated
BufWalk.Unlock(hr); } #else
long cchDone = 0; long cchRest = GetBufCCh() - cchOffset;
while (SUCCEEDED(hr) && lLen > 0) { CHAR* pszBuf; long cchBuf;
if (SUCCEEDED(hr = m_pMLStrBufA->LockBuf(cchOffset, cchRest, &pszBuf, &cchBuf))) { for (LPCSTR pszTemp = pszBuf; lLen > 0 && *pszTemp; lLen--) pszTemp = ::CharNextExA((WORD)m_uCodePage, pszTemp, 0);
if (!*pszBuf) lLen = 0; // String terminated
hr = m_pMLStrBufA->UnlockBuf(pszBuf, 0, 0);
cchOffset += cchBuf; cchRest -= cchBuf; cchDone += (int)(pszTemp - pszBuf); } } #endif
if (pcchLen) { if (SUCCEEDED(hr)) #ifdef ASTRIMPL
*pcchLen = BufWalk.GetDoneCCh(); #else
*pcchLen = cchDone; #endif
else *pcchLen = 0; }
return hr; } else { if (pcchLen) *pcchLen = 0; // No string
return S_OK; } }
HRESULT CMLStr::GetLen(long cchOffset, long cchLen, long* plLen) { if (GetMLStrBufW()) { if (plLen) *plLen = cchLen; // The length is equal to the number of characters
return S_OK; } else if (GetMLStrBufA()) { HRESULT hr = S_OK; long lDoneLen = 0; #ifdef ASTRIMPL
CMLStrBufWalkA BufWalk(GetMLStrBufA(), cchOffset, cchLen);
while (BufWalk.Lock(hr)) { long lTempLen;
hr = CalcLenA(GetCodePage(), BufWalk.GetStr(), BufWalk.GetCCh(), &lTempLen); if (hr == S_FALSE) cchLen = 0; // String terminated
lDoneLen += lTempLen;
BufWalk.Unlock(hr); } #else
while (SUCCEEDED(hr) && cchLen > 0) { CHAR* pszBuf; long cchBuf;
if (SUCCEEDED(hr = m_pMLStrBufA->LockBuf(cchOffset, cchLen, &pszBuf, &cchBuf))) { long lTempLen;
hr = CalcLenA(GetCodePage(), pszBuf, cchBuf, &lTempLen); if (hr == S_FALSE) cchLen = 0; // String terminated
lDoneLen += lTempLen;
hr = m_pMLStrBufA->UnlockBuf(pszBuf, 0, 0);
cchOffset += cchBuf; cchLen -= cchBuf; } } #endif
if (plLen) { if (SUCCEEDED(hr)) *plLen = lDoneLen; else *plLen = 0; }
return hr; } else { if (plLen) *plLen = 0; // No string
return S_OK; } }
HRESULT CMLStr::CalcLenA(UINT uCodePage, const CHAR* psz, long cchLen, long* plLen) { long lLen = 0; const CHAR* const pszEnd = psz + cchLen;
for (; psz < pszEnd && *psz; lLen++) { const CHAR* const pszNew = ::CharNextExA((WORD)uCodePage, psz, 0);
if (pszNew > pszEnd) // Overrun out of buffer
break;
psz = pszNew; }
if (plLen) *plLen = lLen;
if (*psz) return S_OK; else return S_FALSE; }
#ifdef ASTRIMPL
HRESULT CMLStr::CalcCChA(UINT uCodePage, const CHAR* psz, long lLen, long* pcchLen) { const CHAR* const pszStart = psz;
for (; lLen > 0 && *psz; lLen--) psz = ::CharNextExA((WORD)uCodePage, psz, 0);
if (pcchLen) *pcchLen = psz - pszStart;
if (*psz) return S_OK; else return S_FALSE; }
HRESULT CMLStr::ConvAStrToWStr(UINT uCodePage, const CHAR* pszSrc, long cchSrc, WCHAR* pszDest, long cchDest, long* pcchActualA, long* pcchActualW, long* plActualLen) { HRESULT hr = S_OK; long lWrittenLen; long cchWrittenA;
long cchWrittenW = ::MultiByteToWideChar(uCodePage, 0, pszSrc, cchSrc, pszDest, (pszDest) ? cchDest : 0); if (!cchWrittenW) hr = E_FAIL; // NLS failed
if ((pcchActualA || plActualLen) && SUCCEEDED(hr)) hr = CalcLenW(pszDest, cchWrittenW, &lWrittenLen); // BOGUS: pszDest may be NULL
if (pcchActualA && SUCCEEDED(hr)) hr = CalcCChA(uCodePage, pszSrc, lWrittenLen, &cchWrittenA);
if (SUCCEEDED(hr)) { if (pcchActualA) *pcchActualA = cchWrittenA; if (pcchActualW) *pcchActualW = cchWrittenW; if (plActualLen) *plActualLen = lWrittenLen; } else { if (pcchActualA) *pcchActualA = 0; if (pcchActualW) *pcchActualW = 0; if (plActualLen) *plActualLen = 0; }
return hr; }
HRESULT CMLStr::ConvWStrToAStr(BOOL fCanStopAtMiddle, UINT uCodePage, const WCHAR* pszSrc, long cchSrc, CHAR* pszDest, long cchDest, long* pcchActualA, long* pcchActualW, long* plActualLen) { HRESULT hr = S_OK; long lWrittenLen; long cchWrittenW;
long cchWrittenA = ::WideCharToMultiByte(uCodePage, (fCanStopAtMiddle) ? 0 : WC_DEFAULTCHAR, pszSrc, cchSrc, pszDest, (pszDest) ? cchDest : 0, NULL, NULL); if (!cchWrittenA) hr = E_FAIL; // NLS failed
if ((pcchActualW || plActualLen) && SUCCEEDED(hr)) { if (pszDest) hr = CalcLenA(uCodePage, pszDest, cchWrittenA, &lWrittenLen); else hr = E_NOTIMPL; // Can't retrieve pcchActualW and plActualLen
}
if (pcchActualW && SUCCEEDED(hr)) hr = CalcCChW(pszSrc, lWrittenLen, &cchWrittenW);
if (SUCCEEDED(hr)) { if (pcchActualA) *pcchActualA = cchWrittenA; if (pcchActualW) *pcchActualW = cchWrittenW; if (plActualLen) *plActualLen = lWrittenLen; } else { if (pcchActualA) *pcchActualA = 0; if (pcchActualW) *pcchActualW = 0; if (plActualLen) *plActualLen = 0; }
return hr; } #endif
#ifndef ASTRIMPL
HRESULT CMLStr::ConvertMLStrBufAToWStr(UINT uCodePage, IMLangStringBufA* pMLStrBufA, long cchSrcPos, long cchSrcLen, WCHAR* pszBuf, long cchBuf, long* pcchActual) { HRESULT hr = S_OK; long cchDone = 0;
while (SUCCEEDED(hr) && cchSrcLen > 0) { CHAR* pszBufA; long cchBufA;
if (SUCCEEDED(hr = pMLStrBufA->LockBuf(cchSrcPos, cchSrcLen, &pszBufA, &cchBufA))) { long cchWritten = ::MultiByteToWideChar(uCodePage, 0, pszBufA, cchBufA, pszBuf, cchBuf); if (!cchWritten) hr = E_FAIL; // NLS failed
HRESULT hrTemp = pMLStrBufA->UnlockBuf(pszBufA, 0, 0); if (FAILED(hrTemp) && SUCCEEDED(hr)) hr = hrTemp;
cchSrcPos += cchBufA; cchSrcLen -= cchBufA; pszBuf += cchWritten; cchBuf -= cchWritten; cchDone += cchWritten; ASSERT(cchBuf >= 0); } }
if (pcchActual) { *pcchActual = cchDone;
if (FAILED(hr) && cchDone > 0) hr = S_OK; }
return hr; }
HRESULT CMLStr::ConvertWStrToMLStrBufA(const WCHAR*, long, UINT, IMLangStringBufA*, long, long) { return E_NOTIMPL; // !ASTRIMPL
} #endif
#ifdef ASTRIMPL
/////////////////////////////////////////////////////////////////////////////
// CMLStr::CLockInfo
HRESULT CMLStr::CLockInfo::UnlockAll(void) { if (m_pLockArray) { for (int n = 0; n < MAX_LOCK_COUNT; n++) { if (m_pLockArray[n].m_psz) Unlock(&m_pLockArray[n], m_pLockArray[n].m_psz, m_pLockArray[n].m_cchLen, NULL, NULL); } }
return S_OK; }
HRESULT CMLStr::CLockInfo::Lock(PFNUNLOCKPROC pfnUnlockProc, long lFlags, UINT uCodePage, void* psz, long lPos, long lLen, long cchPos, long cchLen) { HRESULT hr = S_OK; int nIndex;
if (!m_pLockArray) { m_pLockArray = new CLockInfoEntry[MAX_LOCK_COUNT];
if (m_pLockArray) { for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++) m_pLockArray[nIndex].m_psz = NULL; } else { hr = E_OUTOFMEMORY; } }
if (SUCCEEDED(hr)) { for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++) { if (!m_pLockArray[nIndex].m_psz) break; } if (nIndex >= MAX_LOCK_COUNT) hr = MLSTR_E_TOOMANYNESTOFLOCK; }
if (SUCCEEDED(hr)) { m_pLockArray[nIndex].m_psz = psz; m_pLockArray[nIndex].m_pfnUnlockProc = pfnUnlockProc; m_pLockArray[nIndex].m_lFlags = lFlags; m_pLockArray[nIndex].m_uCodePage = uCodePage; m_pLockArray[nIndex].m_lPos = lPos; m_pLockArray[nIndex].m_lLen = lLen; m_pLockArray[nIndex].m_cchPos = cchPos; m_pLockArray[nIndex].m_cchLen = cchLen; }
return hr; }
HRESULT CMLStr::CLockInfo::Find(const void* psz, long, void** ppKey) { HRESULT hr = S_OK; int nIndex;
if (m_pLockArray) { for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++) { if (psz == m_pLockArray[nIndex].m_psz) break; } } if (!m_pLockArray || nIndex >= MAX_LOCK_COUNT) hr = E_INVALIDARG;
if (ppKey) { if (SUCCEEDED(hr)) *ppKey = &m_pLockArray[nIndex]; else *ppKey = NULL; }
return hr; }
HRESULT CMLStr::CLockInfo::Unlock(void* pKey, const void* psz, long cch, long* pcchActual, long* plActualLen) { CLockInfoEntry* const pEntry = (CLockInfoEntry*)pKey; HRESULT hr;
if (!(pEntry->m_lFlags & MLSTR_WRITE)) { cch = 0; if (plActualLen) *plActualLen = 0; }
hr = (m_pMLStr->*(pEntry->m_pfnUnlockProc))(pKey, psz, cch, pcchActual, plActualLen);
if (SUCCEEDED(hr)) hr = EndLock(pEntry->m_lFlags & MLSTR_WRITE);
pEntry->m_psz = NULL; // Remove from lock array anyway
if (FAILED(hr)) { if (pcchActual) *pcchActual = 0; if (plActualLen) *plActualLen = 0; }
return hr; }
/////////////////////////////////////////////////////////////////////////////
// CMLStr::CMLStrBufStandardW
long CMLStr::CMLStrBufStandardW::RoundBufSize(long cchStr) { for (int n = 8; n < 12; n++) { if (cchStr < (1L << n)) break; } const long cchTick = (1L << (n - 4)); return (cchStr + cchTick - 1) / cchTick * cchTick; }
#endif
#else // NEWMLSTR
#include "mlstr.h"
/////////////////////////////////////////////////////////////////////////////
// CMLStr
CMLStr::CMLStr(void) : m_lLen(0), m_hUnlockEvent(NULL), m_hZeroEvent(NULL) { DllAddRef(); }
CMLStr::~CMLStr(void) { void* pv;
if (m_hZeroEvent) ::CloseHandle(m_hZeroEvent); if (m_hUnlockEvent) ::CloseHandle(m_hUnlockEvent);
// m_lock should be empty
ASSERT(SUCCEEDED(m_lock.Top(&pv))); ASSERT(!pv);
// Release all attributes in m_attr
VERIFY(SUCCEEDED(m_attr.Top(&pv))); while (pv) { IMLStrAttr* const pAttr = m_attr.GetAttr(pv); ASSERT(pAttr); VERIFY(SUCCEEDED(pAttr->SetClient(NULL))); // Reset
VERIFY(SUCCEEDED(StartEndConnectionAttr(pAttr, NULL, m_attr.GetCookie(pv)))); // Disconnect
pAttr->Release(); VERIFY(SUCCEEDED(m_attr.Next(pv, &pv))); } DllRelease(); }
STDMETHODIMP CMLStr::LockMLStr(long lPos, long lLen, DWORD dwFlags, DWORD* pdwCookie, long* plActualPos, long* plActualLen) { ASSERT_WRITE_PTR_OR_NULL(pdwCookie); ASSERT_WRITE_PTR_OR_NULL(plActualPos); ASSERT_WRITE_PTR_OR_NULL(plActualLen);
HRESULT hr; void* pv;
Lock();
if (SUCCEEDED(hr = ::RegularizePosLen(m_lLen, &lPos, &lLen))) { const DWORD dwThrd = ::GetCurrentThreadId();
if (SUCCEEDED(hr = CheckAccessValidation(lPos, lLen, dwFlags, dwThrd, plActualPos, plActualLen)) && SUCCEEDED(hr = m_lock.Add(&pv))) { if (plActualPos && !plActualLen) lLen -= *plActualPos - lPos; else if (plActualLen) lLen = *plActualLen; if (plActualPos) lPos = *plActualPos;
hr = m_lock.SetLock(pv, lPos, lLen, dwFlags, dwThrd);
if (FAILED(hr)) VERIFY(SUCCEEDED(m_lock.Remove(pv))); } } else { if (plActualPos) *plActualPos = 0; if (plActualLen) *plActualLen = 0; }
Unlock();
if (pdwCookie) { if (SUCCEEDED(hr)) *pdwCookie = (DWORD)pv; else *pdwCookie = 0; }
return hr; }
HRESULT CMLStr::CheckAccessValidation(long lPos, long lLen, DWORD dwFlags, DWORD dwThrd, long* plActualPos, long* plActualLen) { HRESULT hr; DWORD dwStartTime = 0; long lActualPos; long lActualLen;
for (;;) // Waiting unlock loop
{ void* pv; HRESULT hrValidation = S_OK;
lActualPos = lPos; lActualLen = lLen;
hr = m_lock.Top(&pv); while (SUCCEEDED(hr) && pv) // Enumerate all locks
{ LOCKINFO* plinfo;
if (SUCCEEDED(hr = m_lock.GetLockInfo(pv, &plinfo))) // Retrieve info of a lock
{ if ((dwFlags & MLSTR_MOVE) && // Moving this lock
lPos < plinfo->lPos + plinfo->lLen && // Overwrap or left of this lock
(dwThrd != plinfo->dwThrd || // Another thread
(plinfo->dwFlags & (MLSTR_READ | MLSTR_WRITE)))) // Same thread and has read or write access
{ if (dwThrd == plinfo->dwThrd) hr = MLSTR_E_ACCESSDENIED; else hr = MLSTR_E_BUSY; }
if (SUCCEEDED(hr) && lActualPos < plinfo->lPos + plinfo->lLen && lActualPos + lActualLen >= plinfo->lPos) // Overwraping with this lock
{ DWORD dwShareMask = 0; if (dwThrd == plinfo->dwThrd) // Same thread
dwShareMask = ~(MLSTR_SHARE_DENYREAD | MLSTR_SHARE_DENYWRITE); // Ignore share flags
if (((dwFlags & MLSTR_WRITE) && (plinfo->dwFlags & (MLSTR_READ | MLSTR_WRITE | MLSTR_SHARE_DENYWRITE) & dwShareMask)) || // Write on read/write
((dwFlags & MLSTR_READ) && (plinfo->dwFlags & ( MLSTR_WRITE | MLSTR_SHARE_DENYREAD ) & dwShareMask)) || // Read on write
((dwFlags & MLSTR_SHARE_DENYWRITE & dwShareMask) && (plinfo->dwFlags & MLSTR_WRITE)) || // Share deny on write
((dwFlags & MLSTR_SHARE_DENYREAD & dwShareMask) && (plinfo->dwFlags & MLSTR_READ))) // Share deny on read
{ // Conflicting access
if ((plinfo->lPos <= lActualPos && plinfo->lPos + plinfo->lLen >= lActualPos + lActualLen) || // No valid range left
(!plActualPos && !plActualLen)) // Needs to lock entire range
{ lActualPos = 0; lActualLen = 0; if (dwThrd == plinfo->dwThrd) hr = MLSTR_E_ACCESSDENIED; else hr = MLSTR_E_BUSY; } else if ((!plActualPos && plinfo->lPos <= lActualPos) || // Forward processing, Starting from invalid range
(!plActualLen && plinfo->lPos + plinfo->lLen < lActualPos + lActualLen) || // Backward processing, Trancate valid range
(plActualPos && plActualLen && plinfo->lPos - lActualPos >= (lActualPos + lActualLen) - (plinfo->lPos + plinfo->lLen))) // Maximum valid range, Right valid range is bigger
{ lActualLen += lActualPos; lActualPos = plinfo->lPos + plinfo->lLen; lActualLen -= lActualPos; if (!plActualPos) // Forward processing
{ if (dwThrd == plinfo->dwThrd) hrValidation = MLSTR_E_ACCESSDENIED; else hrValidation = MLSTR_E_BUSY; } } else { lActualLen = plinfo->lPos - lActualPos; if (!plActualLen) // Backward processing
{ if (dwThrd == plinfo->dwThrd) hrValidation = MLSTR_E_ACCESSDENIED; else hrValidation = MLSTR_E_BUSY; } } } } }
if (SUCCEEDED(hr)) hr = m_lock.Next(pv, &pv); }
if (SUCCEEDED(hr) && FAILED(hrValidation)) { hr = hrValidation; if (plActualLen && lPos < lActualPos) // Forward processing
{ lActualLen = lActualPos - lPos; lActualPos = lPos; } else if (plActualPos && lPos + lLen != lActualPos + lActualLen) // Backward processing
{ lActualPos += lActualLen; lActualLen = lPos + lLen - lActualPos; } }
if (hr != MLSTR_E_BUSY || (dwFlags | MLSTR_NOWAIT)) // No busy state, or don't want to wait even if busy
break;
// Now, let's wait another thread run UnlockMLStr. Then, try validation again.
if (!dwStartTime) // Not initialized yet
dwStartTime = ::GetTickCount(); // Remember starting time
const DWORD dwElapsedTime = ::GetTickCount() - dwStartTime; if (dwElapsedTime >= MLSTR_LOCK_TIMELIMIT) // Already elapsed long time
break;
if (!m_hUnlockEvent) // We don't have event object yet
{ m_hUnlockEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); // Manual reset, initial reset
if (!m_hUnlockEvent) break;
m_cWaitUnlock = -1; // Initialize
} else // After second time
{ ASSERT(m_cWaitUnlock == 0 || m_cWaitUnlock == -1 || m_cWaitUnlock >= 1); if (m_cWaitUnlock == 0) // Don't reset if m_cWaitUnlock is not zero
{ ::ResetEvent(m_hUnlockEvent); m_cWaitUnlock = -1; } else { if (!m_hZeroEvent) { m_hZeroEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial reset
if (!m_hZeroEvent) break; } if (m_cWaitUnlock == -1) m_cWaitUnlock = 2; else m_cWaitUnlock++; } } ASSERT(m_cWaitUnlock == -1 || m_cWaitUnlock >= 2);
// CAUTION: Don't leave here until we make sure m_cWaitUnlock gets zero.
Unlock();
// === The story of m_cWaitUnlock ===
// If we don't have m_cWaitUnlock, the following scenario can be considered.
// (1) Thread A: ResetEvent(m_hUnlockEvent)
// (2) Thread A: Unlock()
// (3) Thread B: SetEvent(m_hUnlockEvent) // UnlockMLStr!!!
// (4) Thread C: Lock()
// (5) Thread C: ResetEvent(m_hUnlockEvent) // Problem!!!
// (6) Thread C: Unlock()
// (7) Thread A: WaitForSingleObject(m_hUnlockEvent)
// In this scenario, thread A is missing a event of (3). This situation should not happen.
// m_cWaitUnlock solves the problem.
const DWORD dwWaitResult = ::WaitForSingleObject(m_hUnlockEvent, MLSTR_LOCK_TIMELIMIT - dwElapsedTime); // Now wait unlock
Lock();
ASSERT(m_cWaitUnlock == -1 || m_cWaitUnlock >= 1); if (m_cWaitUnlock == -1) { m_cWaitUnlock = 0; } else // m_cWaitUnlock >= 1
{ m_cWaitUnlock--;
// Here, let's wait until m_cWaitUnlock gets zero.
// Unless this, it may not good for performance.
// In worst case, it makes thousands of loops in this function because it never reset m_hUnlockEvent.
// m_hUnlockEvent will be signaled even though UnlockMLStr is called yet.
if (m_cWaitUnlock > 0) { Unlock(); ::WaitForSingleObject(m_hZeroEvent, INFINITE); // Wait until m_cWaitUnlock gets zero, auto-reset
Lock(); } else // Now it's zero! Yeah!
{ ::SetEvent(m_hZeroEvent); // Release other threads
} } // ASSERT(m_cWaitUnlock == 0); This is not true. Maybe non-zero for next time.
// Now we may leave here.
if (dwWaitResult != WAIT_OBJECT_0) // Time expired or an error occurred
break; }
if (plActualPos) *plActualPos = lActualPos; if (plActualLen) *plActualLen = lActualLen;
return hr; }
STDMETHODIMP CMLStr::UnlockMLStr(DWORD dwCookie) { Lock();
void* const pv = (void*)dwCookie;
const HRESULT hr = m_lock.Remove(pv);
if (m_hUnlockEvent) ::SetEvent(m_hUnlockEvent);
Unlock();
return hr; }
STDMETHODIMP CMLStr::GetLength(long* plLen) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(plLen);
if (plLen) *plLen = m_lLen;
return S_OK; }
STDMETHODIMP CMLStr::SetMLStr(long, long, IUnknown*, long, long) { return E_NOTIMPL; // IMLangString::SetMLStr()
}
STDMETHODIMP CMLStr::RegisterAttr(IUnknown* pUnk, DWORD* pdwCookie) { ASSERT_THIS; ASSERT_READ_PTR(pUnk); ASSERT_WRITE_PTR_OR_NULL(pdwCookie);
HRESULT hr; void* pv; IMLStrAttr* pAttr = NULL; BOOL fConnStarted = FALSE; DWORD dwConnCookie;
Lock();
if (SUCCEEDED(hr = m_attr.Add(&pv)) && SUCCEEDED(hr = pUnk->QueryInterface(IID_IMLStrAttr, (void**)&pAttr))) { ASSERT_READ_PTR(pAttr); }
if (SUCCEEDED(hr) && SUCCEEDED(hr = StartEndConnectionAttr(pAttr, &dwConnCookie, 0))) // Connect
{ fConnStarted = TRUE; if (SUCCEEDED(hr = pAttr->SetClient((IMLangString*)this))) { CFire fire(hr, this); while (fire.Next()) hr = fire.Sink()->OnRegisterAttr(pAttr); } }
if (SUCCEEDED(hr) && SUCCEEDED(hr = pAttr->SetMLStr(0, -1, (IMLangString*)this, 0, m_lLen))) { m_attr.SetAttr(pv, pAttr); m_attr.SetCookie(pv, dwConnCookie);
if (pdwCookie) *pdwCookie = (DWORD)pv; } else { if (pAttr) { pAttr->SetClient(NULL); if (fConnStarted) VERIFY(SUCCEEDED(StartEndConnectionAttr(pAttr, NULL, dwConnCookie))); // Disconnect
pAttr->Release(); }
if (pv) m_attr.Remove(pv);
if (pdwCookie) *pdwCookie = NULL; }
Unlock();
return hr; }
STDMETHODIMP CMLStr::UnregisterAttr(DWORD dwCookie) { ASSERT_THIS;
void* const pv = (void*)dwCookie;
Lock();
IMLStrAttr* const pAttr = m_attr.GetAttr(pv); ASSERT(pAttr);
// Fire OnUnregisterAttr
HRESULT hr; CFire fire(hr, this); while (fire.Next()) hr = fire.Sink()->OnUnregisterAttr(pAttr);
// Release attribute
if (SUCCEEDED(hr) && SUCCEEDED(hr = pAttr->SetClient(NULL))) // Reset
{ VERIFY(SUCCEEDED(hr = StartEndConnectionAttr(pAttr, NULL, m_attr.GetCookie(pv)))); // Disconnect
pAttr->Release();
// Remove entry from attr table
m_attr.Remove(pv); }
Unlock();
return hr; }
STDMETHODIMP CMLStr::EnumAttr(IEnumUnknown** ppEnumUnk) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(ppEnumUnk);
if (!ppEnumUnk) return S_OK;
CEnumAttr* const pEnum = new CComObject<CEnumAttr>;
*ppEnumUnk = pEnum;
if (pEnum) { pEnum->Init(this); return S_OK; } else { return E_OUTOFMEMORY; } }
STDMETHODIMP CMLStr::FindAttr(REFIID riid, LPARAM lParam, IUnknown** ppUnk) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(ppUnk);
HRESULT hr; void* pv; IUnknown* pMaxUnk = NULL; long lMaxConf = 0;
Lock();
for (hr = m_attr.Top(&pv); SUCCEEDED(hr) && pv; hr = m_attr.Next(pv, &pv)) { IMLStrAttr* const pIMLStrAttr = m_attr.GetAttr(pv); IUnknown* pUnk; long lConf;
hr = pIMLStrAttr->QueryAttr(riid, lParam, &pUnk, &lConf); if (SUCCEEDED(hr)) { if (lConf > lMaxConf) { lMaxConf = lConf; if (pMaxUnk) pMaxUnk->Release(); pMaxUnk = pUnk; } else { if (pUnk) pUnk->Release(); }
if (lMaxConf == MLSTR_CONF_MAX) break; } }
if (SUCCEEDED(hr)) { if (ppUnk) *ppUnk = pMaxUnk; else if (pMaxUnk) pMaxUnk->Release(); } else { if (pMaxUnk) pMaxUnk->Release(); if (ppUnk) *ppUnk = NULL; }
Unlock();
return hr; }
STDMETHODIMP CMLStr::OnRequestEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk) { HRESULT hr; CFire fire(hr, this); while (fire.Next()) hr = fire.Sink()->OnRequestEdit(lDestPos, lDestLen, lNewLen, riid, lParam, pUnk); return hr; }
STDMETHODIMP CMLStr::OnCanceledEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk) { HRESULT hr; CFire fire(hr, this); while (fire.Next()) hr = fire.Sink()->OnCanceledEdit(lDestPos, lDestLen, lNewLen, riid, lParam, pUnk); return hr; }
STDMETHODIMP CMLStr::OnChanged(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk) { HRESULT hr; CFire fire(hr, this); while (fire.Next()) hr = fire.Sink()->OnChanged(lDestPos, lDestLen, lNewLen, riid, lParam, pUnk); return hr; }
/////////////////////////////////////////////////////////////////////////////
// CMLStr::CEnumAttr
CMLStr::CEnumAttr::CEnumAttr(void) : m_pMLStr(NULL), m_pv(NULL) { }
CMLStr::CEnumAttr::~CEnumAttr(void) { if (m_pMLStr) m_pMLStr->Unlock(); }
void CMLStr::CEnumAttr::Init(CMLStr* pMLStr) { ASSERT_THIS; ASSERT_READ_PTR(pMLStr);
if (m_pMLStr) m_pMLStr->Unlock();
m_pMLStr = pMLStr; m_pMLStr->Lock();
VERIFY(SUCCEEDED(Reset())); }
HRESULT CMLStr::CEnumAttr::Next(ULONG celt, IUnknown** rgelt, ULONG* pceltFetched) { ASSERT_THIS; ASSERT_WRITE_BLOCK_OR_NULL(rgelt, celt); ASSERT_WRITE_PTR_OR_NULL(pceltFetched);
ULONG c = 0;
if (rgelt && m_pMLStr) { for (; m_pv && c < celt; c++) { *rgelt = m_pMLStr->m_attr.GetAttr(m_pv); ASSERT(*rgelt); (*rgelt)->AddRef();
VERIFY(SUCCEEDED(m_pMLStr->m_attr.Next(m_pv, &m_pv))); rgelt++; } }
if (pceltFetched) *pceltFetched = c;
return S_OK; }
HRESULT CMLStr::CEnumAttr::Skip(ULONG celt) { ASSERT_THIS;
for (ULONG c = 0; m_pv && c < celt; c++) VERIFY(SUCCEEDED(m_pMLStr->m_attr.Next(m_pv, &m_pv)));
return S_OK; }
HRESULT CMLStr::CEnumAttr::Reset(void) { ASSERT_THIS; ASSERT_READ_PTR(m_pMLStr);
VERIFY(SUCCEEDED(m_pMLStr->m_attr.Top(&m_pv))); return S_OK; }
HRESULT CMLStr::CEnumAttr::Clone(IEnumUnknown** ppEnum) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(ppEnum); ASSERT_READ_PTR(m_pMLStr);
return m_pMLStr->EnumAttr(ppEnum); }
#endif // NEWMLSTR
|