805 lines
23 KiB
C++
805 lines
23 KiB
C++
/*************************************************************************
|
|
* @doc SHROOM EXTERNAL API *
|
|
* *
|
|
* SYSSRT.CPP *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1997 *
|
|
* All Rights reserved. *
|
|
* *
|
|
* This file contains the implementation of CITSysSort methods. *
|
|
* CITSysSort is a pluggable sort object that uses the system's *
|
|
* CompareString function to do comparisons. CITSysSort supports *
|
|
* NULL terminated strings that are either Unicode or ANSI. *
|
|
* *
|
|
**************************************************************************
|
|
* *
|
|
* Written By : Bill Aloof *
|
|
* Current Owner: billa *
|
|
* *
|
|
**************************************************************************/
|
|
|
|
#include <mvopsys.h>
|
|
|
|
#ifdef _DEBUG
|
|
static char s_aszModule[] = __FILE__; /* For error report */
|
|
#endif
|
|
|
|
#include <atlinc.h> // includes for ATL.
|
|
#include <_mvutil.h>
|
|
#include <mem.h>
|
|
#include <orkin.h>
|
|
#include <iterror.h>
|
|
#include <itsort.h>
|
|
#include <itsortid.h>
|
|
#include "syssrt.h"
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Constructor and Destructor
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
CITSysSort::CITSysSort()
|
|
{
|
|
OSVERSIONINFO osvi;
|
|
|
|
m_fInitialized = m_fDirty = FALSE;
|
|
MEMSET(&m_srtctl, NULL, sizeof(SRTCTL));
|
|
m_hmemAnsi1 = m_hmemAnsi2 = NULL;
|
|
m_cbBufAnsi1Cur = m_cbBufAnsi2Cur = 0;
|
|
|
|
// See if we're running on NT; if GetVersionEx fails, we'll assume
|
|
// we're not since that's causes us do take the more conservative route
|
|
// when doing comparisons.
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
m_fWinNT = (GetVersionEx(&osvi) ?
|
|
(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) : FALSE);
|
|
}
|
|
|
|
|
|
CITSysSort::~CITSysSort()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// IITSortKey Method Implementations
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
/********************************************************************
|
|
* @method STDMETHODIMP | IITSortKey | GetSize |
|
|
* Determines the size of a key.
|
|
* @parm LPCVOID* | lpcvKey | Pointer to key
|
|
* @parm DWORD* | pcbSize | Out param containing key size.
|
|
*
|
|
* @rvalue E_POINTER | lpcvKey or pcbSize was NULL
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::GetSize(LPCVOID lpcvKey, DWORD *pcbSize)
|
|
{
|
|
if (lpcvKey == NULL || pcbSize == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
if (m_srtctl.dwKeyType == IITSK_KEYTYPE_UNICODE_SZ)
|
|
*pcbSize = (DWORD) (sizeof(WCHAR) * (WSTRLEN((WCHAR *)lpcvKey) + 1));
|
|
else
|
|
*pcbSize = (DWORD) (STRLEN((char *)lpcvKey) + 1);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* @method STDMETHODIMP | IITSortKey | Compare |
|
|
* Compares two keys and returns information about their sort order.
|
|
*
|
|
* @parm LPCVOID | lpcvKey1 | Pointer to a key.
|
|
* @parm LPCVOID | lpcvKey2 | Pointer to a key.
|
|
* @parm LONG | *plResult | (out) Indicates whether lpcvKey1 is less than, equal to, or
|
|
* greater than lpcvKey2.
|
|
* @parm DWORD | *pgrfReason | (out) Provides additional information about
|
|
* the comparison (see comments below).
|
|
*
|
|
* @rvalue E_POINTER | Either lpcvKey1, lpcvKey2, or *plResult was NULL
|
|
*
|
|
* @comm
|
|
* On exit, *plResult is set according to strcmp conventions:
|
|
* <lt> 0, = 0, <gt> 0, depending on whether lpcvKey1 is less than, equal to, or
|
|
* greater than lpcvKey2. If pgrfReason is not NULL, *pgrfReason may be
|
|
* filled in on exit with one or more bit flags giving more information about
|
|
* the result of the comparison, if the result was affected by something other
|
|
* than raw lexical comparison (such as special character mappings). If
|
|
* *pgrfReason contains 0 on exit, that means the comparison result
|
|
* was purely lexical; if *pgrfReason contains IITSK_COMPREASON_UNKNOWN,
|
|
* then the sort object implementation wasn't able to provide additional
|
|
* information about the comparison result.
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::Compare(LPCVOID lpcvKey1, LPCVOID lpcvKey2, LONG *plResult,
|
|
DWORD *pgrfReason)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lResult;
|
|
|
|
if (lpcvKey1 == NULL || lpcvKey2 == NULL || plResult == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
if (SUCCEEDED(hr = CompareSz(lpcvKey1, -1, lpcvKey2, -1, &lResult,
|
|
m_srtctl.dwKeyType == IITSK_KEYTYPE_UNICODE_SZ)))
|
|
{
|
|
// We can set the out params now that we know no error occurred.
|
|
*plResult = lResult;
|
|
if (pgrfReason != NULL)
|
|
*pgrfReason = IITSK_COMPREASON_UNKNOWN;
|
|
}
|
|
else
|
|
{
|
|
// Some kind of unexpected error occurred.
|
|
SetErrCode(&hr, E_UNEXPECTED);
|
|
}
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
/********************************************************************
|
|
* @method STDMETHODIMP | IITSortKey | IsRelated |
|
|
* Compares two keys and returns information about their sort order.
|
|
*
|
|
* @parm LPCVOID | lpcvKey1 | Pointer to a key.
|
|
* @parm LPCVOID | lpcvKey2 | Pointer to a key.
|
|
* @parm DWORD | dwKeyRelation | Specifies the relationship to check.
|
|
* Valid parameters are: <nl>
|
|
* IITSK_KEYRELATION_PREFIX ((DWORD) 0) <nl>
|
|
* IITSK_KEYRELATION_INFIX ((DWORD) 1) <nl>
|
|
* IITSK_KEYRELATION_SUFFIX ((DWORD) 2) <nl>
|
|
* @parm DWORD | *pgrfReason | (out) Provides additional information about
|
|
* the comparison.
|
|
*
|
|
* @rvalue S_OK | Indicates that lpcvKey1 is related to lpcvKey2 according to
|
|
* dwKeyRelation.
|
|
* @rvalue S_FALSE | lpcvKey1 is not related to lpcvKey2.
|
|
* @rvalue E_INVALIDARG | The value specified for dwKeyRelation is not supported.
|
|
*
|
|
* @comm
|
|
* If pgrfReason is not NULL, *pgrfReason will be filled in
|
|
* just as it would be by IITSortKey::Compare.
|
|
*
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::IsRelated(LPCVOID lpcvKey1, LPCVOID lpcvKey2, DWORD dwKeyRelation,
|
|
DWORD *pgrfReason)
|
|
{
|
|
HRESULT hr;
|
|
LONG lResult;
|
|
|
|
// We will let the first call to Compare catch any entry error
|
|
// conditions because it checks for everything we would, except for
|
|
// the type of key relation the caller is testing for.
|
|
if (dwKeyRelation != IITSK_KEYRELATION_PREFIX)
|
|
return (SetErrReturn(E_INVALIDARG));
|
|
|
|
if (SUCCEEDED(hr = Compare(lpcvKey1, lpcvKey2, &lResult, NULL)))
|
|
{
|
|
if (lResult < 0)
|
|
{
|
|
LONG cchKey1;
|
|
BOOL fUnicode;
|
|
|
|
if (fUnicode = (m_srtctl.dwKeyType == IITSK_KEYTYPE_UNICODE_SZ))
|
|
cchKey1 = (LONG) WSTRLEN((WCHAR *) lpcvKey1);
|
|
else
|
|
cchKey1 = (LONG) STRLEN((char *) lpcvKey1);
|
|
|
|
if (SUCCEEDED(hr = CompareSz(lpcvKey1, cchKey1,
|
|
lpcvKey2, cchKey1,
|
|
&lResult, fUnicode)))
|
|
{
|
|
hr = (lResult == 0 ? S_OK : S_FALSE);
|
|
}
|
|
}
|
|
else
|
|
hr = (lResult == 0 ? S_OK : S_FALSE);
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && pgrfReason != NULL)
|
|
*pgrfReason = IITSK_COMPREASON_UNKNOWN;
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
* @method STDMETHODIMP | IITSortKey | Convert |
|
|
* Converts a key of one type into a key of another type.
|
|
*
|
|
* @parm DWORD | dwKeyTypeIn | Type of input key.
|
|
* @parm LPCVOID | lpcvKeyIn | Pointer to input key.
|
|
* @parm DWORD | dwKeyTypeOut | Type to convert key to.
|
|
* @parm LPCVOID | lpvKeyOut | Pointer to buffer for output key.
|
|
* @parm DWORD | *pcbSizeOut | Size of output buffer.
|
|
*
|
|
* @rvalue S_OK | The operation completed successfully.
|
|
* @rvalue E_INVALIDARG | the specified conversion is not supported,
|
|
* for example, one or both of the REFGUID parameters is invalid.
|
|
* @rvalue E_FAIL | the buffer pointed to by lpvKeyOut was too small
|
|
* to hold the converted key.
|
|
* @comm
|
|
* This is intended mainly for converting an uncompressed key
|
|
* into a compressed key, but a sort object is free to provide
|
|
* whatever conversion combinations it wants to.
|
|
* *pcbSizeOut should contain the size of the buffer pointed
|
|
* to by lpvKeyOut. To make sure the buffer size specified in
|
|
* *pcbSizeOut is adequate, pass 0 on entry.
|
|
*
|
|
* @comm
|
|
* Not implemented yet.
|
|
****************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::Convert(DWORD dwKeyTypeIn, LPCVOID lpcvKeyIn,
|
|
DWORD dwKeyTypeOut, LPVOID lpvKeyOut, DWORD *pcbSizeOut)
|
|
{
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
* @method STDMETHODIMP | IITSortKey | ResolveDuplicates |
|
|
* .
|
|
*
|
|
* @parm LPCVOID | lpcvSz1 | Pointer to the first input key.
|
|
* @parm LPCVOID | lpcvSz2 | Pointer to the second input key.
|
|
* @parm LPCVOID | lpcvNewSz | Pointer to the new key.
|
|
*
|
|
* @rvalue S_OK | the operation completed successfully.
|
|
* @rvalue E_INVALIDARG | the specified keys are invalid.
|
|
* @rvalue E_NOTOPEN | the sort object is not open.
|
|
* @rvalue E_FAIL | the buffer pointed to by lpvKeyOut was too small
|
|
* to hold the converted key.
|
|
* @comm
|
|
* If duplicate keys are found (as specified in ::Compare), this
|
|
* method provides the oppurtunity to specify a new key. lpcvNewSz
|
|
* must compare as equal to lpcvSz1. lpvcNewSz will be allocated in
|
|
* this function by CoTaskMemAlloc. It is the callers resposibility
|
|
* to free lpcvNewSz when finished with it.
|
|
* *pcbSizeOut should contain the size of the buffer pointed
|
|
* to by lpvKeyOut. To make sure the buffer size specified in
|
|
* *pcbSizeOut is adequate, pass 0 on entry.
|
|
*
|
|
* @comm
|
|
* Not implemented yet.
|
|
****************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::ResolveDuplicates
|
|
(LPCVOID lpcvSz1, LPCVOID lpcvSz2,
|
|
LPCVOID lpvKeyOut, DWORD *pcbSizeOut)
|
|
{
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// IITSortKeyConfig Method Implementations
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
/*******************************************************************
|
|
* @method STDMETHODIMP | IITSortKeyConfig | SetLocaleInfo |
|
|
* Sets locale information to be used by the sort key interface.
|
|
*
|
|
* @parm DWORD | dwCodePageID | ANSI code page no. specified at build time.
|
|
* @parm LCID | lcid | Win32 locale identifier specified at build time.
|
|
*
|
|
* @rvalue S_OK | The operation completed successfully.
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::SetLocaleInfo(DWORD dwCodePageID, LCID lcid)
|
|
{
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
m_cs.Lock();
|
|
|
|
m_srtctl.dwCodePageID = dwCodePageID;
|
|
m_srtctl.lcid = lcid;
|
|
|
|
m_fDirty = TRUE;
|
|
|
|
m_cs.Unlock();
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* @method STDMETHODIMP | IITSortKeyConfig | GetLocaleInfo |
|
|
* Retrieves locale information used by the sort key interface.
|
|
*
|
|
* @parm DWORD | dwCodePageID | ANSI code page no. specified at build time.
|
|
* @parm LCID | lcid | Win32 locale identifier specified at build time.
|
|
*
|
|
* @rvalue E_POINTER | Either pdwCodePageID or plcid is NULL.
|
|
* @rvalue E_NOTOPEN | (?) is not initialized.
|
|
* @rvalue S_OK | The operation completed successfully.
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::GetLocaleInfo(DWORD *pdwCodePageID, LCID *plcid)
|
|
{
|
|
if (pdwCodePageID == NULL || plcid == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
m_cs.Lock();
|
|
|
|
*pdwCodePageID = m_srtctl.dwCodePageID;
|
|
*plcid = m_srtctl.lcid;
|
|
|
|
m_cs.Unlock();
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* @method STDMETHODIMP | IITSortKeyConfig | SetKeyType |
|
|
* Sets the sort key type that the sort object expects to see in calls
|
|
* that take keys as parameters (IITSortKey::GetSize, Compare, IsRelated).
|
|
*
|
|
* @parm DWORD | dwKeyType | Sort key type. Possible values are:
|
|
* IITSK_KEYTYPE_UNICODE_SZ or IITSK_KEYTYPE_ANSI_SZ
|
|
*
|
|
* @rvalue S_OK | The sort key type was understood by the sort object.
|
|
* @rvalue E_INVALIDARG | Invalid sort key type.
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::SetKeyType(DWORD dwKeyType)
|
|
{
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
switch (dwKeyType)
|
|
{
|
|
case IITSK_KEYTYPE_UNICODE_SZ:
|
|
case IITSK_KEYTYPE_ANSI_SZ:
|
|
break;
|
|
|
|
default:
|
|
return (SetErrReturn(E_INVALIDARG));
|
|
};
|
|
|
|
m_cs.Lock();
|
|
|
|
m_srtctl.dwKeyType = dwKeyType;
|
|
m_fDirty = TRUE;
|
|
|
|
m_cs.Unlock();
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* @method STDMETHODIMP | IITSortKeyConfig | GetKeyType |
|
|
* Retrieves the sort key type that the sort object expects to see in calls
|
|
* that take keys as parameters (IITSortKey::GetSize, Compare, IsRelated).
|
|
*
|
|
* @parm DWORD | *pdwKeyType | Pointer to the sort key type.
|
|
*
|
|
* @rvalue S_OK | The operation completed successfully.
|
|
* @rvalue E_POINTER | The key type is null.
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::GetKeyType(DWORD *pdwKeyType)
|
|
{
|
|
if (pdwKeyType == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
*pdwKeyType = m_srtctl.dwKeyType;
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* @method STDMETHODIMP | IITSortKeyConfig | SetControlInfo |
|
|
* Sets data that controls how sort key comparisons are made.
|
|
*
|
|
* @parm DWORD | grfSortFlags | One or more of the following sort flags:<nl>
|
|
* IITSKC_SORT_STRINGSORT 0x00001000 use string sort method <nl>
|
|
* IITSKC_NORM_IGNORECASE 0x00000001 ignore case <nl>
|
|
* IITSKC_NORM_IGNORENONSPACE 0x00000002 ignore nonspacing chars <nl>
|
|
* IITSKC_NORM_IGNORESYMBOLS 0x00000004 ignore symbols <nl>
|
|
* IITSKC_NORM_IGNOREKANATYPE 0x00010000 ignore kanatype <nl>
|
|
* IITSKC_NORM_IGNOREWIDTH 0x00020000 ignore width <nl>
|
|
*
|
|
* @parm DWORD | dwReserved | Reserved for future use.
|
|
*
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::SetControlInfo(DWORD grfSortFlags, DWORD dwReserved)
|
|
{
|
|
DWORD grfFlagsUnsupported;
|
|
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
grfFlagsUnsupported = ~(IITSKC_SORT_STRINGSORT |
|
|
IITSKC_NORM_IGNORECASE |
|
|
IITSKC_NORM_IGNORENONSPACE |
|
|
IITSKC_NORM_IGNORESYMBOLS |
|
|
IITSKC_NORM_IGNORESYMBOLS |
|
|
IITSKC_NORM_IGNOREKANATYPE |
|
|
IITSKC_NORM_IGNOREWIDTH);
|
|
|
|
if ((grfSortFlags & grfFlagsUnsupported) != 0)
|
|
return (SetErrReturn(E_INVALIDARG));
|
|
|
|
m_cs.Lock();
|
|
|
|
m_srtctl.grfSortFlags = grfSortFlags;
|
|
m_fDirty = TRUE;
|
|
|
|
m_cs.Unlock();
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* @method STDMETHODIMP | IITSortKeyConfig | GetControlInfo |
|
|
* Retrieves data that controls how sort key comparisons are made.
|
|
*
|
|
* @parm DWORD | *pgrfSortFlags | Pointer to the sort key flags. See
|
|
* <om .SetControlInfo> for a list of valid flags.
|
|
*
|
|
* @parm DWORD | *pdwReserved | Reserved for future use.
|
|
*
|
|
*
|
|
* @rvalue E_POINTER | The value pgrfSortFlags is NULL.
|
|
* @rvalue S_OK | The operation completed successfully.
|
|
*
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::GetControlInfo(DWORD *pgrfSortFlags, DWORD *pdwReserved)
|
|
{
|
|
if (pgrfSortFlags == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
*pgrfSortFlags = m_srtctl.grfSortFlags;
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* @method STDMETHODIMP | IITSortKeyConfig | LoadExternalSortData |
|
|
* Loads external sort data such as tables containing the relative
|
|
* sort order of specific characters for a textual key type, from the
|
|
* specified stream.
|
|
*
|
|
* @parm IStream | *pStream | Pointer to the external stream object
|
|
* from which to load data.
|
|
* @parm DWORD | dwExtDataType | Describes the format of sort data.
|
|
*
|
|
* @comm
|
|
* Although the format of the external sort data is entirely
|
|
* implementation-specific, this interface provides a general type for
|
|
* data that can be passed in dwExtDataType: IITWBC_EXTDATA_SORTTABLE ((DWORD) 2).
|
|
*
|
|
* @comm
|
|
* Not implemented yet.
|
|
********************************************************************/
|
|
STDMETHODIMP
|
|
CITSysSort::LoadExternalSortData(IStream *pStream, DWORD dwExtDataType)
|
|
{
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// IPersistStreamInit Method Implementations
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
STDMETHODIMP
|
|
CITSysSort::GetClassID(CLSID *pclsid)
|
|
{
|
|
if (pclsid == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
*pclsid = CLSID_ITSysSort;
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CITSysSort::IsDirty(void)
|
|
{
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
return (m_fDirty ? S_OK : S_FALSE);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CITSysSort::Load(IStream *pStream)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwVersion;
|
|
DWORD cbRead;
|
|
|
|
if (pStream == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
// Lock before checking m_fInitialized to make sure we don't compete
|
|
// with a call to ::InitNew.
|
|
m_cs.Lock();
|
|
|
|
if (m_fInitialized)
|
|
return (SetErrReturn(E_ALREADYOPEN));
|
|
|
|
if (SUCCEEDED(hr = pStream->Read((LPVOID) &dwVersion, sizeof(DWORD),
|
|
&cbRead)) &&
|
|
SUCCEEDED(hr = ((cbRead == sizeof(DWORD)) ? S_OK : E_BADFORMAT)) &&
|
|
SUCCEEDED(hr = ((dwVersion == VERSION_SYSSORT) ? S_OK :
|
|
E_BADVERSION)) &&
|
|
SUCCEEDED(hr = pStream->Read((LPVOID) &m_srtctl, sizeof(SRTCTL),
|
|
&cbRead)) &&
|
|
SUCCEEDED(hr = ((cbRead == sizeof(SRTCTL)) ? S_OK : E_BADFORMAT)))
|
|
{
|
|
m_fInitialized = TRUE;
|
|
}
|
|
|
|
m_cs.Unlock();
|
|
return (hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CITSysSort::Save(IStream *pStream, BOOL fClearDirty)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwVersion;
|
|
DWORD cbWritten;
|
|
|
|
if (pStream == NULL)
|
|
return (SetErrReturn(E_POINTER));
|
|
|
|
if (!m_fInitialized)
|
|
return (SetErrReturn(E_NOTOPEN));
|
|
|
|
m_cs.Lock();
|
|
|
|
dwVersion = VERSION_SYSSORT;
|
|
if (SUCCEEDED(hr = pStream->Write((LPVOID) &dwVersion, sizeof(DWORD),
|
|
&cbWritten)) &&
|
|
SUCCEEDED(hr = pStream->Write((LPVOID) &m_srtctl, sizeof(SRTCTL),
|
|
&cbWritten)) &&
|
|
fClearDirty)
|
|
{
|
|
m_fDirty = FALSE;
|
|
}
|
|
|
|
m_cs.Unlock();
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CITSysSort::GetSizeMax(ULARGE_INTEGER *pcbSizeMax)
|
|
{
|
|
return (E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CITSysSort::InitNew(void)
|
|
{
|
|
// Lock before checking m_fInitialized to make sure we don't compete
|
|
// with a call to ::Load.
|
|
m_cs.Lock();
|
|
|
|
if (m_fInitialized)
|
|
return (SetErrReturn(E_ALREADYOPEN));
|
|
|
|
m_srtctl.dwCodePageID = GetACP();
|
|
m_srtctl.lcid = GetUserDefaultLCID();
|
|
m_srtctl.dwKeyType = IITSK_KEYTYPE_UNICODE_SZ;
|
|
|
|
// CompareString does word sort by default, but we have to
|
|
// tell it to ignore case.
|
|
m_srtctl.grfSortFlags = IITSKC_NORM_IGNORECASE;
|
|
|
|
m_fInitialized = TRUE;
|
|
|
|
m_cs.Unlock();
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Private Method Implementations
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
// Compares either two Unicode strings or two Ansi strings, calling the
|
|
// appropriate variant of CompareString. The cch params should denote
|
|
// count of characters, NOT bytes, not including a NULL terminator. -1
|
|
// is a valid value for the cch params, which means compare the strings
|
|
// until a NULL terminator is found. If fUnicode is TRUE, this routine
|
|
// may decide to convert the string to Ansi before doing the compare if
|
|
// the system doesn't support CompareStringW. The result of the
|
|
// comparison is returned in *plResult in strcmp-compatible form.
|
|
HRESULT
|
|
CITSysSort::CompareSz(LPCVOID lpcvSz1, LONG cch1, LPCVOID lpcvSz2, LONG cch2,
|
|
LONG *plResult, BOOL fUnicode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lResult;
|
|
BOOL fAnsiCompare;
|
|
SRTCTL srtctl;
|
|
LPSTR lpstr1 = NULL;
|
|
LPSTR lpstr2 = NULL;
|
|
|
|
|
|
m_cs.Lock();
|
|
srtctl = m_srtctl;
|
|
m_cs.Unlock();
|
|
|
|
fAnsiCompare = !fUnicode || !m_fWinNT;
|
|
|
|
// See if we need to convert from Unicode to ANSI.
|
|
if (fAnsiCompare && fUnicode)
|
|
{
|
|
DWORD cbAnsi1;
|
|
DWORD cbAnsi2;
|
|
|
|
m_cs.Lock();
|
|
|
|
if (cch1 < 0)
|
|
hr = GetSize(lpcvSz1, &cbAnsi1);
|
|
else
|
|
// leave enough space for double byte chars in MBCS.
|
|
cbAnsi1 = (cch1 + 1) * sizeof(WCHAR);
|
|
|
|
if (cch2 < 0)
|
|
hr = GetSize(lpcvSz2, &cbAnsi2);
|
|
else
|
|
// leave enough space for double byte chars in MBCS.
|
|
cbAnsi2 = (cch2 + 1) * sizeof(WCHAR);
|
|
|
|
if (SUCCEEDED(hr) &&
|
|
SUCCEEDED(hr = ReallocBuffer(&m_hmemAnsi1, &m_cbBufAnsi1Cur,
|
|
cbAnsi1)) &&
|
|
SUCCEEDED(hr = ReallocBuffer(&m_hmemAnsi2, &m_cbBufAnsi2Cur,
|
|
cbAnsi2)))
|
|
{
|
|
// We lock the ansi buffers here, but we won't unlock them
|
|
// until the end of this routine so that we can pass them
|
|
// to compare string.
|
|
lpstr1 = (LPSTR) _GLOBALLOCK(m_hmemAnsi1);
|
|
lpstr2 = (LPSTR) _GLOBALLOCK(m_hmemAnsi2);
|
|
|
|
if ((cch1 = WideCharToMultiByte(srtctl.dwCodePageID, NULL,
|
|
(LPCWSTR) lpcvSz1, cch1, lpstr1, m_cbBufAnsi1Cur,
|
|
NULL, NULL)) != 0 &&
|
|
(cch2 = WideCharToMultiByte(srtctl.dwCodePageID, NULL,
|
|
(LPCWSTR) lpcvSz2, cch2, lpstr2, m_cbBufAnsi2Cur,
|
|
NULL, NULL)) != 0)
|
|
{
|
|
// Set up for call to CompareStringA.
|
|
lpcvSz1 = (LPCVOID) lpstr1;
|
|
lpcvSz2 = (LPCVOID) lpstr2;
|
|
}
|
|
else
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (fAnsiCompare)
|
|
lResult = CompareStringA(srtctl.lcid, srtctl.grfSortFlags,
|
|
(LPCSTR) lpcvSz1, cch1, (LPCSTR) lpcvSz2, cch2);
|
|
else
|
|
lResult = CompareStringW(srtctl.lcid, srtctl.grfSortFlags,
|
|
(LPCWSTR) lpcvSz1, cch1, (LPCWSTR) lpcvSz2, cch2);
|
|
|
|
if (lResult == 0)
|
|
// Some kind of unexpected error occurred.
|
|
SetErrCode(&hr, E_UNEXPECTED);
|
|
else
|
|
// We need to subtract 2 from the lResult to convert
|
|
// it into a strcmp-compatible form.
|
|
*plResult = lResult - 2;
|
|
}
|
|
|
|
if (lpstr1 != NULL)
|
|
_GLOBALUNLOCK(m_hmemAnsi1);
|
|
|
|
if (lpstr2 != NULL)
|
|
_GLOBALUNLOCK(m_hmemAnsi2);
|
|
|
|
if (fAnsiCompare && fUnicode)
|
|
m_cs.Unlock();
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CITSysSort::ReallocBuffer(HGLOBAL *phmemBuf, DWORD *pcbBufCur, DWORD cbBufNew)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
m_cs.Lock();
|
|
|
|
hr = ReallocBufferHmem(phmemBuf, pcbBufCur, max(cbBufNew, cbAnsiBufInit));
|
|
|
|
m_cs.Unlock();
|
|
|
|
return (hr);
|
|
}
|
|
|
|
|
|
void
|
|
CITSysSort::Close(void)
|
|
{
|
|
if (m_hmemAnsi1 != NULL)
|
|
{
|
|
_GLOBALFREE(m_hmemAnsi1);
|
|
m_hmemAnsi1 = NULL;
|
|
m_cbBufAnsi1Cur = 0;
|
|
}
|
|
|
|
if (m_hmemAnsi2 != NULL)
|
|
{
|
|
_GLOBALFREE(m_hmemAnsi2);
|
|
m_hmemAnsi2 = NULL;
|
|
m_cbBufAnsi2Cur = 0;
|
|
}
|
|
|
|
MEMSET(&m_srtctl, NULL, sizeof(SRTCTL));
|
|
m_fInitialized = m_fDirty = FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|