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.

804 lines
23 KiB

  1. /*************************************************************************
  2. * @doc SHROOM EXTERNAL API *
  3. * *
  4. * SYSSRT.CPP *
  5. * *
  6. * Copyright (C) Microsoft Corporation 1997 *
  7. * All Rights reserved. *
  8. * *
  9. * This file contains the implementation of CITSysSort methods. *
  10. * CITSysSort is a pluggable sort object that uses the system's *
  11. * CompareString function to do comparisons. CITSysSort supports *
  12. * NULL terminated strings that are either Unicode or ANSI. *
  13. * *
  14. **************************************************************************
  15. * *
  16. * Written By : Bill Aloof *
  17. * Current Owner: billa *
  18. * *
  19. **************************************************************************/
  20. #include <mvopsys.h>
  21. #ifdef _DEBUG
  22. static char s_aszModule[] = __FILE__; /* For error report */
  23. #endif
  24. #include <atlinc.h> // includes for ATL.
  25. #include <_mvutil.h>
  26. #include <mem.h>
  27. #include <orkin.h>
  28. #include <iterror.h>
  29. #include <itsort.h>
  30. #include <itsortid.h>
  31. #include "syssrt.h"
  32. //---------------------------------------------------------------------------
  33. // Constructor and Destructor
  34. //---------------------------------------------------------------------------
  35. CITSysSort::CITSysSort()
  36. {
  37. OSVERSIONINFO osvi;
  38. m_fInitialized = m_fDirty = FALSE;
  39. MEMSET(&m_srtctl, NULL, sizeof(SRTCTL));
  40. m_hmemAnsi1 = m_hmemAnsi2 = NULL;
  41. m_cbBufAnsi1Cur = m_cbBufAnsi2Cur = 0;
  42. // See if we're running on NT; if GetVersionEx fails, we'll assume
  43. // we're not since that's causes us do take the more conservative route
  44. // when doing comparisons.
  45. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  46. m_fWinNT = (GetVersionEx(&osvi) ?
  47. (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) : FALSE);
  48. }
  49. CITSysSort::~CITSysSort()
  50. {
  51. Close();
  52. }
  53. //---------------------------------------------------------------------------
  54. // IITSortKey Method Implementations
  55. //---------------------------------------------------------------------------
  56. /********************************************************************
  57. * @method STDMETHODIMP | IITSortKey | GetSize |
  58. * Determines the size of a key.
  59. * @parm LPCVOID* | lpcvKey | Pointer to key
  60. * @parm DWORD* | pcbSize | Out param containing key size.
  61. *
  62. * @rvalue E_POINTER | lpcvKey or pcbSize was NULL
  63. *
  64. ********************************************************************/
  65. STDMETHODIMP
  66. CITSysSort::GetSize(LPCVOID lpcvKey, DWORD *pcbSize)
  67. {
  68. if (lpcvKey == NULL || pcbSize == NULL)
  69. return (SetErrReturn(E_POINTER));
  70. if (!m_fInitialized)
  71. return (SetErrReturn(E_NOTOPEN));
  72. if (m_srtctl.dwKeyType == IITSK_KEYTYPE_UNICODE_SZ)
  73. *pcbSize = (DWORD) (sizeof(WCHAR) * (WSTRLEN((WCHAR *)lpcvKey) + 1));
  74. else
  75. *pcbSize = (DWORD) (STRLEN((char *)lpcvKey) + 1);
  76. return (S_OK);
  77. }
  78. /********************************************************************
  79. * @method STDMETHODIMP | IITSortKey | Compare |
  80. * Compares two keys and returns information about their sort order.
  81. *
  82. * @parm LPCVOID | lpcvKey1 | Pointer to a key.
  83. * @parm LPCVOID | lpcvKey2 | Pointer to a key.
  84. * @parm LONG | *plResult | (out) Indicates whether lpcvKey1 is less than, equal to, or
  85. * greater than lpcvKey2.
  86. * @parm DWORD | *pgrfReason | (out) Provides additional information about
  87. * the comparison (see comments below).
  88. *
  89. * @rvalue E_POINTER | Either lpcvKey1, lpcvKey2, or *plResult was NULL
  90. *
  91. * @comm
  92. * On exit, *plResult is set according to strcmp conventions:
  93. * <lt> 0, = 0, <gt> 0, depending on whether lpcvKey1 is less than, equal to, or
  94. * greater than lpcvKey2. If pgrfReason is not NULL, *pgrfReason may be
  95. * filled in on exit with one or more bit flags giving more information about
  96. * the result of the comparison, if the result was affected by something other
  97. * than raw lexical comparison (such as special character mappings). If
  98. * *pgrfReason contains 0 on exit, that means the comparison result
  99. * was purely lexical; if *pgrfReason contains IITSK_COMPREASON_UNKNOWN,
  100. * then the sort object implementation wasn't able to provide additional
  101. * information about the comparison result.
  102. *
  103. ********************************************************************/
  104. STDMETHODIMP
  105. CITSysSort::Compare(LPCVOID lpcvKey1, LPCVOID lpcvKey2, LONG *plResult,
  106. DWORD *pgrfReason)
  107. {
  108. HRESULT hr = S_OK;
  109. LONG lResult;
  110. if (lpcvKey1 == NULL || lpcvKey2 == NULL || plResult == NULL)
  111. return (SetErrReturn(E_POINTER));
  112. if (!m_fInitialized)
  113. return (SetErrReturn(E_NOTOPEN));
  114. if (SUCCEEDED(hr = CompareSz(lpcvKey1, -1, lpcvKey2, -1, &lResult,
  115. m_srtctl.dwKeyType == IITSK_KEYTYPE_UNICODE_SZ)))
  116. {
  117. // We can set the out params now that we know no error occurred.
  118. *plResult = lResult;
  119. if (pgrfReason != NULL)
  120. *pgrfReason = IITSK_COMPREASON_UNKNOWN;
  121. }
  122. else
  123. {
  124. // Some kind of unexpected error occurred.
  125. SetErrCode(&hr, E_UNEXPECTED);
  126. }
  127. return (hr);
  128. }
  129. /********************************************************************
  130. * @method STDMETHODIMP | IITSortKey | IsRelated |
  131. * Compares two keys and returns information about their sort order.
  132. *
  133. * @parm LPCVOID | lpcvKey1 | Pointer to a key.
  134. * @parm LPCVOID | lpcvKey2 | Pointer to a key.
  135. * @parm DWORD | dwKeyRelation | Specifies the relationship to check.
  136. * Valid parameters are: <nl>
  137. * IITSK_KEYRELATION_PREFIX ((DWORD) 0) <nl>
  138. * IITSK_KEYRELATION_INFIX ((DWORD) 1) <nl>
  139. * IITSK_KEYRELATION_SUFFIX ((DWORD) 2) <nl>
  140. * @parm DWORD | *pgrfReason | (out) Provides additional information about
  141. * the comparison.
  142. *
  143. * @rvalue S_OK | Indicates that lpcvKey1 is related to lpcvKey2 according to
  144. * dwKeyRelation.
  145. * @rvalue S_FALSE | lpcvKey1 is not related to lpcvKey2.
  146. * @rvalue E_INVALIDARG | The value specified for dwKeyRelation is not supported.
  147. *
  148. * @comm
  149. * If pgrfReason is not NULL, *pgrfReason will be filled in
  150. * just as it would be by IITSortKey::Compare.
  151. *
  152. *
  153. ********************************************************************/
  154. STDMETHODIMP
  155. CITSysSort::IsRelated(LPCVOID lpcvKey1, LPCVOID lpcvKey2, DWORD dwKeyRelation,
  156. DWORD *pgrfReason)
  157. {
  158. HRESULT hr;
  159. LONG lResult;
  160. // We will let the first call to Compare catch any entry error
  161. // conditions because it checks for everything we would, except for
  162. // the type of key relation the caller is testing for.
  163. if (dwKeyRelation != IITSK_KEYRELATION_PREFIX)
  164. return (SetErrReturn(E_INVALIDARG));
  165. if (SUCCEEDED(hr = Compare(lpcvKey1, lpcvKey2, &lResult, NULL)))
  166. {
  167. if (lResult < 0)
  168. {
  169. LONG cchKey1;
  170. BOOL fUnicode;
  171. if (fUnicode = (m_srtctl.dwKeyType == IITSK_KEYTYPE_UNICODE_SZ))
  172. cchKey1 = (LONG) WSTRLEN((WCHAR *) lpcvKey1);
  173. else
  174. cchKey1 = (LONG) STRLEN((char *) lpcvKey1);
  175. if (SUCCEEDED(hr = CompareSz(lpcvKey1, cchKey1,
  176. lpcvKey2, cchKey1,
  177. &lResult, fUnicode)))
  178. {
  179. hr = (lResult == 0 ? S_OK : S_FALSE);
  180. }
  181. }
  182. else
  183. hr = (lResult == 0 ? S_OK : S_FALSE);
  184. }
  185. if (SUCCEEDED(hr) && pgrfReason != NULL)
  186. *pgrfReason = IITSK_COMPREASON_UNKNOWN;
  187. return (hr);
  188. }
  189. /*****************************************************************
  190. * @method STDMETHODIMP | IITSortKey | Convert |
  191. * Converts a key of one type into a key of another type.
  192. *
  193. * @parm DWORD | dwKeyTypeIn | Type of input key.
  194. * @parm LPCVOID | lpcvKeyIn | Pointer to input key.
  195. * @parm DWORD | dwKeyTypeOut | Type to convert key to.
  196. * @parm LPCVOID | lpvKeyOut | Pointer to buffer for output key.
  197. * @parm DWORD | *pcbSizeOut | Size of output buffer.
  198. *
  199. * @rvalue S_OK | The operation completed successfully.
  200. * @rvalue E_INVALIDARG | the specified conversion is not supported,
  201. * for example, one or both of the REFGUID parameters is invalid.
  202. * @rvalue E_FAIL | the buffer pointed to by lpvKeyOut was too small
  203. * to hold the converted key.
  204. * @comm
  205. * This is intended mainly for converting an uncompressed key
  206. * into a compressed key, but a sort object is free to provide
  207. * whatever conversion combinations it wants to.
  208. * *pcbSizeOut should contain the size of the buffer pointed
  209. * to by lpvKeyOut. To make sure the buffer size specified in
  210. * *pcbSizeOut is adequate, pass 0 on entry.
  211. *
  212. * @comm
  213. * Not implemented yet.
  214. ****************************************************************/
  215. STDMETHODIMP
  216. CITSysSort::Convert(DWORD dwKeyTypeIn, LPCVOID lpcvKeyIn,
  217. DWORD dwKeyTypeOut, LPVOID lpvKeyOut, DWORD *pcbSizeOut)
  218. {
  219. if (!m_fInitialized)
  220. return (SetErrReturn(E_NOTOPEN));
  221. return (E_NOTIMPL);
  222. }
  223. /*****************************************************************
  224. * @method STDMETHODIMP | IITSortKey | ResolveDuplicates |
  225. * .
  226. *
  227. * @parm LPCVOID | lpcvSz1 | Pointer to the first input key.
  228. * @parm LPCVOID | lpcvSz2 | Pointer to the second input key.
  229. * @parm LPCVOID | lpcvNewSz | Pointer to the new key.
  230. *
  231. * @rvalue S_OK | the operation completed successfully.
  232. * @rvalue E_INVALIDARG | the specified keys are invalid.
  233. * @rvalue E_NOTOPEN | the sort object is not open.
  234. * @rvalue E_FAIL | the buffer pointed to by lpvKeyOut was too small
  235. * to hold the converted key.
  236. * @comm
  237. * If duplicate keys are found (as specified in ::Compare), this
  238. * method provides the oppurtunity to specify a new key. lpcvNewSz
  239. * must compare as equal to lpcvSz1. lpvcNewSz will be allocated in
  240. * this function by CoTaskMemAlloc. It is the callers resposibility
  241. * to free lpcvNewSz when finished with it.
  242. * *pcbSizeOut should contain the size of the buffer pointed
  243. * to by lpvKeyOut. To make sure the buffer size specified in
  244. * *pcbSizeOut is adequate, pass 0 on entry.
  245. *
  246. * @comm
  247. * Not implemented yet.
  248. ****************************************************************/
  249. STDMETHODIMP
  250. CITSysSort::ResolveDuplicates
  251. (LPCVOID lpcvSz1, LPCVOID lpcvSz2,
  252. LPCVOID lpvKeyOut, DWORD *pcbSizeOut)
  253. {
  254. if (!m_fInitialized)
  255. return (SetErrReturn(E_NOTOPEN));
  256. return (E_NOTIMPL);
  257. }
  258. //---------------------------------------------------------------------------
  259. // IITSortKeyConfig Method Implementations
  260. //---------------------------------------------------------------------------
  261. /*******************************************************************
  262. * @method STDMETHODIMP | IITSortKeyConfig | SetLocaleInfo |
  263. * Sets locale information to be used by the sort key interface.
  264. *
  265. * @parm DWORD | dwCodePageID | ANSI code page no. specified at build time.
  266. * @parm LCID | lcid | Win32 locale identifier specified at build time.
  267. *
  268. * @rvalue S_OK | The operation completed successfully.
  269. *
  270. ********************************************************************/
  271. STDMETHODIMP
  272. CITSysSort::SetLocaleInfo(DWORD dwCodePageID, LCID lcid)
  273. {
  274. if (!m_fInitialized)
  275. return (SetErrReturn(E_NOTOPEN));
  276. m_cs.Lock();
  277. m_srtctl.dwCodePageID = dwCodePageID;
  278. m_srtctl.lcid = lcid;
  279. m_fDirty = TRUE;
  280. m_cs.Unlock();
  281. return (S_OK);
  282. }
  283. /*******************************************************************
  284. * @method STDMETHODIMP | IITSortKeyConfig | GetLocaleInfo |
  285. * Retrieves locale information used by the sort key interface.
  286. *
  287. * @parm DWORD | dwCodePageID | ANSI code page no. specified at build time.
  288. * @parm LCID | lcid | Win32 locale identifier specified at build time.
  289. *
  290. * @rvalue E_POINTER | Either pdwCodePageID or plcid is NULL.
  291. * @rvalue E_NOTOPEN | (?) is not initialized.
  292. * @rvalue S_OK | The operation completed successfully.
  293. *
  294. ********************************************************************/
  295. STDMETHODIMP
  296. CITSysSort::GetLocaleInfo(DWORD *pdwCodePageID, LCID *plcid)
  297. {
  298. if (pdwCodePageID == NULL || plcid == NULL)
  299. return (SetErrReturn(E_POINTER));
  300. if (!m_fInitialized)
  301. return (SetErrReturn(E_NOTOPEN));
  302. m_cs.Lock();
  303. *pdwCodePageID = m_srtctl.dwCodePageID;
  304. *plcid = m_srtctl.lcid;
  305. m_cs.Unlock();
  306. return (S_OK);
  307. }
  308. /*******************************************************************
  309. * @method STDMETHODIMP | IITSortKeyConfig | SetKeyType |
  310. * Sets the sort key type that the sort object expects to see in calls
  311. * that take keys as parameters (IITSortKey::GetSize, Compare, IsRelated).
  312. *
  313. * @parm DWORD | dwKeyType | Sort key type. Possible values are:
  314. * IITSK_KEYTYPE_UNICODE_SZ or IITSK_KEYTYPE_ANSI_SZ
  315. *
  316. * @rvalue S_OK | The sort key type was understood by the sort object.
  317. * @rvalue E_INVALIDARG | Invalid sort key type.
  318. *
  319. ********************************************************************/
  320. STDMETHODIMP
  321. CITSysSort::SetKeyType(DWORD dwKeyType)
  322. {
  323. if (!m_fInitialized)
  324. return (SetErrReturn(E_NOTOPEN));
  325. switch (dwKeyType)
  326. {
  327. case IITSK_KEYTYPE_UNICODE_SZ:
  328. case IITSK_KEYTYPE_ANSI_SZ:
  329. break;
  330. default:
  331. return (SetErrReturn(E_INVALIDARG));
  332. };
  333. m_cs.Lock();
  334. m_srtctl.dwKeyType = dwKeyType;
  335. m_fDirty = TRUE;
  336. m_cs.Unlock();
  337. return (S_OK);
  338. }
  339. /*******************************************************************
  340. * @method STDMETHODIMP | IITSortKeyConfig | GetKeyType |
  341. * Retrieves the sort key type that the sort object expects to see in calls
  342. * that take keys as parameters (IITSortKey::GetSize, Compare, IsRelated).
  343. *
  344. * @parm DWORD | *pdwKeyType | Pointer to the sort key type.
  345. *
  346. * @rvalue S_OK | The operation completed successfully.
  347. * @rvalue E_POINTER | The key type is null.
  348. *
  349. ********************************************************************/
  350. STDMETHODIMP
  351. CITSysSort::GetKeyType(DWORD *pdwKeyType)
  352. {
  353. if (pdwKeyType == NULL)
  354. return (SetErrReturn(E_POINTER));
  355. if (!m_fInitialized)
  356. return (SetErrReturn(E_NOTOPEN));
  357. *pdwKeyType = m_srtctl.dwKeyType;
  358. return (S_OK);
  359. }
  360. /*******************************************************************
  361. * @method STDMETHODIMP | IITSortKeyConfig | SetControlInfo |
  362. * Sets data that controls how sort key comparisons are made.
  363. *
  364. * @parm DWORD | grfSortFlags | One or more of the following sort flags:<nl>
  365. * IITSKC_SORT_STRINGSORT 0x00001000 use string sort method <nl>
  366. * IITSKC_NORM_IGNORECASE 0x00000001 ignore case <nl>
  367. * IITSKC_NORM_IGNORENONSPACE 0x00000002 ignore nonspacing chars <nl>
  368. * IITSKC_NORM_IGNORESYMBOLS 0x00000004 ignore symbols <nl>
  369. * IITSKC_NORM_IGNOREKANATYPE 0x00010000 ignore kanatype <nl>
  370. * IITSKC_NORM_IGNOREWIDTH 0x00020000 ignore width <nl>
  371. *
  372. * @parm DWORD | dwReserved | Reserved for future use.
  373. *
  374. *
  375. ********************************************************************/
  376. STDMETHODIMP
  377. CITSysSort::SetControlInfo(DWORD grfSortFlags, DWORD dwReserved)
  378. {
  379. DWORD grfFlagsUnsupported;
  380. if (!m_fInitialized)
  381. return (SetErrReturn(E_NOTOPEN));
  382. grfFlagsUnsupported = ~(IITSKC_SORT_STRINGSORT |
  383. IITSKC_NORM_IGNORECASE |
  384. IITSKC_NORM_IGNORENONSPACE |
  385. IITSKC_NORM_IGNORESYMBOLS |
  386. IITSKC_NORM_IGNORESYMBOLS |
  387. IITSKC_NORM_IGNOREKANATYPE |
  388. IITSKC_NORM_IGNOREWIDTH);
  389. if ((grfSortFlags & grfFlagsUnsupported) != 0)
  390. return (SetErrReturn(E_INVALIDARG));
  391. m_cs.Lock();
  392. m_srtctl.grfSortFlags = grfSortFlags;
  393. m_fDirty = TRUE;
  394. m_cs.Unlock();
  395. return (S_OK);
  396. }
  397. /*******************************************************************
  398. * @method STDMETHODIMP | IITSortKeyConfig | GetControlInfo |
  399. * Retrieves data that controls how sort key comparisons are made.
  400. *
  401. * @parm DWORD | *pgrfSortFlags | Pointer to the sort key flags. See
  402. * <om .SetControlInfo> for a list of valid flags.
  403. *
  404. * @parm DWORD | *pdwReserved | Reserved for future use.
  405. *
  406. *
  407. * @rvalue E_POINTER | The value pgrfSortFlags is NULL.
  408. * @rvalue S_OK | The operation completed successfully.
  409. *
  410. ********************************************************************/
  411. STDMETHODIMP
  412. CITSysSort::GetControlInfo(DWORD *pgrfSortFlags, DWORD *pdwReserved)
  413. {
  414. if (pgrfSortFlags == NULL)
  415. return (SetErrReturn(E_POINTER));
  416. if (!m_fInitialized)
  417. return (SetErrReturn(E_NOTOPEN));
  418. *pgrfSortFlags = m_srtctl.grfSortFlags;
  419. return (S_OK);
  420. }
  421. /*******************************************************************
  422. * @method STDMETHODIMP | IITSortKeyConfig | LoadExternalSortData |
  423. * Loads external sort data such as tables containing the relative
  424. * sort order of specific characters for a textual key type, from the
  425. * specified stream.
  426. *
  427. * @parm IStream | *pStream | Pointer to the external stream object
  428. * from which to load data.
  429. * @parm DWORD | dwExtDataType | Describes the format of sort data.
  430. *
  431. * @comm
  432. * Although the format of the external sort data is entirely
  433. * implementation-specific, this interface provides a general type for
  434. * data that can be passed in dwExtDataType: IITWBC_EXTDATA_SORTTABLE ((DWORD) 2).
  435. *
  436. * @comm
  437. * Not implemented yet.
  438. ********************************************************************/
  439. STDMETHODIMP
  440. CITSysSort::LoadExternalSortData(IStream *pStream, DWORD dwExtDataType)
  441. {
  442. if (!m_fInitialized)
  443. return (SetErrReturn(E_NOTOPEN));
  444. return (E_NOTIMPL);
  445. }
  446. //---------------------------------------------------------------------------
  447. // IPersistStreamInit Method Implementations
  448. //---------------------------------------------------------------------------
  449. STDMETHODIMP
  450. CITSysSort::GetClassID(CLSID *pclsid)
  451. {
  452. if (pclsid == NULL)
  453. return (SetErrReturn(E_POINTER));
  454. *pclsid = CLSID_ITSysSort;
  455. return (S_OK);
  456. }
  457. STDMETHODIMP
  458. CITSysSort::IsDirty(void)
  459. {
  460. if (!m_fInitialized)
  461. return (SetErrReturn(E_NOTOPEN));
  462. return (m_fDirty ? S_OK : S_FALSE);
  463. }
  464. STDMETHODIMP
  465. CITSysSort::Load(IStream *pStream)
  466. {
  467. HRESULT hr;
  468. DWORD dwVersion;
  469. DWORD cbRead;
  470. if (pStream == NULL)
  471. return (SetErrReturn(E_POINTER));
  472. // Lock before checking m_fInitialized to make sure we don't compete
  473. // with a call to ::InitNew.
  474. m_cs.Lock();
  475. if (m_fInitialized)
  476. return (SetErrReturn(E_ALREADYOPEN));
  477. if (SUCCEEDED(hr = pStream->Read((LPVOID) &dwVersion, sizeof(DWORD),
  478. &cbRead)) &&
  479. SUCCEEDED(hr = ((cbRead == sizeof(DWORD)) ? S_OK : E_BADFORMAT)) &&
  480. SUCCEEDED(hr = ((dwVersion == VERSION_SYSSORT) ? S_OK :
  481. E_BADVERSION)) &&
  482. SUCCEEDED(hr = pStream->Read((LPVOID) &m_srtctl, sizeof(SRTCTL),
  483. &cbRead)) &&
  484. SUCCEEDED(hr = ((cbRead == sizeof(SRTCTL)) ? S_OK : E_BADFORMAT)))
  485. {
  486. m_fInitialized = TRUE;
  487. }
  488. m_cs.Unlock();
  489. return (hr);
  490. }
  491. STDMETHODIMP
  492. CITSysSort::Save(IStream *pStream, BOOL fClearDirty)
  493. {
  494. HRESULT hr;
  495. DWORD dwVersion;
  496. DWORD cbWritten;
  497. if (pStream == NULL)
  498. return (SetErrReturn(E_POINTER));
  499. if (!m_fInitialized)
  500. return (SetErrReturn(E_NOTOPEN));
  501. m_cs.Lock();
  502. dwVersion = VERSION_SYSSORT;
  503. if (SUCCEEDED(hr = pStream->Write((LPVOID) &dwVersion, sizeof(DWORD),
  504. &cbWritten)) &&
  505. SUCCEEDED(hr = pStream->Write((LPVOID) &m_srtctl, sizeof(SRTCTL),
  506. &cbWritten)) &&
  507. fClearDirty)
  508. {
  509. m_fDirty = FALSE;
  510. }
  511. m_cs.Unlock();
  512. return (hr);
  513. }
  514. STDMETHODIMP
  515. CITSysSort::GetSizeMax(ULARGE_INTEGER *pcbSizeMax)
  516. {
  517. return (E_NOTIMPL);
  518. }
  519. STDMETHODIMP
  520. CITSysSort::InitNew(void)
  521. {
  522. // Lock before checking m_fInitialized to make sure we don't compete
  523. // with a call to ::Load.
  524. m_cs.Lock();
  525. if (m_fInitialized)
  526. return (SetErrReturn(E_ALREADYOPEN));
  527. m_srtctl.dwCodePageID = GetACP();
  528. m_srtctl.lcid = GetUserDefaultLCID();
  529. m_srtctl.dwKeyType = IITSK_KEYTYPE_UNICODE_SZ;
  530. // CompareString does word sort by default, but we have to
  531. // tell it to ignore case.
  532. m_srtctl.grfSortFlags = IITSKC_NORM_IGNORECASE;
  533. m_fInitialized = TRUE;
  534. m_cs.Unlock();
  535. return (S_OK);
  536. }
  537. //---------------------------------------------------------------------------
  538. // Private Method Implementations
  539. //---------------------------------------------------------------------------
  540. // Compares either two Unicode strings or two Ansi strings, calling the
  541. // appropriate variant of CompareString. The cch params should denote
  542. // count of characters, NOT bytes, not including a NULL terminator. -1
  543. // is a valid value for the cch params, which means compare the strings
  544. // until a NULL terminator is found. If fUnicode is TRUE, this routine
  545. // may decide to convert the string to Ansi before doing the compare if
  546. // the system doesn't support CompareStringW. The result of the
  547. // comparison is returned in *plResult in strcmp-compatible form.
  548. HRESULT
  549. CITSysSort::CompareSz(LPCVOID lpcvSz1, LONG cch1, LPCVOID lpcvSz2, LONG cch2,
  550. LONG *plResult, BOOL fUnicode)
  551. {
  552. HRESULT hr = S_OK;
  553. LONG lResult;
  554. BOOL fAnsiCompare;
  555. SRTCTL srtctl;
  556. LPSTR lpstr1 = NULL;
  557. LPSTR lpstr2 = NULL;
  558. m_cs.Lock();
  559. srtctl = m_srtctl;
  560. m_cs.Unlock();
  561. fAnsiCompare = !fUnicode || !m_fWinNT;
  562. // See if we need to convert from Unicode to ANSI.
  563. if (fAnsiCompare && fUnicode)
  564. {
  565. DWORD cbAnsi1;
  566. DWORD cbAnsi2;
  567. m_cs.Lock();
  568. if (cch1 < 0)
  569. hr = GetSize(lpcvSz1, &cbAnsi1);
  570. else
  571. // leave enough space for double byte chars in MBCS.
  572. cbAnsi1 = (cch1 + 1) * sizeof(WCHAR);
  573. if (cch2 < 0)
  574. hr = GetSize(lpcvSz2, &cbAnsi2);
  575. else
  576. // leave enough space for double byte chars in MBCS.
  577. cbAnsi2 = (cch2 + 1) * sizeof(WCHAR);
  578. if (SUCCEEDED(hr) &&
  579. SUCCEEDED(hr = ReallocBuffer(&m_hmemAnsi1, &m_cbBufAnsi1Cur,
  580. cbAnsi1)) &&
  581. SUCCEEDED(hr = ReallocBuffer(&m_hmemAnsi2, &m_cbBufAnsi2Cur,
  582. cbAnsi2)))
  583. {
  584. // We lock the ansi buffers here, but we won't unlock them
  585. // until the end of this routine so that we can pass them
  586. // to compare string.
  587. lpstr1 = (LPSTR) _GLOBALLOCK(m_hmemAnsi1);
  588. lpstr2 = (LPSTR) _GLOBALLOCK(m_hmemAnsi2);
  589. if ((cch1 = WideCharToMultiByte(srtctl.dwCodePageID, NULL,
  590. (LPCWSTR) lpcvSz1, cch1, lpstr1, m_cbBufAnsi1Cur,
  591. NULL, NULL)) != 0 &&
  592. (cch2 = WideCharToMultiByte(srtctl.dwCodePageID, NULL,
  593. (LPCWSTR) lpcvSz2, cch2, lpstr2, m_cbBufAnsi2Cur,
  594. NULL, NULL)) != 0)
  595. {
  596. // Set up for call to CompareStringA.
  597. lpcvSz1 = (LPCVOID) lpstr1;
  598. lpcvSz2 = (LPCVOID) lpstr2;
  599. }
  600. else
  601. hr = E_UNEXPECTED;
  602. }
  603. }
  604. if (SUCCEEDED(hr))
  605. {
  606. if (fAnsiCompare)
  607. lResult = CompareStringA(srtctl.lcid, srtctl.grfSortFlags,
  608. (LPCSTR) lpcvSz1, cch1, (LPCSTR) lpcvSz2, cch2);
  609. else
  610. lResult = CompareStringW(srtctl.lcid, srtctl.grfSortFlags,
  611. (LPCWSTR) lpcvSz1, cch1, (LPCWSTR) lpcvSz2, cch2);
  612. if (lResult == 0)
  613. // Some kind of unexpected error occurred.
  614. SetErrCode(&hr, E_UNEXPECTED);
  615. else
  616. // We need to subtract 2 from the lResult to convert
  617. // it into a strcmp-compatible form.
  618. *plResult = lResult - 2;
  619. }
  620. if (lpstr1 != NULL)
  621. _GLOBALUNLOCK(m_hmemAnsi1);
  622. if (lpstr2 != NULL)
  623. _GLOBALUNLOCK(m_hmemAnsi2);
  624. if (fAnsiCompare && fUnicode)
  625. m_cs.Unlock();
  626. return (hr);
  627. }
  628. HRESULT
  629. CITSysSort::ReallocBuffer(HGLOBAL *phmemBuf, DWORD *pcbBufCur, DWORD cbBufNew)
  630. {
  631. HRESULT hr = S_OK;
  632. m_cs.Lock();
  633. hr = ReallocBufferHmem(phmemBuf, pcbBufCur, max(cbBufNew, cbAnsiBufInit));
  634. m_cs.Unlock();
  635. return (hr);
  636. }
  637. void
  638. CITSysSort::Close(void)
  639. {
  640. if (m_hmemAnsi1 != NULL)
  641. {
  642. _GLOBALFREE(m_hmemAnsi1);
  643. m_hmemAnsi1 = NULL;
  644. m_cbBufAnsi1Cur = 0;
  645. }
  646. if (m_hmemAnsi2 != NULL)
  647. {
  648. _GLOBALFREE(m_hmemAnsi2);
  649. m_hmemAnsi2 = NULL;
  650. m_cbBufAnsi2Cur = 0;
  651. }
  652. MEMSET(&m_srtctl, NULL, sizeof(SRTCTL));
  653. m_fInitialized = m_fDirty = FALSE;
  654. }