blob: 4e099318f5c3ec9ce306f87cafab3246dbd70268 [file] [log] [blame]
/*
* Unit test suite for MAPI property functions
*
* Copyright 2004 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "wine/test.h"
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winerror.h"
#include "winnt.h"
#include "initguid.h"
#include "mapiutil.h"
#include "mapitags.h"
#include "mapi32_test.h"
static HMODULE hMapi32 = 0;
static SCODE (WINAPI *pScInitMapiUtil)(ULONG);
static void (WINAPI *pDeinitMapiUtil)(void);
static SCODE (WINAPI *pPropCopyMore)(LPSPropValue,LPSPropValue,ALLOCATEMORE*,LPVOID);
static ULONG (WINAPI *pUlPropSize)(LPSPropValue);
static BOOL (WINAPI *pFPropContainsProp)(LPSPropValue,LPSPropValue,ULONG);
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);
static BOOL (WINAPI *pFBadRowSet)(LPSRowSet);
static ULONG (WINAPI *pFBadPropTag)(ULONG);
static ULONG (WINAPI *pFBadRow)(LPSRow);
static ULONG (WINAPI *pFBadProp)(LPSPropValue);
static ULONG (WINAPI *pFBadColumnSet)(LPSPropTagArray);
static SCODE (WINAPI *pCreateIProp)(LPCIID,ALLOCATEBUFFER*,ALLOCATEMORE*,
FREEBUFFER*,LPVOID,LPPROPDATA*);
static SCODE (WINAPI *pMAPIAllocateBuffer)(ULONG, LPVOID);
static SCODE (WINAPI *pMAPIAllocateMore)(ULONG, LPVOID, LPVOID);
static SCODE (WINAPI *pMAPIInitialize)(LPVOID);
static SCODE (WINAPI *pMAPIFreeBuffer)(LPVOID);
static void (WINAPI *pMAPIUninitialize)(void);
static BOOL InitFuncPtrs(void)
{
hMapi32 = LoadLibraryA("mapi32.dll");
pPropCopyMore = (void*)GetProcAddress(hMapi32, "PropCopyMore@16");
pUlPropSize = (void*)GetProcAddress(hMapi32, "UlPropSize@4");
pFPropContainsProp = (void*)GetProcAddress(hMapi32, "FPropContainsProp@12");
pFPropCompareProp = (void*)GetProcAddress(hMapi32, "FPropCompareProp@12");
pLPropCompareProp = (void*)GetProcAddress(hMapi32, "LPropCompareProp@8");
pPpropFindProp = (void*)GetProcAddress(hMapi32, "PpropFindProp@12");
pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
pScCopyProps = (void*)GetProcAddress(hMapi32, "ScCopyProps@16");
pScRelocProps = (void*)GetProcAddress(hMapi32, "ScRelocProps@20");
pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12");
pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8");
pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8");
pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4");
pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4");
pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4");
pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4");
pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4");
pCreateIProp = (void*)GetProcAddress(hMapi32, "CreateIProp@24");
pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
pDeinitMapiUtil = (void*)GetProcAddress(hMapi32, "DeinitMapiUtil@0");
pMAPIAllocateBuffer = (void*)GetProcAddress(hMapi32, "MAPIAllocateBuffer");
pMAPIAllocateMore = (void*)GetProcAddress(hMapi32, "MAPIAllocateMore");
pMAPIFreeBuffer = (void*)GetProcAddress(hMapi32, "MAPIFreeBuffer");
pMAPIInitialize = (void*)GetProcAddress(hMapi32, "MAPIInitialize");
pMAPIUninitialize = (void*)GetProcAddress(hMapi32, "MAPIUninitialize");
return pMAPIAllocateBuffer && pMAPIAllocateMore && pMAPIFreeBuffer &&
pScInitMapiUtil && pDeinitMapiUtil;
}
/* FIXME: Test PT_I2, PT_I4, PT_R4, PT_R8, PT_CURRENCY, PT_APPTIME, PT_SYSTIME,
* PT_ERROR, PT_BOOLEAN, PT_I8, and PT_CLSID. */
static ULONG ptTypes[] = {
PT_STRING8, PT_BINARY, PT_UNICODE
};
static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
{
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static void test_PropCopyMore(void)
{
static char szHiA[] = "Hi!";
static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
SPropValue *lpDest = NULL, *lpSrc = NULL;
ULONG i;
SCODE scode;
if (!pPropCopyMore)
{
win_skip("PropCopyMore is not available\n");
return;
}
scode = pMAPIAllocateBuffer(sizeof(SPropValue), &lpDest);
ok(scode == S_OK, "Expected MAPIAllocateBuffer to return S_OK, got 0x%x\n", scode);
if (FAILED(scode))
{
skip("MAPIAllocateBuffer failed\n");
return;
}
scode = pMAPIAllocateMore(sizeof(SPropValue), lpDest, &lpSrc);
ok(scode == S_OK, "Expected MAPIAllocateMore to return S_OK, got 0x%x\n", scode);
if (FAILED(scode))
{
skip("MAPIAllocateMore failed\n");
return;
}
for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
{
lpSrc->ulPropTag = ptTypes[i];
switch (ptTypes[i])
{
case PT_STRING8:
lpSrc->Value.lpszA = szHiA;
break;
case PT_UNICODE:
lpSrc->Value.lpszW = szHiW;
break;
case PT_BINARY:
lpSrc->Value.bin.cb = 4;
lpSrc->Value.bin.lpb = (LPBYTE)szHiA;
break;
}
memset(lpDest, 0xff, sizeof(SPropValue));
scode = pPropCopyMore(lpDest, lpSrc, (ALLOCATEMORE*)pMAPIAllocateMore, lpDest);
ok(!scode && lpDest->ulPropTag == lpSrc->ulPropTag,
"PropCopyMore: Expected 0x0,%d, got 0x%08x,%d\n",
lpSrc->ulPropTag, scode, lpDest->ulPropTag);
if (SUCCEEDED(scode))
{
switch (ptTypes[i])
{
case PT_STRING8:
ok(lstrcmpA(lpDest->Value.lpszA, lpSrc->Value.lpszA) == 0,
"PropCopyMore: Ascii string differs\n");
break;
case PT_UNICODE:
ok(strcmpW(lpDest->Value.lpszW, lpSrc->Value.lpszW) == 0,
"PropCopyMore: Unicode string differs\n");
break;
case PT_BINARY:
ok(lpDest->Value.bin.cb == 4 &&
!memcmp(lpSrc->Value.bin.lpb, lpDest->Value.bin.lpb, 4),
"PropCopyMore: Binary array differs\n");
break;
}
}
}
/* Since all allocations are linked, freeing lpDest frees everything */
scode = pMAPIFreeBuffer(lpDest);
ok(scode == S_OK, "Expected MAPIFreeBuffer to return S_OK, got 0x%x\n", scode);
}
static void test_UlPropSize(void)
{
static char szHiA[] = "Hi!";
static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
LPSTR buffa[2];
LPWSTR buffw[2];
SBinary buffbin[2];
ULONG pt, exp, res;
if (!pUlPropSize)
{
win_skip("UlPropSize is not available\n");
return;
}
for (pt = 0; pt < PROP_ID_INVALID; pt++)
{
SPropValue pv;
memset(&pv, 0 ,sizeof(pv));
pv.ulPropTag = pt;
exp = 1u; /* Default to one item for non-MV properties */
switch (PROP_TYPE(pt))
{
case PT_MV_I2: pv.Value.MVi.cValues = exp = 2;
case PT_I2: exp *= sizeof(USHORT); break;
case PT_MV_I4: pv.Value.MVl.cValues = exp = 2;
case PT_I4: exp *= sizeof(LONG); break;
case PT_MV_R4: pv.Value.MVflt.cValues = exp = 2;
case PT_R4: exp *= sizeof(float); break;
case PT_MV_DOUBLE: pv.Value.MVdbl.cValues = exp = 2;
case PT_R8: exp *= sizeof(double); break;
case PT_MV_CURRENCY: pv.Value.MVcur.cValues = exp = 2;
case PT_CURRENCY: exp *= sizeof(CY); break;
case PT_MV_APPTIME: pv.Value.MVat.cValues = exp = 2;
case PT_APPTIME: exp *= sizeof(double); break;
case PT_MV_SYSTIME: pv.Value.MVft.cValues = exp = 2;
case PT_SYSTIME: exp *= sizeof(FILETIME); break;
case PT_ERROR: exp = sizeof(SCODE); break;
case PT_BOOLEAN: exp = sizeof(USHORT); break;
case PT_OBJECT: exp = 0; break;
case PT_MV_I8: pv.Value.MVli.cValues = exp = 2;
case PT_I8: exp *= sizeof(LONG64); break;
#if 0
/* My version of native mapi returns 0 for PT_MV_CLSID even if a valid
* array is given. This _has_ to be a bug, so Wine does
* the right thing(tm) and we don't test it here.
*/
case PT_MV_CLSID: pv.Value.MVguid.cValues = exp = 2;
#endif
case PT_CLSID: exp *= sizeof(GUID); break;
case PT_STRING8:
pv.Value.lpszA = szHiA;
exp = 4;
break;
case PT_UNICODE:
pv.Value.lpszW = szHiW;
exp = 4 * sizeof(WCHAR);
break;
case PT_BINARY:
pv.Value.bin.cb = exp = 19;
break;
case PT_MV_STRING8:
pv.Value.MVszA.cValues = 2;
pv.Value.MVszA.lppszA = buffa;
buffa[0] = szHiA;
buffa[1] = szHiA;
exp = 8;
break;
case PT_MV_UNICODE:
pv.Value.MVszW.cValues = 2;
pv.Value.MVszW.lppszW = buffw;
buffw[0] = szHiW;
buffw[1] = szHiW;
exp = 8 * sizeof(WCHAR);
break;
case PT_MV_BINARY:
pv.Value.MVbin.cValues = 2;
pv.Value.MVbin.lpbin = buffbin;
buffbin[0].cb = 19;
buffbin[1].cb = 1;
exp = 20;
break;
default:
exp = 0;
}
res = pUlPropSize(&pv);
ok(res == exp,
"pt= %d: Expected %d, got %d\n", pt, exp, res);
}
}
static void test_FPropContainsProp(void)
{
static char szFull[] = "Full String";
static char szFullLower[] = "full string";
static char szPrefix[] = "Full";
static char szPrefixLower[] = "full";
static char szSubstring[] = "ll St";
static char szSubstringLower[] = "ll st";
SPropValue pvLeft, pvRight;
ULONG pt;
BOOL bRet;
if (!pFPropContainsProp)
{
win_skip("FPropContainsProp is not available\n");
return;
}
/* Ensure that only PT_STRING8 and PT_BINARY are handled */
for (pt = 0; pt < PROP_ID_INVALID; pt++)
{
if (pt == PT_STRING8 || pt == PT_BINARY)
continue; /* test these later */
memset(&pvLeft, 0 ,sizeof(pvLeft));
memset(&pvRight, 0 ,sizeof(pvRight));
pvLeft.ulPropTag = pvRight.ulPropTag = pt;
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
ok(bRet == FALSE, "pt= %d: Expected FALSE, got %d\n", pt, bRet);
}
/* test the various flag combinations */
pvLeft.ulPropTag = pvRight.ulPropTag = PT_STRING8;
pvLeft.Value.lpszA = szFull;
pvRight.Value.lpszA = szFull;
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
ok(bRet == TRUE, "(full,full)[] match failed\n");
pvRight.Value.lpszA = szPrefix;
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
ok(bRet == FALSE, "(full,prefix)[] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == TRUE, "(full,prefix)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == TRUE, "(full,prefix)[SUBSTRING] match failed\n");
pvRight.Value.lpszA = szPrefixLower;
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == FALSE, "(full,prefixlow)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == FALSE, "(full,prefixlow)[SUBSTRING] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
ok(bRet == TRUE, "(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
ok(bRet == TRUE, "(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
pvRight.Value.lpszA = szSubstring;
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
ok(bRet == FALSE, "(full,substr)[] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == FALSE, "(full,substr)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == TRUE, "(full,substr)[SUBSTRING] match failed\n");
pvRight.Value.lpszA = szSubstringLower;
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == FALSE, "(full,substrlow)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == FALSE, "(full,substrlow)[SUBSTRING] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
ok(bRet == FALSE, "(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
ok(bRet == TRUE, "(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
pvRight.Value.lpszA = szFullLower;
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
ok(bRet == TRUE, "(full,fulllow)[IGNORECASE] match failed\n");
pvLeft.ulPropTag = pvRight.ulPropTag = PT_BINARY;
pvLeft.Value.bin.lpb = (LPBYTE)szFull;
pvRight.Value.bin.lpb = (LPBYTE)szFull;
pvLeft.Value.bin.cb = pvRight.Value.bin.cb = strlen(szFull);
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
ok(bRet == TRUE, "bin(full,full)[] match failed\n");
pvRight.Value.bin.lpb = (LPBYTE)szPrefix;
pvRight.Value.bin.cb = strlen(szPrefix);
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
ok(bRet == FALSE, "bin(full,prefix)[] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == TRUE, "bin(full,prefix)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == TRUE, "bin(full,prefix)[SUBSTRING] match failed\n");
pvRight.Value.bin.lpb = (LPBYTE)szPrefixLower;
pvRight.Value.bin.cb = strlen(szPrefixLower);
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
ok(bRet == FALSE, "bin(full,prefixlow)[PREFIX|IGNORECASE] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
ok(bRet == FALSE, "bin(full,prefixlow)[SUBSTRING|IGNORECASE] match failed\n");
pvRight.Value.bin.lpb = (LPBYTE)szSubstring;
pvRight.Value.bin.cb = strlen(szSubstring);
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
ok(bRet == FALSE, "bin(full,substr)[] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == FALSE, "bin(full,substr)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == TRUE, "bin(full,substr)[SUBSTRING] match failed\n");
pvRight.Value.bin.lpb = (LPBYTE)szSubstringLower;
pvRight.Value.bin.cb = strlen(szSubstringLower);
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX);
ok(bRet == FALSE, "bin(full,substrlow)[PREFIX] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING);
ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_PREFIX|FL_IGNORECASE);
ok(bRet == FALSE, "bin(full,substrlow)[PREFIX|IGNORECASE] match failed\n");
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_SUBSTRING|FL_IGNORECASE);
ok(bRet == FALSE, "bin(full,substrlow)[SUBSTRING|IGNORECASE] match failed\n");
pvRight.Value.bin.lpb = (LPBYTE)szFullLower;
pvRight.Value.bin.cb = strlen(szFullLower);
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING|FL_IGNORECASE);
ok(bRet == FALSE, "bin(full,fulllow)[IGNORECASE] match failed\n");
}
typedef struct tagFPropCompareProp_Result
{
SHORT lVal;
SHORT rVal;
ULONG relOp;
BOOL bRet;
} FPropCompareProp_Result;
static const FPropCompareProp_Result FPCProp_Results[] =
{
{ 1, 2, RELOP_LT, TRUE },
{ 1, 1, RELOP_LT, FALSE },
{ 2, 1, RELOP_LT, FALSE },
{ 1, 2, RELOP_LE, TRUE },
{ 1, 1, RELOP_LE, TRUE },
{ 2, 1, RELOP_LE, FALSE },
{ 1, 2, RELOP_GT, FALSE },
{ 1, 1, RELOP_GT, FALSE },
{ 2, 1, RELOP_GT, TRUE },
{ 1, 2, RELOP_GE, FALSE },
{ 1, 1, RELOP_GE, TRUE },
{ 2, 1, RELOP_GE, TRUE },
{ 1, 2, RELOP_EQ, FALSE },
{ 1, 1, RELOP_EQ, TRUE },
{ 2, 1, RELOP_EQ, FALSE }
};
static const char *relops[] = { "RELOP_LT", "RELOP_LE", "RELOP_GT", "RELOP_GE", "RELOP_EQ" };
static void test_FPropCompareProp(void)
{
SPropValue pvLeft, pvRight;
GUID lguid, rguid;
char lbuffa[2], rbuffa[2];
WCHAR lbuffw[2], rbuffw[2];
ULONG i, j;
BOOL bRet, bExp;
if (!pFPropCompareProp)
{
win_skip("FPropCompareProp is not available\n");
return;
}
lbuffa[1] = '\0';
rbuffa[1] = '\0';
lbuffw[1] = '\0';
rbuffw[1] = '\0';
for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
{
pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
for (j = 0; j < sizeof(FPCProp_Results)/sizeof(FPCProp_Results[0]); j++)
{
SHORT lVal = FPCProp_Results[j].lVal;
SHORT rVal = FPCProp_Results[j].rVal;
bExp = FPCProp_Results[j].bRet;
switch (ptTypes[i])
{
case PT_BOOLEAN:
/* Boolean values have no concept of less or greater than, only equality */
if ((lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_LT) ||
(lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_LE)||
(lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_GT)||
(lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_GE)||
(lVal == 1 && rVal == 2 && FPCProp_Results[j].relOp == RELOP_EQ)||
(lVal == 2 && rVal == 1 && FPCProp_Results[j].relOp == RELOP_EQ))
bExp = !bExp;
/* Fall through ... */
case PT_I2:
pvLeft.Value.i = lVal;
pvRight.Value.i = rVal;
break;
case PT_ERROR:
case PT_I4:
pvLeft.Value.l = lVal;
pvRight.Value.l = rVal;
break;
case PT_R4:
pvLeft.Value.flt = lVal;
pvRight.Value.flt = rVal;
break;
case PT_APPTIME:
case PT_R8:
pvLeft.Value.dbl = lVal;
pvRight.Value.dbl = rVal;
break;
case PT_CURRENCY:
pvLeft.Value.cur.int64 = lVal;
pvRight.Value.cur.int64 = rVal;
break;
case PT_SYSTIME:
pvLeft.Value.ft.dwLowDateTime = lVal;
pvLeft.Value.ft.dwHighDateTime = 0;
pvRight.Value.ft.dwLowDateTime = rVal;
pvRight.Value.ft.dwHighDateTime = 0;
break;
case PT_I8:
pvLeft.Value.li.u.LowPart = lVal;
pvLeft.Value.li.u.HighPart = 0;
pvRight.Value.li.u.LowPart = rVal;
pvRight.Value.li.u.HighPart = 0;
break;
case PT_CLSID:
memset(&lguid, 0, sizeof(GUID));
memset(&rguid, 0, sizeof(GUID));
lguid.Data4[7] = lVal;
rguid.Data4[7] = rVal;
pvLeft.Value.lpguid = &lguid;
pvRight.Value.lpguid = &rguid;
break;
case PT_STRING8:
pvLeft.Value.lpszA = lbuffa;
pvRight.Value.lpszA = rbuffa;
lbuffa[0] = '0' + lVal;
rbuffa[0] = '0' + rVal;
break;
case PT_UNICODE:
pvLeft.Value.lpszW = lbuffw;
pvRight.Value.lpszW = rbuffw;
lbuffw[0] = '0' + lVal;
rbuffw[0] = '0' + rVal;
break;
case PT_BINARY:
pvLeft.Value.bin.cb = 1;
pvRight.Value.bin.cb = 1;
pvLeft.Value.bin.lpb = (LPBYTE)lbuffa;
pvRight.Value.bin.lpb = (LPBYTE)rbuffa;
lbuffa[0] = lVal;
rbuffa[0] = rVal;
break;
}
bRet = pFPropCompareProp(&pvLeft, FPCProp_Results[j].relOp, &pvRight);
ok(bRet == bExp,
"pt %d (%d,%d,%s): expected %d, got %d\n", ptTypes[i],
FPCProp_Results[j].lVal, FPCProp_Results[j].rVal,
relops[FPCProp_Results[j].relOp], bExp, bRet);
}
}
}
typedef struct tagLPropCompareProp_Result
{
SHORT lVal;
SHORT rVal;
INT iRet;
} LPropCompareProp_Result;
static const LPropCompareProp_Result LPCProp_Results[] =
{
{ 1, 2, -1 },
{ 1, 1, 0 },
{ 2, 1, 1 },
};
static void test_LPropCompareProp(void)
{
SPropValue pvLeft, pvRight;
GUID lguid, rguid;
char lbuffa[2], rbuffa[2];
WCHAR lbuffw[2], rbuffw[2];
ULONG i, j;
INT iRet, iExp;
if (!pLPropCompareProp)
{
win_skip("LPropCompareProp is not available\n");
return;
}
lbuffa[1] = '\0';
rbuffa[1] = '\0';
lbuffw[1] = '\0';
rbuffw[1] = '\0';
for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
{
pvLeft.ulPropTag = pvRight.ulPropTag = ptTypes[i];
for (j = 0; j < sizeof(LPCProp_Results)/sizeof(LPCProp_Results[0]); j++)
{
SHORT lVal = LPCProp_Results[j].lVal;
SHORT rVal = LPCProp_Results[j].rVal;
iExp = LPCProp_Results[j].iRet;
switch (ptTypes[i])
{
case PT_BOOLEAN:
/* Boolean values have no concept of less or greater than, only equality */
if (lVal && rVal)
iExp = 0;
/* Fall through ... */
case PT_I2:
pvLeft.Value.i = lVal;
pvRight.Value.i = rVal;
break;
case PT_ERROR:
case PT_I4:
pvLeft.Value.l = lVal;
pvRight.Value.l = rVal;
break;
case PT_R4:
pvLeft.Value.flt = lVal;
pvRight.Value.flt = rVal;
break;
case PT_APPTIME:
case PT_R8:
pvLeft.Value.dbl = lVal;
pvRight.Value.dbl = rVal;
break;
case PT_CURRENCY:
pvLeft.Value.cur.int64 = lVal;
pvRight.Value.cur.int64 = rVal;
break;
case PT_SYSTIME:
pvLeft.Value.ft.dwLowDateTime = lVal;
pvLeft.Value.ft.dwHighDateTime = 0;
pvRight.Value.ft.dwLowDateTime = rVal;
pvRight.Value.ft.dwHighDateTime = 0;
break;
case PT_I8:
pvLeft.Value.li.u.LowPart = lVal;
pvLeft.Value.li.u.HighPart = 0;
pvRight.Value.li.u.LowPart = rVal;
pvRight.Value.li.u.HighPart = 0;
break;
case PT_CLSID:
memset(&lguid, 0, sizeof(GUID));
memset(&rguid, 0, sizeof(GUID));
lguid.Data4[7] = lVal;
rguid.Data4[7] = rVal;
pvLeft.Value.lpguid = &lguid;
pvRight.Value.lpguid = &rguid;
break;
case PT_STRING8:
pvLeft.Value.lpszA = lbuffa;
pvRight.Value.lpszA = rbuffa;
lbuffa[0] = '0' + lVal;
rbuffa[0] = '0' + rVal;
break;
case PT_UNICODE:
pvLeft.Value.lpszW = lbuffw;
pvRight.Value.lpszW = rbuffw;
lbuffw[0] = '0' + lVal;
rbuffw[0] = '0' + rVal;
break;
case PT_BINARY:
pvLeft.Value.bin.cb = 1;
pvRight.Value.bin.cb = 1;
pvLeft.Value.bin.lpb = (LPBYTE)lbuffa;
pvRight.Value.bin.lpb = (LPBYTE)rbuffa;
lbuffa[0] = lVal;
rbuffa[0] = rVal;
break;
}
iRet = pLPropCompareProp(&pvLeft, &pvRight);
ok(iRet == iExp,
"pt %d (%d,%d): expected %d, got %d\n", ptTypes[i],
LPCProp_Results[j].lVal, LPCProp_Results[j].rVal, iExp, iRet);
}
}
}
static void test_PpropFindProp(void)
{
SPropValue pvProp, *pRet;
ULONG i;
if (!pPpropFindProp)
{
win_skip("PpropFindProp is not available\n");
return;
}
for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
{
pvProp.ulPropTag = ptTypes[i];
pRet = pPpropFindProp(&pvProp, 1u, ptTypes[i]);
ok(pRet == &pvProp,
"PpropFindProp[%d]: Didn't find existing property\n",
ptTypes[i]);
pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]);
ok(pRet == NULL, "PpropFindProp[%d]: Found nonexistent property\n",
ptTypes[i]);
}
pvProp.ulPropTag = PROP_TAG(PT_I2, 1u);
pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 0u));
ok(pRet == NULL, "PpropFindProp[UNSPECIFIED]: Matched on different id\n");
pRet = pPpropFindProp(&pvProp, 1u, PROP_TAG(PT_UNSPECIFIED, 1u));
ok(pRet == &pvProp, "PpropFindProp[UNSPECIFIED]: Didn't match id\n");
}
static void test_ScCountProps(void)
{
static char szHiA[] = "Hi!";
static WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
static const ULONG ULHILEN = 4; /* chars in szHiA/W incl. NUL */
LPSTR buffa[3];
LPWSTR buffw[3];
SBinary buffbin[3];
GUID iids[4], *iid = iids;
SCODE res;
ULONG pt, exp, ulRet;
BOOL success = TRUE;
if (!pScCountProps)
{
win_skip("ScCountProps is not available\n");
return;
}
for (pt = 0; pt < PROP_ID_INVALID && success; pt++)
{
SPropValue pv;
memset(&pv, 0 ,sizeof(pv));
pv.ulPropTag = PROP_TAG(pt, 1u);
switch (PROP_TYPE(pt))
{
case PT_I2:
case PT_I4:
case PT_R4:
case PT_R8:
case PT_CURRENCY:
case PT_APPTIME:
case PT_SYSTIME:
case PT_ERROR:
case PT_BOOLEAN:
case PT_OBJECT:
case PT_I8:
exp = sizeof(pv);
break;
case PT_CLSID:
pv.Value.lpguid = iid;
exp = sizeof(GUID) + sizeof(pv);
break;
case PT_STRING8:
pv.Value.lpszA = szHiA;
exp = 4 + sizeof(pv);
break;
case PT_UNICODE:
pv.Value.lpszW = szHiW;
exp = 4 * sizeof(WCHAR) + sizeof(pv);
break;
case PT_BINARY:
pv.Value.bin.cb = 2;
pv.Value.bin.lpb = (LPBYTE)iid;
exp = 2 + sizeof(pv);
break;
case PT_MV_I2:
pv.Value.MVi.cValues = 3;
pv.Value.MVi.lpi = (SHORT*)iid;
exp = 3 * sizeof(SHORT) + sizeof(pv);
break;
case PT_MV_I4:
pv.Value.MVl.cValues = 3;
pv.Value.MVl.lpl = (LONG*)iid;
exp = 3 * sizeof(LONG) + sizeof(pv);
break;
case PT_MV_I8:
pv.Value.MVli.cValues = 3;
pv.Value.MVli.lpli = (LARGE_INTEGER*)iid;
exp = 3 * sizeof(LARGE_INTEGER) + sizeof(pv);
break;
case PT_MV_R4:
pv.Value.MVflt.cValues = 3;
pv.Value.MVflt.lpflt = (float*)iid;
exp = 3 * sizeof(float) + sizeof(pv);
break;
case PT_MV_APPTIME:
case PT_MV_R8:
pv.Value.MVdbl.cValues = 3;
pv.Value.MVdbl.lpdbl = (double*)iid;
exp = 3 * sizeof(double) + sizeof(pv);
break;
case PT_MV_CURRENCY:
pv.Value.MVcur.cValues = 3;
pv.Value.MVcur.lpcur = (CY*)iid;
exp = 3 * sizeof(CY) + sizeof(pv);
break;
case PT_MV_SYSTIME:
pv.Value.MVft.cValues = 3;
pv.Value.MVft.lpft = (FILETIME*)iid;
exp = 3 * sizeof(CY) + sizeof(pv);
break;
case PT_MV_STRING8:
pv.Value.MVszA.cValues = 3;
pv.Value.MVszA.lppszA = buffa;
buffa[0] = szHiA;
buffa[1] = szHiA;
buffa[2] = szHiA;
exp = ULHILEN * 3 + 3 * sizeof(char*) + sizeof(pv);
break;
case PT_MV_UNICODE:
pv.Value.MVszW.cValues = 3;
pv.Value.MVszW.lppszW = buffw;
buffw[0] = szHiW;
buffw[1] = szHiW;
buffw[2] = szHiW;
exp = ULHILEN * 3 * sizeof(WCHAR) + 3 * sizeof(WCHAR*) + sizeof(pv);
break;
case PT_MV_BINARY:
pv.Value.MVbin.cValues = 3;
pv.Value.MVbin.lpbin = buffbin;
buffbin[0].cb = 17;
buffbin[0].lpb = (LPBYTE)&iid;
buffbin[1].cb = 2;
buffbin[1].lpb = (LPBYTE)&iid;
buffbin[2].cb = 1;
buffbin[2].lpb = (LPBYTE)&iid;
exp = 20 + sizeof(pv) + sizeof(SBinary) * 3;
break;
default:
exp = 0;
}
ulRet = 0xffffffff;
res = pScCountProps(1, &pv, &ulRet);
if (!exp) {
success = res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff;
ok(success, "pt= %d: Expected failure, got %d, ret=0x%08X\n",
pt, ulRet, res);
}
else {
success = res == S_OK && ulRet == exp;
ok(success, "pt= %d: Expected %d, got %d, ret=0x%08X\n",
pt, exp, ulRet, res);
}
}
}
static void test_ScCopyRelocProps(void)
{
static char szTestA[] = "Test";
char buffer[512], buffer2[512], *lppszA[1];
SPropValue pvProp, *lpResProp = (LPSPropValue)buffer;
ULONG ulCount;
SCODE sc;
if (!pScCopyProps || !pScRelocProps)
{
win_skip("SPropValue copy functions are not available\n");
return;
}
pvProp.ulPropTag = PROP_TAG(PT_MV_STRING8, 1u);
lppszA[0] = szTestA;
pvProp.Value.MVszA.cValues = 1;
pvProp.Value.MVszA.lppszA = lppszA;
ulCount = 0;
sc = pScCopyProps(1, &pvProp, buffer, &ulCount);
ok(sc == S_OK, "wrong ret %d\n", sc);
if(sc == S_OK)
{
ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag);
ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues);
ok(lpResProp->Value.MVszA.lppszA[0] == buffer + sizeof(SPropValue) + sizeof(char*),
"wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]);
ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5, "wrong count %d\n", ulCount);
ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA),
"wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]);
}
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, "wrong ret %d\n", sc);
if(sc == S_OK)
{
ok(lpResProp->ulPropTag == pvProp.ulPropTag, "wrong tag %x\n",lpResProp->ulPropTag);
ok(lpResProp->Value.MVszA.cValues == 1, "wrong cValues %d\n", lpResProp->Value.MVszA.cValues);
ok(lpResProp->Value.MVszA.lppszA[0] == buffer2 + sizeof(SPropValue) + sizeof(char*),
"wrong lppszA[0] %p\n",lpResProp->Value.MVszA.lppszA[0]);
/* 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.
*/
ok(ulCount == sizeof(SPropValue) + sizeof(char*) + 5 || ulCount == sizeof(SPropValue) + 5,
"wrong count %d\n", ulCount);
ok(!strcmp(lpResProp->Value.MVszA.lppszA[0], szTestA),
"wrong string '%s'\n", lpResProp->Value.MVszA.lppszA[0]);
}
/* Native crashes with lpNew or lpOld set to NULL so skip testing this */
}
static void test_LpValFindProp(void)
{
SPropValue pvProp, *pRet;
ULONG i;
if (!pLpValFindProp)
{
win_skip("LpValFindProp is not available\n");
return;
}
for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
{
pvProp.ulPropTag = PROP_TAG(ptTypes[i], 1u);
pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 1u), 1u, &pvProp);
ok(pRet == &pvProp,
"LpValFindProp[%d]: Didn't find existing property id/type\n",
ptTypes[i]);
pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp);
ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent property id\n",
ptTypes[i]);
pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp);
ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent property id/type\n",
ptTypes[i]);
pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp);
ok(pRet == &pvProp,
"LpValFindProp[%d]: Didn't find existing property id\n",
ptTypes[i]);
}
}
static void test_FBadRglpszA(void)
{
LPSTR lpStrs[4];
static CHAR szString[] = "A String";
BOOL bRet;
if (!pFBadRglpszA)
{
win_skip("FBadRglpszA is not available\n");
return;
}
bRet = pFBadRglpszA(NULL, 10);
ok(bRet == TRUE, "FBadRglpszA(Null): expected TRUE, got FALSE\n");
lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
bRet = pFBadRglpszA(lpStrs, 4);
ok(bRet == TRUE, "FBadRglpszA(Nulls): expected TRUE, got FALSE\n");
lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
bRet = pFBadRglpszA(lpStrs, 3);
ok(bRet == FALSE, "FBadRglpszA(valid): expected FALSE, got TRUE\n");
bRet = pFBadRglpszA(lpStrs, 4);
ok(bRet == TRUE, "FBadRglpszA(1 invalid): expected TRUE, got FALSE\n");
}
static void test_FBadRglpszW(void)
{
LPWSTR lpStrs[4];
static WCHAR szString[] = { 'A',' ','S','t','r','i','n','g','\0' };
BOOL bRet;
if (!pFBadRglpszW)
{
win_skip("FBadRglpszW is not available\n");
return;
}
bRet = pFBadRglpszW(NULL, 10);
ok(bRet == TRUE, "FBadRglpszW(Null): expected TRUE, got FALSE\n");
lpStrs[0] = lpStrs[1] = lpStrs[2] = lpStrs[3] = NULL;
bRet = pFBadRglpszW(lpStrs, 4);
ok(bRet == TRUE, "FBadRglpszW(Nulls): expected TRUE, got FALSE\n");
lpStrs[0] = lpStrs[1] = lpStrs[2] = szString;
bRet = pFBadRglpszW(lpStrs, 3);
ok(bRet == FALSE, "FBadRglpszW(valid): expected FALSE, got TRUE\n");
bRet = pFBadRglpszW(lpStrs, 4);
ok(bRet == TRUE, "FBadRglpszW(1 invalid): expected TRUE, got FALSE\n");
}
static void test_FBadRowSet(void)
{
ULONG ulRet;
if (!pFBadRowSet)
{
win_skip("FBadRowSet is not available\n");
return;
}
ulRet = pFBadRowSet(NULL);
ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
/* FIXME */
}
static void test_FBadPropTag(void)
{
ULONG pt, res;
if (!pFBadPropTag)
{
win_skip("FBadPropTag is not available\n");
return;
}
for (pt = 0; pt < PROP_ID_INVALID; pt++)
{
BOOL bBad = TRUE;
switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
{
case PT_UNSPECIFIED:
case PT_NULL: case PT_I2: case PT_I4: case PT_R4:
case PT_R8: case PT_CURRENCY: case PT_APPTIME:
case PT_ERROR: case PT_BOOLEAN: case PT_OBJECT:
case PT_I8: case PT_STRING8: case PT_UNICODE:
case PT_SYSTIME: case PT_CLSID: case PT_BINARY:
bBad = FALSE;
}
res = pFBadPropTag(pt);
if (bBad)
ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
else
ok(res == 0,
"pt= %d: Expected zero, got %d\n", pt, res);
}
}
static void test_FBadRow(void)
{
ULONG ulRet;
if (!pFBadRow)
{
win_skip("FBadRow is not available\n");
return;
}
ulRet = pFBadRow(NULL);
ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
/* FIXME */
}
static void test_FBadProp(void)
{
static WCHAR szEmpty[] = { '\0' };
GUID iid;
ULONG pt, res;
SPropValue pv;
if (!pFBadProp)
{
win_skip("FBadProp is not available\n");
return;
}
for (pt = 0; pt < PROP_ID_INVALID; pt++)
{
BOOL bBad = TRUE;
memset(&pv, 0, sizeof(pv));
pv.ulPropTag = pt;
/* Note that MV values are valid below because their array count is 0,
* so no pointers are validated.
*/
switch (PROP_TYPE(pt))
{
case (MV_FLAG|PT_UNSPECIFIED):
case PT_UNSPECIFIED:
case (MV_FLAG|PT_NULL):
case PT_NULL:
case PT_MV_I2:
case PT_I2:
case PT_MV_I4:
case PT_I4:
case PT_MV_I8:
case PT_I8:
case PT_MV_R4:
case PT_R4:
case PT_MV_R8:
case PT_R8:
case PT_MV_CURRENCY:
case PT_CURRENCY:
case PT_MV_APPTIME:
case PT_APPTIME:
case (MV_FLAG|PT_ERROR):
case PT_ERROR:
case (MV_FLAG|PT_BOOLEAN):
case PT_BOOLEAN:
case (MV_FLAG|PT_OBJECT):
case PT_OBJECT:
case PT_MV_STRING8:
case PT_MV_UNICODE:
case PT_MV_SYSTIME:
case PT_SYSTIME:
case PT_MV_BINARY:
case PT_BINARY:
case PT_MV_CLSID:
bBad = FALSE;
break;
case PT_STRING8:
case PT_UNICODE:
pv.Value.lpszW = szEmpty;
bBad = FALSE;
break;
case PT_CLSID:
pv.Value.lpguid = &iid;
bBad = FALSE;
break;
}
res = pFBadProp(&pv);
if (bBad)
ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
else
ok(res == 0,
"pt= %d: Expected zero, got %d\n", pt, res);
}
}
static void test_FBadColumnSet(void)
{
SPropTagArray pta;
ULONG pt, res;
if (!pFBadColumnSet)
{
win_skip("FBadColumnSet is not available\n");
return;
}
res = pFBadColumnSet(NULL);
ok(res != 0, "(null): Expected non-zero, got 0\n");
pta.cValues = 1;
for (pt = 0; pt < PROP_ID_INVALID; pt++)
{
BOOL bBad = TRUE;
pta.aulPropTag[0] = pt;
switch (pt & (~MV_FLAG & PROP_TYPE_MASK))
{
case PT_UNSPECIFIED:
case PT_NULL:
case PT_I2:
case PT_I4:
case PT_R4:
case PT_R8:
case PT_CURRENCY:
case PT_APPTIME:
case PT_BOOLEAN:
case PT_OBJECT:
case PT_I8:
case PT_STRING8:
case PT_UNICODE:
case PT_SYSTIME:
case PT_CLSID:
case PT_BINARY:
bBad = FALSE;
}
if (pt == (MV_FLAG|PT_ERROR))
bBad = FALSE;
res = pFBadColumnSet(&pta);
if (bBad)
ok(res != 0, "pt= %d: Expected non-zero, got 0\n", pt);
else
ok(res == 0,
"pt= %d: Expected zero, got %d\n", pt, res);
}
}
static void test_IProp(void)
{
IPropData *lpIProp;
LPMAPIERROR lpError;
LPSPropProblemArray lpProbs;
LPSPropValue lpProps;
LPSPropTagArray lpTags;
SPropValue pvs[2];
SizedSPropTagArray(2,tags);
ULONG access[2], count;
SCODE sc;
if (!pCreateIProp)
{
win_skip("CreateIProp is not available\n");
return;
}
memset(&tags, 0 , sizeof(tags));
/* Create the object */
lpIProp = NULL;
sc = pCreateIProp(&IID_IMAPIPropData, (ALLOCATEBUFFER *)pMAPIAllocateBuffer, (ALLOCATEMORE*)pMAPIAllocateMore,
(FREEBUFFER *)pMAPIFreeBuffer, NULL, &lpIProp);
ok(sc == S_OK && lpIProp,
"CreateIProp: expected S_OK, non-null, got 0x%08X,%p\n", sc, lpIProp);
if (sc != S_OK || !lpIProp)
return;
/* GetLastError - No errors set */
lpError = NULL;
sc = IPropData_GetLastError(lpIProp, E_INVALIDARG, 0, &lpError);
ok(sc == S_OK && !lpError,
"GetLastError: Expected S_OK, null, got 0x%08X,%p\n", sc, lpError);
/* Get prop tags - succeeds returning 0 items */
lpTags = NULL;
sc = IPropData_GetPropList(lpIProp, 0, &lpTags);
ok(sc == S_OK && lpTags && lpTags->cValues == 0,
"GetPropList(empty): Expected S_OK, non-null, 0, got 0x%08X,%p,%d\n",
sc, lpTags, lpTags ? lpTags->cValues : 0);
if (lpTags)
pMAPIFreeBuffer(lpTags);
/* Get props - succeeds returning 0 items */
lpProps = NULL;
count = 0;
tags.cValues = 1;
tags.aulPropTag[0] = PR_IMPORTANCE;
sc = IPropData_GetProps(lpIProp, (LPSPropTagArray)&tags, 0, &count, &lpProps);
ok(sc == MAPI_W_ERRORS_RETURNED && lpProps && count == 1,
"GetProps(empty): Expected ERRORS_RETURNED, non-null, 1, got 0x%08X,%p,%d\n",
sc, lpProps, count);
if (lpProps && count > 0)
{
ok(lpProps[0].ulPropTag == CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR),
"GetProps(empty): Expected %x, got %x\n",
CHANGE_PROP_TYPE(PR_IMPORTANCE,PT_ERROR), lpProps[0].ulPropTag);
pMAPIFreeBuffer(lpProps);
}
/* Add (NULL) - Can't add NULLs */
lpProbs = NULL;
pvs[0].ulPropTag = PROP_TAG(PT_NULL,0x01);
sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs,
"SetProps(): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n",
sc, lpProbs);
/* Add (OBJECT) - Can't add OBJECTs */
lpProbs = NULL;
pvs[0].ulPropTag = PROP_TAG(PT_OBJECT,0x01);
sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
ok(sc == MAPI_E_INVALID_PARAMETER && !lpProbs,
"SetProps(OBJECT): Expected INVALID_PARAMETER, null, got 0x%08X,%p\n",
sc, lpProbs);
/* Add - Adds value */
lpProbs = NULL;
pvs[0].ulPropTag = PR_IMPORTANCE;
sc = IPropData_SetProps(lpIProp, 1, pvs, &lpProbs);
ok(sc == S_OK && !lpProbs,
"SetProps(ERROR): Expected S_OK, null, got 0x%08X,%p\n", sc, lpProbs);
/* Get prop list - returns 1 item */
lpTags = NULL;
IPropData_GetPropList(lpIProp, 0, &lpTags);
ok(sc == S_OK && lpTags && lpTags->cValues == 1,
"GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n",
sc, lpTags, lpTags ? lpTags->cValues : 0);
if (lpTags && lpTags->cValues > 0)
{
ok(lpTags->aulPropTag[0] == PR_IMPORTANCE,
"GetPropList: Expected %x, got %x\n",
PR_IMPORTANCE, lpTags->aulPropTag[0]);
pMAPIFreeBuffer(lpTags);
}
/* Set access to read and write */
sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE);
ok(sc == S_OK, "SetObjAccess(WRITE): Expected S_OK got 0x%08X\n", sc);
tags.cValues = 1;
tags.aulPropTag[0] = PR_IMPORTANCE;
/* Set item access (bad access) - Fails */
access[0] = 0;
sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
ok(sc == MAPI_E_INVALID_PARAMETER,
"SetPropAccess(0): Expected INVALID_PARAMETER got 0x%08X\n",sc);
access[0] = IPROP_READWRITE;
sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
ok(sc == MAPI_E_INVALID_PARAMETER,
"SetPropAccess(RW): Expected INVALID_PARAMETER got 0x%08X\n",sc);
access[0] = IPROP_CLEAN;
sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
ok(sc == MAPI_E_INVALID_PARAMETER,
"SetPropAccess(C): Expected INVALID_PARAMETER got 0x%08X\n",sc);
/* Set item access to read/write/clean */
tags.cValues = 1;
tags.aulPropTag[0] = PR_IMPORTANCE;
access[0] = IPROP_READWRITE|IPROP_CLEAN;
sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
ok(sc == S_OK, "SetPropAccess(RW/C): Expected S_OK got 0x%08X\n",sc);
/* Set object access to read only */
sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READONLY);
ok(sc == S_OK, "SetObjAccess(READ): Expected S_OK got 0x%08X\n", sc);
/* Set item access to read/write/dirty - doesn't care about RO object */
access[0] = IPROP_READONLY|IPROP_DIRTY;
sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
ok(sc == S_OK, "SetPropAccess(WRITE): Expected S_OK got 0x%08X\n", sc);
/* Delete any item when set to read only - Error */
lpProbs = NULL;
tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
ok(sc == E_ACCESSDENIED && !lpProbs,
"DeleteProps(nonexistent): Expected E_ACCESSDENIED null got 0x%08X %p\n",
sc, lpProbs);
/* Set access to read and write */
sc = IPropData_HrSetObjAccess(lpIProp, IPROP_READWRITE);
ok(sc == S_OK, "SetObjAccess(WRITE): Expected S_OK got 0x%08X\n", sc);
/* Delete nonexistent item - No error */
lpProbs = NULL;
tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
ok(sc == S_OK && !lpProbs,
"DeleteProps(nonexistent): Expected S_OK null got 0x%08X %p\n",
sc, lpProbs);
/* Delete existing item (r/o) - No error, but lpProbs populated */
lpProbs = NULL;
tags.aulPropTag[0] = PR_IMPORTANCE;
sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
ok(sc == S_OK && lpProbs,
"DeleteProps(RO): Expected S_OK non-null got 0x%08X %p\n", sc, lpProbs);
if (lpProbs && lpProbs->cProblem > 0)
{
ok(lpProbs->cProblem == 1 &&
lpProbs->aProblem[0].ulIndex == 0 &&
lpProbs->aProblem[0].ulPropTag == PR_IMPORTANCE &&
lpProbs->aProblem[0].scode == E_ACCESSDENIED,
"DeleteProps(RO): Expected (1,0,%x,%x) got (%d,%x,%x)\n",
PR_IMPORTANCE, E_ACCESSDENIED,
lpProbs->aProblem[0].ulIndex, lpProbs->aProblem[0].ulPropTag,
lpProbs->aProblem[0].scode);
pMAPIFreeBuffer(lpProbs);
}
lpProbs = NULL;
tags.cValues = 1;
tags.aulPropTag[0] = PR_RESPONSE_REQUESTED;
IPropData_HrAddObjProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
ok(sc == S_OK && !lpProbs,
"AddObjProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs);
/* Get prop list - returns 1 item */
lpTags = NULL;
IPropData_GetPropList(lpIProp, 0, &lpTags);
ok(sc == S_OK && lpTags && lpTags->cValues == 1,
"GetPropList: Expected S_OK, non-null, 1, got 0x%08X,%p,%d\n",
sc, lpTags, lpTags ? lpTags->cValues : 0);
if (lpTags && lpTags->cValues > 0)
{
ok(lpTags->aulPropTag[0] == PR_IMPORTANCE,
"GetPropList: Expected %x, got %x\n",
PR_IMPORTANCE, lpTags->aulPropTag[0]);
pMAPIFreeBuffer(lpTags);
}
/* Set item to r/w again */
access[0] = IPROP_READWRITE|IPROP_DIRTY;
sc = IPropData_HrSetPropAccess(lpIProp, (LPSPropTagArray)&tags, access);
ok(sc == S_OK, "SetPropAccess(WRITE): Expected S_OK got 0x%08X\n", sc);
/* Delete existing item (r/w) - No error, no problems */
lpProbs = NULL;
sc = IPropData_DeleteProps(lpIProp, (LPSPropTagArray)&tags, &lpProbs);
ok(sc == S_OK && !lpProbs,
"DeleteProps(RO): Expected S_OK null got 0x%08X %p\n", sc, lpProbs);
/* Free the list */
IPropData_Release(lpIProp);
}
START_TEST(prop)
{
SCODE ret;
if (!HaveDefaultMailClient())
{
win_skip("No default mail client installed\n");
return;
}
if(!InitFuncPtrs())
{
win_skip("Needed functions are not available\n");
return;
}
SetLastError(0xdeadbeef);
ret = pScInitMapiUtil(0);
if ((ret != S_OK) && (GetLastError() == ERROR_PROC_NOT_FOUND))
{
win_skip("ScInitMapiUtil is not implemented\n");
FreeLibrary(hMapi32);
return;
}
else if ((ret == E_FAIL) && (GetLastError() == ERROR_INVALID_HANDLE))
{
win_skip("ScInitMapiUtil doesn't work on some Win98 and WinME systems\n");
FreeLibrary(hMapi32);
return;
}
test_PropCopyMore();
test_UlPropSize();
/* We call MAPIInitialize here for the benefit of native extended MAPI
* providers which crash in the FPropContainsProp tests when MAPIInitialize
* has not been called. Since MAPIInitialize is irrelevant for FPropContainsProp
* on Wine, we do not care whether MAPIInitialize succeeds. */
if (pMAPIInitialize)
ret = pMAPIInitialize(NULL);
test_FPropContainsProp();
if (pMAPIUninitialize && ret == S_OK)
pMAPIUninitialize();
test_FPropCompareProp();
test_LPropCompareProp();
test_PpropFindProp();
test_ScCountProps();
test_ScCopyRelocProps();
test_LpValFindProp();
test_FBadRglpszA();
test_FBadRglpszW();
test_FBadRowSet();
test_FBadPropTag();
test_FBadRow();
test_FBadProp();
test_FBadColumnSet();
test_IProp();
pDeinitMapiUtil();
FreeLibrary(hMapi32);
}