Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1818 lines
48 KiB

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