Implement and test ScCopyProps/ScRelocProps.

This commit is contained in:
Jon Griffiths 2004-05-03 20:19:00 +00:00 committed by Alexandre Julliard
parent a56eadc92d
commit d0f9c31c28
3 changed files with 343 additions and 3 deletions

View file

@ -108,8 +108,8 @@
165 stub ScCopyNotifications@16
166 stub ScRelocNotifications@20
170 stdcall ScCountProps@12(long ptr ptr) ScCountProps
171 stub ScCopyProps@16
172 stub ScRelocProps@20
171 stdcall ScCopyProps@16(long ptr ptr ptr) ScCopyProps
172 stdcall ScRelocProps@20(long ptr ptr ptr ptr) ScRelocProps
173 stdcall LpValFindProp@12(long long ptr) LpValFindProp
174 stub ScDupPropset@16
175 stdcall FBadRglpszA@8(ptr long) FBadRglpszA

View file

@ -160,7 +160,7 @@ SCODE WINAPI PropCopyMore(LPSPropValue lpDest, LPSPropValue lpSrc,
ULONG ulStrLen = strlenW(lpSrc->Value.MVszW.lppszW[i]) + 1u;
lpDest->Value.MVszW.lppszW[i] = lpNextStr;
memcpy(lpNextStr, lpSrc->Value.MVszA.lppszA[i], ulStrLen * sizeof(WCHAR));
memcpy(lpNextStr, lpSrc->Value.MVszW.lppszW[i], ulStrLen * sizeof(WCHAR));
lpNextStr += ulStrLen;
}
break;
@ -627,6 +627,281 @@ SCODE WINAPI ScCountProps(INT iCount, LPSPropValue lpProps, ULONG *pcBytes)
return S_OK;
}
/*************************************************************************
* ScCopyProps@16 (MAPI32.171)
*
* Copy an array of property values into a buffer suited for serialisation.
*
* PARAMS
* cValues [I] Number of properties in lpProps
* lpProps [I] Property array to copy
* lpDst [O] Destination for the serialised data
* lpCount [O] If non-NULL, destination for the number of bytes of data written to lpDst
*
* RETURNS
* Success: S_OK. lpDst contains the serialised data from lpProps.
* Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
*
* NOTES
* The resulting property value array is stored in a contigous block starting at lpDst.
*/
SCODE WINAPI ScCopyProps(int cValues, LPSPropValue lpProps, LPVOID lpDst, ULONG *lpCount)
{
LPSPropValue lpDest = (LPSPropValue)lpDst;
char *lpDataDest = (char *)(lpDest + cValues);
ULONG ulLen, i;
TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpDst, lpCount);
if (!lpProps || cValues < 0 || !lpDest)
return MAPI_E_INVALID_PARAMETER;
memcpy(lpDst, lpProps, cValues * sizeof(SPropValue));
for (i = 0; i < cValues; i++)
{
switch (PROP_TYPE(lpProps->ulPropTag))
{
case PT_CLSID:
lpDest->Value.lpguid = (LPGUID)lpDataDest;
memcpy(lpDest->Value.lpguid, lpProps->Value.lpguid, sizeof(GUID));
lpDataDest += sizeof(GUID);
break;
case PT_STRING8:
ulLen = lstrlenA(lpProps->Value.lpszA) + 1u;
lpDest->Value.lpszA = lpDataDest;
memcpy(lpDest->Value.lpszA, lpProps->Value.lpszA, ulLen);
lpDataDest += ulLen;
break;
case PT_UNICODE:
ulLen = (strlenW(lpProps->Value.lpszW) + 1u) * sizeof(WCHAR);
lpDest->Value.lpszW = (LPWSTR)lpDataDest;
memcpy(lpDest->Value.lpszW, lpProps->Value.lpszW, ulLen);
lpDataDest += ulLen;
break;
case PT_BINARY:
lpDest->Value.bin.lpb = (LPBYTE)lpDataDest;
memcpy(lpDest->Value.bin.lpb, lpProps->Value.bin.lpb, lpProps->Value.bin.cb);
lpDataDest += lpProps->Value.bin.cb;
break;
default:
if (lpProps->ulPropTag & MV_FLAG)
{
lpDest->Value.MVi.cValues = lpProps->Value.MVi.cValues;
/* Note: Assignment uses lppszA but covers all cases by union aliasing */
lpDest->Value.MVszA.lppszA = (char**)lpDataDest;
switch (PROP_TYPE(lpProps->ulPropTag))
{
case PT_MV_STRING8:
{
lpDataDest += lpProps->Value.MVszA.cValues * sizeof(char *);
for (i = 0; i < lpProps->Value.MVszA.cValues; i++)
{
ULONG ulStrLen = lstrlenA(lpProps->Value.MVszA.lppszA[i]) + 1u;
lpDest->Value.MVszA.lppszA[i] = lpDataDest;
memcpy(lpDataDest, lpProps->Value.MVszA.lppszA[i], ulStrLen);
lpDataDest += ulStrLen;
}
break;
}
case PT_MV_UNICODE:
{
lpDataDest += lpProps->Value.MVszW.cValues * sizeof(WCHAR *);
for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
{
ULONG ulStrLen = (strlenW(lpProps->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
lpDest->Value.MVszW.lppszW[i] = (LPWSTR)lpDataDest;
memcpy(lpDataDest, lpProps->Value.MVszW.lppszW[i], ulStrLen);
lpDataDest += ulStrLen;
}
break;
}
case PT_MV_BINARY:
{
lpDataDest += lpProps->Value.MVszW.cValues * sizeof(SBinary);
for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
{
lpDest->Value.MVbin.lpbin[i].cb = lpProps->Value.MVbin.lpbin[i].cb;
lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)lpDataDest;
memcpy(lpDataDest, lpProps->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
lpDataDest += lpDest->Value.MVbin.lpbin[i].cb;
}
break;
}
default:
/* No embedded pointers, just copy the data over */
ulLen = UlPropSize(lpProps);
memcpy(lpDest->Value.MVi.lpi, lpProps->Value.MVi.lpi, ulLen);
lpDataDest += ulLen;
break;
}
break;
}
}
lpDest++;
lpProps++;
}
if (lpCount)
*lpCount = lpDataDest - (char *)lpDst;
return S_OK;
}
/*************************************************************************
* ScRelocProps@20 (MAPI32.172)
*
* Relocate the pointers in an array of property values after it has been copied.
*
* PARAMS
* cValues [I] Number of properties in lpProps
* lpProps [O] Property array to relocate the pointers in.
* lpOld [I] Position where the data was copied from
* lpNew [I] Position where the data was copied to
* lpCount [O] If non-NULL, destination for the number of bytes of data at lpDst
*
* RETURNS
* Success: S_OK. Any pointers in lpProps are relocated.
* Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
*
* NOTES
* MSDN states that this function can be used for serialisation by passing
* NULL as either lpOld or lpNew, thus converting any pointers in lpProps
* between offsets and pointers. This does not work in native (it crashes),
* and cannot be made to work in Wine because the original interface design
* is deficient. The only use left for this function is to remap pointers
* in a contigous property array that has been copied with memcpy() to another
* memory location.
*/
SCODE WINAPI ScRelocProps(int cValues, LPSPropValue lpProps, LPVOID lpOld,
LPVOID lpNew, ULONG *lpCount)
{
static const BOOL bBadPtr = TRUE; /* Windows bug - Assumes source is bad */
LPSPropValue lpDest = (LPSPropValue)lpProps;
ULONG ulCount = cValues * sizeof(SPropValue);
ULONG ulLen, i;
TRACE("(%d,%p,%p,%p,%p)\n", cValues, lpProps, lpOld, lpNew, lpCount);
if (!lpProps || cValues < 0 || !lpOld || !lpNew)
return MAPI_E_INVALID_PARAMETER;
/* The reason native doesn't work as MSDN states is that it assumes that
* the lpProps pointer contains valid pointers. This is obviously not
* true if the array is being read back from serialisation (the pointers
* are just offsets). Native can't actually work converting the pointers to
* offsets either, because it converts any array pointers to offsets then
* _dereferences the offset_ in order to convert the array elements!
*
* The code below would handle both cases except that the design of this
* function makes it impossible to know when the pointers in lpProps are
* valid. If both lpOld and lpNew are non-NULL, native reads the pointers
* after converting them, so we must do the same. Its seems this
* functionality was never tested by MS.
*/
#define RELOC_PTR(p) (((char*)(p)) - (char*)lpOld + (char*)lpNew)
for (i = 0; i < cValues; i++)
{
switch (PROP_TYPE(lpDest->ulPropTag))
{
case PT_CLSID:
lpDest->Value.lpguid = (LPGUID)RELOC_PTR(lpDest->Value.lpguid);
ulCount += sizeof(GUID);
break;
case PT_STRING8:
ulLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.lpszA) + 1u;
lpDest->Value.lpszA = (LPSTR)RELOC_PTR(lpDest->Value.lpszA);
if (bBadPtr)
ulLen = lstrlenA(lpDest->Value.lpszA) + 1u;
ulCount += ulLen;
break;
case PT_UNICODE:
ulLen = bBadPtr ? 0 : (lstrlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
lpDest->Value.lpszW = (LPWSTR)RELOC_PTR(lpDest->Value.lpszW);
if (bBadPtr)
ulLen = (strlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
ulCount += ulLen;
break;
case PT_BINARY:
lpDest->Value.bin.lpb = (LPBYTE)RELOC_PTR(lpDest->Value.bin.lpb);
ulCount += lpDest->Value.bin.cb;
break;
default:
if (lpDest->ulPropTag & MV_FLAG)
{
/* Since we have to access the array elements, don't map the
* array unless it is invalid (otherwise, map it at the end)
*/
if (bBadPtr)
lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
switch (PROP_TYPE(lpProps->ulPropTag))
{
case PT_MV_STRING8:
{
ulCount += lpDest->Value.MVszA.cValues * sizeof(char *);
for (i = 0; i < lpDest->Value.MVszA.cValues; i++)
{
ULONG ulStrLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
lpDest->Value.MVszA.lppszA[i] = (LPSTR)RELOC_PTR(lpDest->Value.MVszA.lppszA[i]);
if (bBadPtr)
ulStrLen = lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
ulCount += ulStrLen;
}
break;
}
case PT_MV_UNICODE:
{
ulCount += lpDest->Value.MVszW.cValues * sizeof(WCHAR *);
for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
{
ULONG ulStrLen = bBadPtr ? 0 : (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
lpDest->Value.MVszW.lppszW[i] = (LPWSTR)RELOC_PTR(lpDest->Value.MVszW.lppszW[i]);
if (bBadPtr)
ulStrLen = (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
ulCount += ulStrLen;
}
break;
}
case PT_MV_BINARY:
{
ulCount += lpDest->Value.MVszW.cValues * sizeof(SBinary);
for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
{
lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)RELOC_PTR(lpDest->Value.MVbin.lpbin[i].lpb);
ulCount += lpDest->Value.MVbin.lpbin[i].cb;
}
break;
}
default:
ulCount += UlPropSize(lpDest);
break;
}
if (!bBadPtr)
lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
break;
}
}
lpDest++;
}
if (lpCount)
*lpCount = ulCount;
return S_OK;
}
/*************************************************************************
* LpValFindProp@12 (MAPI32.173)
*

View file

@ -41,6 +41,8 @@ static BOOL (WINAPI *pFPropCompareProp)(LPSPropValue,ULONG,LPSPropValue)
static LONG (WINAPI *pLPropCompareProp)(LPSPropValue,LPSPropValue);
static LPSPropValue (WINAPI *pPpropFindProp)(LPSPropValue,ULONG,ULONG);
static SCODE (WINAPI *pScCountProps)(INT,LPSPropValue,ULONG*);
static SCODE (WINAPI *pScCopyProps)(int,LPSPropValue,LPVOID,ULONG*);
static SCODE (WINAPI *pScRelocProps)(int,LPSPropValue,LPVOID,LPVOID,ULONG*);
static LPSPropValue (WINAPI *pLpValFindProp)(ULONG,ULONG,LPSPropValue);
static BOOL (WINAPI *pFBadRglpszA)(LPSTR*,ULONG);
static BOOL (WINAPI *pFBadRglpszW)(LPWSTR*,ULONG);
@ -779,6 +781,68 @@ static void test_ScCountProps(void)
}
static void test_ScCopyRelocProps(void)
{
static const char* szTestA = "Test";
char buffer[512], buffer2[512], *lppszA[1];
SPropValue pvProp, *lpResProp = (LPSPropValue)buffer;
ULONG ulCount;
SCODE sc;
pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16");
pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20");
if (!pScCopyProps || !pScRelocProps)
return;
pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u);
lppszA[0] = (char *)szTestA;
pvProp.Value.MVszA.cValues = 1;
pvProp.Value.MVszA.lppszA = lppszA;
ulCount = 0;
sc = pScCopyProps(1, &pvProp, buffer, &ulCount);
ok(sc == S_OK && lpResProp->ulPropTag == pvProp.ulPropTag &&
lpResProp->Value.MVszA.cValues == 1 &&
lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*) &&
!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA) &&
ulCount == sizeof(SPropValue) + sizeof(char*) + 5,
"CopyProps(str): Expected 0 {1,%lx,%p,%s} %d got 0x%08lx {%ld,%lx,%p,%s} %ld\n",
pvProp.ulPropTag, buffer + sizeof(SPropValue) + sizeof(char*),
szTestA, sizeof(SPropValue) + sizeof(char*) + 5, sc,
lpResProp->Value.MVszA.cValues, lpResProp->ulPropTag,
lpResProp->Value.MVszA.lppszA[0], lpResProp->Value.MVszA.lppszA[0], ulCount);
memcpy(buffer2, buffer, sizeof(buffer));
/* Clear the data in the source buffer. Since pointers in the copied buffer
* refer to the source buffer, this proves that native always assumes that
* the copied buffers pointers are bad (needing to be relocated first).
*/
memset(buffer, 0, sizeof(buffer));
ulCount = 0;
sc = pScRelocProps(1, (LPSPropValue)buffer2, buffer, buffer2, &ulCount);
lpResProp = (LPSPropValue)buffer2;
ok(sc == S_OK && lpResProp->ulPropTag == pvProp.ulPropTag &&
lpResProp->Value.MVszA.cValues == 1 &&
lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*) &&
!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA) &&
/* Native has a bug whereby it calculates the size correctly when copying
* but when relocating does not (presumably it uses UlPropSize() which
* ignores multivalue pointers). Wine returns the correct value.
*/
(ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5),
"RelocProps(str): Expected 0 {1,%lx,%p,%s} %d got 0x%08lx {%ld,%lx,%p,%s} %ld\n",
pvProp.ulPropTag, buffer2 + sizeof(SPropValue) + sizeof(char*),
szTestA, sizeof(SPropValue) + sizeof(char*) + 5, sc,
lpResProp->Value.MVszA.cValues, lpResProp->ulPropTag,
lpResProp->Value.MVszA.lppszA[0], lpResProp->Value.MVszA.lppszA[0], ulCount);
/* Native crashes with lpNew or lpOld set to NULL so skip testing this */
}
static void test_LpValFindProp(void)
{
SPropValue pvProp, *pRet;
@ -1062,6 +1126,7 @@ START_TEST(prop)
test_LPropCompareProp();
test_PpropFindProp();
test_ScCountProps();
test_ScCopyRelocProps();
test_LpValFindProp();
test_FBadRglpszA();
test_FBadRglpszW();