summaryrefslogtreecommitdiffstats
path: root/private/ole32/stg/props/utest/rtlstub.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'private/ole32/stg/props/utest/rtlstub.cxx')
-rw-r--r--private/ole32/stg/props/utest/rtlstub.cxx783
1 files changed, 783 insertions, 0 deletions
diff --git a/private/ole32/stg/props/utest/rtlstub.cxx b/private/ole32/stg/props/utest/rtlstub.cxx
new file mode 100644
index 000000000..3ad6cfaf9
--- /dev/null
+++ b/private/ole32/stg/props/utest/rtlstub.cxx
@@ -0,0 +1,783 @@
+
+
+//+============================================================================
+//
+// 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
+RtlCompareVariants(
+ 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;
+
+#ifdef PROPVAR_VT_I1
+ case VT_I1:
+#endif
+ 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;
+
+#ifdef PROPVAR_VT_I1
+ case VT_VECTOR | VT_I1:
+#endif
+ 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 = RtlCompareVariants(
+ 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);
+}
+