778 lines
22 KiB
C++
778 lines
22 KiB
C++
|
|
||
|
|
||
|
//+============================================================================
|
||
|
//
|
||
|
// File: RtlStub.cxx
|
||
|
//
|
||
|
// Purpose:
|
||
|
// This file provides some RTL routines which are also implemented
|
||
|
// in NTDLL. They are duplicated here so that we can build
|
||
|
// PropTest without linking to NTDLL, which doesn't exist
|
||
|
// on Win95.
|
||
|
//
|
||
|
//+============================================================================
|
||
|
|
||
|
|
||
|
|
||
|
#include "pch.cxx" // Brings in most other includes/defines/etc.
|
||
|
|
||
|
#define BSTRLEN(bstrVal) *((ULONG *) bstrVal - 1)
|
||
|
|
||
|
// we use static array instead of string literals because some systems
|
||
|
// have 4 bytes string literals, and would not produce the correct result
|
||
|
// for REF's 2 byte Unicode convention
|
||
|
//
|
||
|
OLECHAR aocMap[CCH_MAP + 1] = {'a','b','c','d','e','f','g',
|
||
|
'h','i','j','k','l','m','n',
|
||
|
'o','p','q','r','s','t','u',
|
||
|
'v','w','x','y','z',
|
||
|
'0','1','2','3','4','5','\0'};
|
||
|
|
||
|
GUID guidSummary =
|
||
|
{ 0xf29f85e0,
|
||
|
0x4ff9, 0x1068,
|
||
|
{ 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 } };
|
||
|
|
||
|
OLECHAR oszSummary[] = {'S','u','m','m','a','r','y',
|
||
|
'I','n','f','o','r','m','a','t','i','o','n','\0'};
|
||
|
|
||
|
GUID guidDocumentSummary =
|
||
|
{ 0xd5cdd502,
|
||
|
0x2e9c, 0x101b,
|
||
|
{ 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae } };
|
||
|
|
||
|
OLECHAR oszDocumentSummary[] = {'D','o','c','u','m','e','n','t',
|
||
|
'S','u','m','m','a','r','y',
|
||
|
'I','n','f','o','r','m','a','t','i','o','n',
|
||
|
'\0'};
|
||
|
|
||
|
// Note that user defined properties are placed in section 2 with the below
|
||
|
// GUID as the FMTID -- alas, we did not expect Office95 to actually use it.
|
||
|
|
||
|
GUID guidDocumentSummarySection2 =
|
||
|
{ 0xd5cdd505,
|
||
|
0x2e9c, 0x101b,
|
||
|
{ 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae } };
|
||
|
|
||
|
// *Global Info*
|
||
|
|
||
|
GUID guidGlobalInfo =
|
||
|
{ 0x56616F00,
|
||
|
0xC154, 0x11ce,
|
||
|
{ 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
|
||
|
|
||
|
// *Image Contents*
|
||
|
|
||
|
GUID guidImageContents =
|
||
|
{ 0x56616500,
|
||
|
0xC154, 0x11ce,
|
||
|
{ 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
|
||
|
|
||
|
// *Image Info*
|
||
|
|
||
|
GUID guidImageInfo =
|
||
|
{ 0x56616500,
|
||
|
0xC154, 0x11ce,
|
||
|
{ 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
// Function: RtlGuidToPropertySetName
|
||
|
//
|
||
|
// Synopsis: Map property set GUID to null-terminated UNICODE name string.
|
||
|
//
|
||
|
// The awcname parameter is assumed to be a buffer with room for
|
||
|
// CWC_PROPSETSZ (28) UNICODE characters. The first character
|
||
|
// is always WC_PROPSET0 (0x05), as specified by the OLE Appendix
|
||
|
// B documentation. The colon character normally used as an NT
|
||
|
// stream name separator is not written to the caller's buffer.
|
||
|
//
|
||
|
// No error is possible.
|
||
|
//
|
||
|
// Arguments: IN GUID *pguid -- pointer to GUID to convert
|
||
|
// OUT OLECHAR aocname[] -- output string buffer
|
||
|
//
|
||
|
// Returns: count of non-NULL characters in the output string buffer
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
ULONG PROPSYSAPI PROPAPI
|
||
|
RtlGuidToPropertySetName(
|
||
|
IN GUID const *pguid,
|
||
|
OUT OLECHAR aocname[])
|
||
|
{
|
||
|
ULONG cbitRemain = CBIT_BYTE;
|
||
|
OLECHAR *poc = aocname;
|
||
|
|
||
|
BYTE *pb;
|
||
|
BYTE *pbEnd;
|
||
|
|
||
|
*poc++ = OC_PROPSET0;
|
||
|
|
||
|
// -----------------------
|
||
|
// Check for special-cases
|
||
|
// -----------------------
|
||
|
|
||
|
// Note: CCH_PROPSET includes the OC_PROPSET0, and sizeof(osz...)
|
||
|
// includes the trailing '\0', so sizeof(osz...) is ok because the
|
||
|
// OC_PROPSET0 character compensates for the trailing NULL character.
|
||
|
|
||
|
// Is this the SummaryInformation propset?
|
||
|
PROPASSERT(CCH_PROPSET >= sizeof(oszSummary)/sizeof(OLECHAR));
|
||
|
|
||
|
if (*pguid == guidSummary)
|
||
|
{
|
||
|
RtlCopyMemory(poc, oszSummary, sizeof(oszSummary));
|
||
|
return(sizeof(oszSummary)/sizeof(OLECHAR));
|
||
|
}
|
||
|
|
||
|
// Is this The DocumentSummaryInformation or User-Defined propset?
|
||
|
PROPASSERT(CCH_PROPSET >= sizeof(oszDocumentSummary)/sizeof(OLECHAR));
|
||
|
|
||
|
if (*pguid == guidDocumentSummary || *pguid == guidDocumentSummarySection2)
|
||
|
{
|
||
|
RtlCopyMemory(poc, oszDocumentSummary, sizeof(oszDocumentSummary));
|
||
|
return(sizeof(oszDocumentSummary)/sizeof(OLECHAR));
|
||
|
}
|
||
|
|
||
|
// Is this the Global Info propset?
|
||
|
PROPASSERT(CCH_PROPSET >= sizeof(oszGlobalInfo)/sizeof(OLECHAR));
|
||
|
if (*pguid == guidGlobalInfo)
|
||
|
{
|
||
|
RtlCopyMemory(poc, oszGlobalInfo, cboszGlobalInfo);
|
||
|
return(cboszGlobalInfo/sizeof(OLECHAR));
|
||
|
}
|
||
|
|
||
|
// Is this the Image Contents propset?
|
||
|
PROPASSERT(CCH_PROPSET >= sizeof(oszImageContents)/sizeof(OLECHAR));
|
||
|
if (*pguid == guidImageContents)
|
||
|
{
|
||
|
RtlCopyMemory(poc, oszImageContents, cboszImageContents);
|
||
|
return(cboszImageContents/sizeof(OLECHAR));
|
||
|
}
|
||
|
|
||
|
// Is this the Image Info propset?
|
||
|
PROPASSERT(CCH_PROPSET >= sizeof(oszImageInfo)/sizeof(OLECHAR));
|
||
|
if (*pguid == guidImageInfo)
|
||
|
{
|
||
|
RtlCopyMemory(poc, oszImageInfo, cboszImageInfo);
|
||
|
return(cboszImageInfo/sizeof(OLECHAR));
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------
|
||
|
// Calculate the string-ized GUID
|
||
|
// ------------------------------
|
||
|
|
||
|
// If this is a big-endian system, we need to convert
|
||
|
// the GUID to little-endian for the conversion.
|
||
|
|
||
|
#if BIGENDIAN
|
||
|
GUID guidByteSwapped = *pguid;
|
||
|
PropByteSwap( &guidByteSwapped );
|
||
|
pguid = &guidByteSwapped;
|
||
|
#endif
|
||
|
|
||
|
// Point to the beginning and ending of the GUID
|
||
|
pb = (BYTE*) pguid;
|
||
|
pbEnd = pb + sizeof(*pguid);
|
||
|
|
||
|
// Walk 'pb' through each byte of the GUID.
|
||
|
|
||
|
while (pb < pbEnd)
|
||
|
{
|
||
|
ULONG i = *pb >> (CBIT_BYTE - cbitRemain);
|
||
|
|
||
|
if (cbitRemain >= CBIT_CHARMASK)
|
||
|
{
|
||
|
*poc = MapChar(i);
|
||
|
if (cbitRemain == CBIT_BYTE && *poc >= (OLECHAR)'a'
|
||
|
&& *poc <= ((OLECHAR)'z'))
|
||
|
{
|
||
|
*poc += (OLECHAR) ( ((OLECHAR)'A') - ((OLECHAR)'a') );
|
||
|
}
|
||
|
poc++;
|
||
|
cbitRemain -= CBIT_CHARMASK;
|
||
|
if (cbitRemain == 0)
|
||
|
{
|
||
|
pb++;
|
||
|
cbitRemain = CBIT_BYTE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (++pb < pbEnd)
|
||
|
{
|
||
|
i |= *pb << cbitRemain;
|
||
|
}
|
||
|
*poc++ = MapChar(i);
|
||
|
cbitRemain += CBIT_BYTE - CBIT_CHARMASK;
|
||
|
}
|
||
|
} // while (pb < pbEnd)
|
||
|
|
||
|
*poc = OLESTR( '\0' );
|
||
|
return(CCH_PROPSET);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
// Function: RtlPropertySetNameToGuid
|
||
|
//
|
||
|
// Synopsis: Map non null-terminated UNICODE string to a property set GUID.
|
||
|
//
|
||
|
// If the name is not properly formed as per
|
||
|
// RtlGuidToPropertySetName(), STATUS_INVALID_PARAMETER is
|
||
|
// returned. The pguid parameter is assumed to point to a buffer
|
||
|
// with room for a GUID structure.
|
||
|
//
|
||
|
// Arguments: IN ULONG cocname -- count of OLECHARs in string to convert
|
||
|
// IN OLECHAR aocname[] -- input string to convert
|
||
|
// OUT GUID *pguid -- pointer to buffer for converted GUID
|
||
|
//
|
||
|
// Returns: NTSTATUS
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS PROPSYSAPI PROPAPI
|
||
|
RtlPropertySetNameToGuid(
|
||
|
IN ULONG cocname,
|
||
|
IN OLECHAR const aocname[],
|
||
|
OUT GUID *pguid)
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
||
|
|
||
|
OLECHAR const *poc = aocname;
|
||
|
|
||
|
if (poc[0] == OC_PROPSET0)
|
||
|
{
|
||
|
// -----------------------
|
||
|
// Check for Special-Cases
|
||
|
// -----------------------
|
||
|
|
||
|
// Note: cocname includes the OC_PROPSET0, and sizeof(osz...)
|
||
|
// includes the trailing OLESTR('\0'), but the comparison excludes both
|
||
|
// the leading OC_PROPSET0 and the trailing '\0'.
|
||
|
|
||
|
// Is this SummaryInformation?
|
||
|
if (cocname == sizeof(oszSummary)/sizeof(OLECHAR) &&
|
||
|
ocsnicmp(&poc[1], oszSummary, cocname - 1) == 0)
|
||
|
{
|
||
|
*pguid = guidSummary;
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
// Is this DocumentSummaryInformation?
|
||
|
if (cocname == sizeof(oszDocumentSummary)/sizeof(OLECHAR) &&
|
||
|
ocsnicmp(&poc[1], oszDocumentSummary, cocname - 1) == 0)
|
||
|
{
|
||
|
*pguid = guidDocumentSummary;
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
// Is this Global Info?
|
||
|
if (cocname == cboszGlobalInfo/sizeof(OLECHAR) &&
|
||
|
ocsnicmp(&poc[1], oszGlobalInfo, cocname - 1) == 0)
|
||
|
{
|
||
|
*pguid = guidGlobalInfo;
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
// Is this Image Info?
|
||
|
if (cocname == cboszImageInfo/sizeof(OLECHAR) &&
|
||
|
ocsnicmp(&poc[1], oszImageInfo, cocname - 1) == 0)
|
||
|
{
|
||
|
*pguid = guidImageInfo;
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
// Is this Image Contents?
|
||
|
if (cocname == cboszImageContents/sizeof(OLECHAR) &&
|
||
|
ocsnicmp(&poc[1], oszImageContents, cocname - 1) == 0)
|
||
|
{
|
||
|
*pguid = guidImageContents;
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
// ------------------
|
||
|
// Calculate the GUID
|
||
|
// ------------------
|
||
|
|
||
|
// None of the special-cases hit, so we must calculate
|
||
|
// the GUID from the name.
|
||
|
|
||
|
if (cocname == CCH_PROPSET)
|
||
|
{
|
||
|
ULONG cbit;
|
||
|
BYTE *pb = (BYTE *) pguid - 1;
|
||
|
|
||
|
RtlZeroMemory(pguid, sizeof(*pguid));
|
||
|
for (cbit = 0; cbit < CBIT_GUID; cbit += CBIT_CHARMASK)
|
||
|
{
|
||
|
ULONG cbitUsed = cbit % CBIT_BYTE;
|
||
|
ULONG cbitStored;
|
||
|
OLECHAR oc;
|
||
|
|
||
|
if (cbitUsed == 0)
|
||
|
{
|
||
|
pb++;
|
||
|
}
|
||
|
|
||
|
oc = *++poc - (OLECHAR)'A'; // assume upper case
|
||
|
// for wchar (unsigned) -ve values becomes a large number
|
||
|
// but for char, which is signed, -ve is -ve
|
||
|
if (oc > CALPHACHARS || oc < 0)
|
||
|
{
|
||
|
// oops, try lower case
|
||
|
oc += (OLECHAR) ( ((OLECHAR)'A') - ((OLECHAR)'a'));
|
||
|
if (oc > CALPHACHARS || oc < 0)
|
||
|
{
|
||
|
// must be a digit
|
||
|
oc += ((OLECHAR)'a') - ((OLECHAR)'0') + CALPHACHARS;
|
||
|
if (oc > CHARMASK)
|
||
|
{
|
||
|
goto Exit; // invalid character
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*pb |= (BYTE) (oc << cbitUsed);
|
||
|
|
||
|
cbitStored = min(CBIT_BYTE - cbitUsed, CBIT_CHARMASK);
|
||
|
|
||
|
// If the translated bits wouldn't all fit in the current byte
|
||
|
|
||
|
if (cbitStored < CBIT_CHARMASK)
|
||
|
{
|
||
|
oc >>= CBIT_BYTE - cbitUsed;
|
||
|
|
||
|
if (cbit + cbitStored == CBIT_GUID)
|
||
|
{
|
||
|
if (oc != 0)
|
||
|
{
|
||
|
goto Exit; // extra bits
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
pb++;
|
||
|
|
||
|
*pb |= (BYTE) oc;
|
||
|
}
|
||
|
} // for (cbit = 0; cbit < CBIT_GUID; cbit += CBIT_CHARMASK)
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
// If byte-swapping is necessary, do so now on the calculated
|
||
|
// GUID.
|
||
|
|
||
|
PropByteSwap( pguid );
|
||
|
|
||
|
} // if (cocname == CCH_PROPSET)
|
||
|
} // if (poc[0] == OC_PROPSET0)
|
||
|
|
||
|
|
||
|
// ----
|
||
|
// Exit
|
||
|
// ----
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
inline BOOLEAN
|
||
|
_Compare_VT_BOOL(VARIANT_BOOL bool1, VARIANT_BOOL bool2)
|
||
|
{
|
||
|
// Allow any non-zero value to match any non-zero value
|
||
|
|
||
|
return((bool1 == FALSE) == (bool2 == FALSE));
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
_Compare_VT_CF(CLIPDATA *pclipdata1, CLIPDATA *pclipdata2)
|
||
|
{
|
||
|
BOOLEAN fSame;
|
||
|
|
||
|
if (pclipdata1 != NULL && pclipdata2 != NULL)
|
||
|
{
|
||
|
fSame = ( pclipdata1->cbSize == pclipdata2->cbSize
|
||
|
&&
|
||
|
pclipdata1->ulClipFmt == pclipdata2->ulClipFmt );
|
||
|
|
||
|
if (fSame)
|
||
|
{
|
||
|
if (pclipdata1->pClipData != NULL && pclipdata2->pClipData != NULL)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pclipdata1->pClipData,
|
||
|
pclipdata2->pClipData,
|
||
|
CBPCLIPDATA(*pclipdata1)
|
||
|
) == 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// They're the same if both are NULL, or if
|
||
|
// they have a zero length (if they have a zero
|
||
|
// length, either one may or may not be NULL, but they're
|
||
|
// still considered the same).
|
||
|
|
||
|
fSame = pclipdata1->pClipData == pclipdata2->pClipData
|
||
|
||
|
||
|
CBPCLIPDATA(*pclipdata1) == 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fSame = pclipdata1 == pclipdata2;
|
||
|
}
|
||
|
return(fSame);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
// Function: RtlCompareVariants, public
|
||
|
//
|
||
|
// Synopsis: Compare two passed PROPVARIANTs -- case sensitive for strings
|
||
|
//
|
||
|
// Arguments: [CodePage] -- CodePage
|
||
|
// [pvar1] -- pointer to PROPVARIANT
|
||
|
// [pvar2] -- pointer to PROPVARIANT
|
||
|
//
|
||
|
// Returns: TRUE if identical, else FALSE
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef _MAC
|
||
|
EXTERN_C // The Mac linker doesn't seem to be able to export with C++ decorations
|
||
|
#endif
|
||
|
|
||
|
BOOLEAN PROPSYSAPI PROPAPI
|
||
|
PropTestCompareVariants(
|
||
|
USHORT CodePage,
|
||
|
PROPVARIANT const *pvar1,
|
||
|
PROPVARIANT const *pvar2)
|
||
|
{
|
||
|
if (pvar1->vt != pvar2->vt)
|
||
|
{
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
BOOLEAN fSame;
|
||
|
ULONG i;
|
||
|
|
||
|
switch (pvar1->vt)
|
||
|
{
|
||
|
case VT_EMPTY:
|
||
|
case VT_NULL:
|
||
|
fSame = TRUE;
|
||
|
break;
|
||
|
|
||
|
case VT_I1:
|
||
|
case VT_UI1:
|
||
|
fSame = pvar1->bVal == pvar2->bVal;
|
||
|
break;
|
||
|
|
||
|
case VT_I2:
|
||
|
case VT_UI2:
|
||
|
fSame = pvar1->iVal == pvar2->iVal;
|
||
|
break;
|
||
|
|
||
|
case VT_BOOL:
|
||
|
fSame = _Compare_VT_BOOL(pvar1->boolVal, pvar2->boolVal);
|
||
|
break;
|
||
|
|
||
|
case VT_I4:
|
||
|
case VT_UI4:
|
||
|
case VT_R4:
|
||
|
case VT_ERROR:
|
||
|
fSame = pvar1->lVal == pvar2->lVal;
|
||
|
break;
|
||
|
|
||
|
case VT_I8:
|
||
|
case VT_UI8:
|
||
|
case VT_R8:
|
||
|
case VT_CY:
|
||
|
case VT_DATE:
|
||
|
case VT_FILETIME:
|
||
|
fSame = pvar1->hVal.HighPart == pvar2->hVal.HighPart
|
||
|
&&
|
||
|
pvar1->hVal.LowPart == pvar2->hVal.LowPart;
|
||
|
break;
|
||
|
|
||
|
case VT_CLSID:
|
||
|
fSame = memcmp(pvar1->puuid, pvar2->puuid, sizeof(CLSID)) == 0;
|
||
|
break;
|
||
|
|
||
|
case VT_BLOB:
|
||
|
case VT_BLOB_OBJECT:
|
||
|
fSame = ( pvar1->blob.cbSize == pvar2->blob.cbSize );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->blob.pBlobData,
|
||
|
pvar2->blob.pBlobData,
|
||
|
pvar1->blob.cbSize) == 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_CF:
|
||
|
fSame = _Compare_VT_CF(pvar1->pclipdata, pvar2->pclipdata);
|
||
|
break;
|
||
|
|
||
|
case VT_BSTR:
|
||
|
if (pvar1->bstrVal != NULL && pvar2->bstrVal != NULL)
|
||
|
{
|
||
|
fSame = ( BSTRLEN(pvar1->bstrVal) == BSTRLEN(pvar2->bstrVal) );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->bstrVal,
|
||
|
pvar2->bstrVal,
|
||
|
BSTRLEN(pvar1->bstrVal)) == 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fSame = pvar1->bstrVal == pvar2->bstrVal;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_LPSTR:
|
||
|
if (pvar1->pszVal != NULL && pvar2->pszVal != NULL)
|
||
|
{
|
||
|
fSame = strcmp(pvar1->pszVal, pvar2->pszVal) == 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fSame = pvar1->pszVal == pvar2->pszVal;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_STREAM:
|
||
|
case VT_STREAMED_OBJECT:
|
||
|
case VT_STORAGE:
|
||
|
case VT_STORED_OBJECT:
|
||
|
case VT_LPWSTR:
|
||
|
if (pvar1->pwszVal != NULL && pvar2->pwszVal != NULL)
|
||
|
{
|
||
|
fSame = Prop_wcscmp(pvar1->pwszVal, pvar2->pwszVal) == 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fSame = pvar1->pwszVal == pvar2->pwszVal;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_I1:
|
||
|
case VT_VECTOR | VT_UI1:
|
||
|
fSame = ( pvar1->caub.cElems == pvar2->caub.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->caub.pElems,
|
||
|
pvar2->caub.pElems,
|
||
|
pvar1->caub.cElems * sizeof(pvar1->caub.pElems[0])) == 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_I2:
|
||
|
case VT_VECTOR | VT_UI2:
|
||
|
fSame = ( pvar1->cai.cElems == pvar2->cai.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->cai.pElems,
|
||
|
pvar2->cai.pElems,
|
||
|
pvar1->cai.cElems * sizeof(pvar1->cai.pElems[0])) == 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_BOOL:
|
||
|
fSame = ( pvar1->cabool.cElems == pvar2->cabool.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
for (i = 0; i < pvar1->cabool.cElems; i++)
|
||
|
{
|
||
|
fSame = _Compare_VT_BOOL(
|
||
|
pvar1->cabool.pElems[i],
|
||
|
pvar2->cabool.pElems[i]);
|
||
|
if (!fSame)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_I4:
|
||
|
case VT_VECTOR | VT_UI4:
|
||
|
case VT_VECTOR | VT_R4:
|
||
|
case VT_VECTOR | VT_ERROR:
|
||
|
fSame = ( pvar1->cal.cElems == pvar2->cal.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->cal.pElems,
|
||
|
pvar2->cal.pElems,
|
||
|
pvar1->cal.cElems * sizeof(pvar1->cal.pElems[0])) == 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_I8:
|
||
|
case VT_VECTOR | VT_UI8:
|
||
|
case VT_VECTOR | VT_R8:
|
||
|
case VT_VECTOR | VT_CY:
|
||
|
case VT_VECTOR | VT_DATE:
|
||
|
case VT_VECTOR | VT_FILETIME:
|
||
|
fSame = ( pvar1->cah.cElems == pvar2->cah.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->cah.pElems,
|
||
|
pvar2->cah.pElems,
|
||
|
pvar1->cah.cElems *
|
||
|
sizeof(pvar1->cah.pElems[0])) == 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_CLSID:
|
||
|
fSame = ( pvar1->cauuid.cElems == pvar2->cauuid.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->cauuid.pElems,
|
||
|
pvar2->cauuid.pElems,
|
||
|
pvar1->cauuid.cElems *
|
||
|
sizeof(pvar1->cauuid.pElems[0])) == 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_CF:
|
||
|
fSame = ( pvar1->caclipdata.cElems == pvar2->caclipdata.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
for (i = 0; i < pvar1->caclipdata.cElems; i++)
|
||
|
{
|
||
|
fSame = _Compare_VT_CF(
|
||
|
&pvar1->caclipdata.pElems[i],
|
||
|
&pvar2->caclipdata.pElems[i]);
|
||
|
if (!fSame)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_BSTR:
|
||
|
fSame = ( pvar1->cabstr.cElems == pvar2->cabstr.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
for (i = 0; i < pvar1->cabstr.cElems; i++)
|
||
|
{
|
||
|
if (pvar1->cabstr.pElems[i] != NULL &&
|
||
|
pvar2->cabstr.pElems[i] != NULL)
|
||
|
{
|
||
|
fSame = ( BSTRLEN(pvar1->cabstr.pElems[i])
|
||
|
==
|
||
|
BSTRLEN(pvar2->cabstr.pElems[i]) );
|
||
|
if (fSame)
|
||
|
{
|
||
|
fSame = memcmp(
|
||
|
pvar1->cabstr.pElems[i],
|
||
|
pvar2->cabstr.pElems[i],
|
||
|
BSTRLEN(pvar1->cabstr.pElems[i])) == 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fSame = pvar1->cabstr.pElems[i] == pvar2->cabstr.pElems[i];
|
||
|
}
|
||
|
if (!fSame)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_LPSTR:
|
||
|
fSame = ( pvar1->calpstr.cElems == pvar2->calpstr.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
for (i = 0; i < pvar1->calpstr.cElems; i++)
|
||
|
{
|
||
|
if (pvar1->calpstr.pElems[i] != NULL &&
|
||
|
pvar2->calpstr.pElems[i] != NULL)
|
||
|
{
|
||
|
fSame = strcmp(
|
||
|
pvar1->calpstr.pElems[i],
|
||
|
pvar2->calpstr.pElems[i]) == 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fSame = pvar1->calpstr.pElems[i] ==
|
||
|
pvar2->calpstr.pElems[i];
|
||
|
}
|
||
|
if (!fSame)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_LPWSTR:
|
||
|
fSame = ( pvar1->calpwstr.cElems == pvar2->calpwstr.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
for (i = 0; i < pvar1->calpwstr.cElems; i++)
|
||
|
{
|
||
|
if (pvar1->calpwstr.pElems[i] != NULL &&
|
||
|
pvar2->calpwstr.pElems[i] != NULL)
|
||
|
{
|
||
|
fSame = Prop_wcscmp(
|
||
|
pvar1->calpwstr.pElems[i],
|
||
|
pvar2->calpwstr.pElems[i]) == 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fSame = pvar1->calpwstr.pElems[i] ==
|
||
|
pvar2->calpwstr.pElems[i];
|
||
|
}
|
||
|
if (!fSame)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_VECTOR | VT_VARIANT:
|
||
|
fSame = ( pvar1->capropvar.cElems == pvar2->capropvar.cElems );
|
||
|
if (fSame)
|
||
|
{
|
||
|
for (i = 0; i < pvar1->capropvar.cElems; i++)
|
||
|
{
|
||
|
fSame = PropTestCompareVariants(
|
||
|
CodePage,
|
||
|
&pvar1->capropvar.pElems[i],
|
||
|
&pvar2->capropvar.pElems[i]);
|
||
|
if (!fSame)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
PROPASSERT(!"Invalid type for PROPVARIANT Comparison");
|
||
|
fSame = FALSE;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
return(fSame);
|
||
|
}
|
||
|
|