1372 lines
47 KiB
C
1372 lines
47 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
#define NONAMELESSUNION
|
|
#define NONAMELESSSTRUCT
|
|
#include "wine/test.h"
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "winerror.h"
|
|
#include "winnt.h"
|
|
#include "mapiutil.h"
|
|
#include "mapitags.h"
|
|
|
|
static HMODULE hMapi32 = 0;
|
|
|
|
static SCODE (WINAPI *pScInitMapiUtil)(ULONG);
|
|
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 *pMAPIFreeBuffer)(LPVOID);
|
|
|
|
static BOOL InitFuncPtrs(void)
|
|
{
|
|
hMapi32 = LoadLibraryA("mapi32.dll");
|
|
|
|
pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
|
|
pMAPIAllocateBuffer = (void*)GetProcAddress(hMapi32, "MAPIAllocateBuffer");
|
|
pMAPIAllocateMore = (void*)GetProcAddress(hMapi32, "MAPIAllocateMore");
|
|
pMAPIFreeBuffer = (void*)GetProcAddress(hMapi32, "MAPIFreeBuffer");
|
|
if(pScInitMapiUtil && pMAPIAllocateBuffer && pMAPIAllocateMore && pMAPIFreeBuffer)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static ULONG ptTypes[] = {
|
|
PT_I2, PT_I4, PT_R4, PT_R8, PT_CURRENCY, PT_APPTIME, PT_SYSTIME,
|
|
PT_ERROR, PT_BOOLEAN, PT_I8, PT_CLSID, 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 const char *szHiA = "Hi!";
|
|
static const WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
|
|
SPropValue *lpDest = NULL, *lpSrc = NULL;
|
|
ULONG i;
|
|
SCODE scode;
|
|
|
|
pPropCopyMore = (void*)GetProcAddress(hMapi32, "PropCopyMore@16");
|
|
|
|
if (!pPropCopyMore)
|
|
return;
|
|
|
|
scode = pMAPIAllocateBuffer(sizeof(LPSPropValue), (LPVOID *)lpDest);
|
|
if (FAILED(scode))
|
|
return;
|
|
|
|
scode = pMAPIAllocateMore(sizeof(LPSPropValue), lpDest, (LPVOID *)lpSrc);
|
|
if (FAILED(scode))
|
|
return;
|
|
|
|
for (i = 0; i < sizeof(ptTypes)/sizeof(ptTypes[0]); i++)
|
|
{
|
|
lpSrc->ulPropTag = ptTypes[i];
|
|
|
|
switch (ptTypes[i])
|
|
{
|
|
case PT_STRING8:
|
|
lpSrc->Value.lpszA = (char*)szHiA;
|
|
break;
|
|
case PT_UNICODE:
|
|
lpSrc->Value.lpszW = (WCHAR*)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 */
|
|
pMAPIFreeBuffer(lpDest);
|
|
}
|
|
|
|
static void test_UlPropSize(void)
|
|
{
|
|
static const char *szHiA = "Hi!";
|
|
static const WCHAR szHiW[] = { 'H', 'i', '!', '\0' };
|
|
LPSTR buffa[2];
|
|
LPWSTR buffw[2];
|
|
SBinary buffbin[2];
|
|
ULONG pt, exp, res;
|
|
|
|
pUlPropSize = (void*)GetProcAddress(hMapi32, "UlPropSize@4");
|
|
|
|
if (!pUlPropSize)
|
|
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 = (LPSTR)szHiA;
|
|
exp = 4;
|
|
break;
|
|
case PT_UNICODE:
|
|
pv.Value.lpszW = (LPWSTR)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] = (LPSTR)szHiA;
|
|
buffa[1] = (LPSTR)szHiA;
|
|
exp = 8;
|
|
break;
|
|
case PT_MV_UNICODE:
|
|
pv.Value.MVszW.cValues = 2;
|
|
pv.Value.MVszW.lppszW = buffw;
|
|
buffw[0] = (LPWSTR)szHiW;
|
|
buffw[1] = (LPWSTR)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 const char *szFull = "Full String";
|
|
static const char *szFullLower = "full string";
|
|
static const char *szPrefix = "Full";
|
|
static const char *szPrefixLower = "full";
|
|
static const char *szSubstring = "ll St";
|
|
static const char *szSubstringLower = "ll st";
|
|
SPropValue pvLeft, pvRight;
|
|
ULONG pt;
|
|
BOOL bRet;
|
|
|
|
pFPropContainsProp = (void*)GetProcAddress(hMapi32, "FPropContainsProp@12");
|
|
|
|
if (!pFPropContainsProp)
|
|
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 = (LPSTR)szFull;
|
|
pvRight.Value.lpszA = (LPSTR)szFull;
|
|
|
|
bRet = pFPropContainsProp(&pvLeft, &pvRight, FL_FULLSTRING);
|
|
ok(bRet == TRUE, "(full,full)[] match failed\n");
|
|
pvRight.Value.lpszA = (LPSTR)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 = (LPSTR)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 = (LPSTR)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 = (LPSTR)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 = (LPSTR)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;
|
|
|
|
pFPropCompareProp = (void*)GetProcAddress(hMapi32, "FPropCompareProp@12");
|
|
|
|
if (!pFPropCompareProp)
|
|
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;
|
|
|
|
pLPropCompareProp = (void*)GetProcAddress(hMapi32, "LPropCompareProp@8");
|
|
|
|
if (!pLPropCompareProp)
|
|
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;
|
|
|
|
pPpropFindProp = (void*)GetProcAddress(hMapi32, "PpropFindProp@12");
|
|
|
|
if (!pPpropFindProp)
|
|
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 propery\n",
|
|
ptTypes[i]);
|
|
|
|
pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]);
|
|
ok(pRet == NULL, "PpropFindProp[%d]: Found nonexistent propery\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 const char *szHiA = "Hi!";
|
|
static const 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;
|
|
int success = 1;
|
|
|
|
pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
|
|
|
|
if (!pScCountProps)
|
|
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 = (LPSTR)szHiA;
|
|
exp = 4 + sizeof(pv);
|
|
break;
|
|
case PT_UNICODE:
|
|
pv.Value.lpszW = (LPWSTR)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] = (LPSTR)szHiA;
|
|
buffa[1] = (LPSTR)szHiA;
|
|
buffa[2] = (LPSTR)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] = (LPWSTR)szHiW;
|
|
buffw[1] = (LPWSTR)szHiW;
|
|
buffw[2] = (LPWSTR)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 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, "wrong ret %d\n", sc);
|
|
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);
|
|
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;
|
|
|
|
pLpValFindProp = (void*)GetProcAddress(hMapi32, "LpValFindProp@12");
|
|
|
|
if (!pLpValFindProp)
|
|
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 propery id/type\n",
|
|
ptTypes[i]);
|
|
|
|
pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp);
|
|
ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent propery id\n",
|
|
ptTypes[i]);
|
|
|
|
pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp);
|
|
ok(pRet == NULL, "LpValFindProp[%d]: Found nonexistent propery id/type\n",
|
|
ptTypes[i]);
|
|
|
|
pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp);
|
|
ok(pRet == &pvProp, "LpValFindProp[%d]: Didn't find existing propery id\n",
|
|
ptTypes[i]);
|
|
}
|
|
}
|
|
|
|
static void test_FBadRglpszA(void)
|
|
{
|
|
LPSTR lpStrs[4];
|
|
static CHAR szString[] = "A String";
|
|
BOOL bRet;
|
|
|
|
pFBadRglpszA = (void*)GetProcAddress(hMapi32, "FBadRglpszA@8");
|
|
if (!pFBadRglpszA)
|
|
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;
|
|
|
|
pFBadRglpszW = (void*)GetProcAddress(hMapi32, "FBadRglpszW@8");
|
|
if (!pFBadRglpszW)
|
|
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;
|
|
|
|
pFBadRowSet = (void*)GetProcAddress(hMapi32, "FBadRowSet@4");
|
|
if (!pFBadRowSet)
|
|
return;
|
|
|
|
ulRet = pFBadRowSet(NULL);
|
|
ok(ulRet != 0, "FBadRow(null): Expected non-zero, got 0\n");
|
|
|
|
/* FIXME */
|
|
}
|
|
|
|
static void test_FBadPropTag(void)
|
|
{
|
|
ULONG pt, res;
|
|
|
|
pFBadPropTag = (void*)GetProcAddress(hMapi32, "FBadPropTag@4");
|
|
if (!pFBadPropTag)
|
|
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;
|
|
|
|
pFBadRow = (void*)GetProcAddress(hMapi32, "FBadRow@4");
|
|
if (!pFBadRow)
|
|
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;
|
|
|
|
pFBadProp = (void*)GetProcAddress(hMapi32, "FBadProp@4");
|
|
if (!pFBadProp)
|
|
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;
|
|
|
|
pFBadColumnSet = (void*)GetProcAddress(hMapi32, "FBadColumnSet@4");
|
|
if (!pFBadColumnSet)
|
|
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;
|
|
|
|
pCreateIProp = (void*)GetProcAddress(hMapi32, "CreateIProp@24");
|
|
|
|
if (!pCreateIProp)
|
|
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;
|
|
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 NULL's */
|
|
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's */
|
|
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, "SetObjAcess(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,
|
|
"SetPropAcess(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,
|
|
"SetPropAcess(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,
|
|
"SetPropAcess(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, "SetPropAcess(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, "SetObjAcess(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, "SetPropAcess(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, "SetObjAcess(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, "SetPropAcess(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)
|
|
{
|
|
if(!InitFuncPtrs())
|
|
return;
|
|
|
|
pScInitMapiUtil(0);
|
|
|
|
test_PropCopyMore();
|
|
test_UlPropSize();
|
|
test_FPropContainsProp();
|
|
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();
|
|
FreeLibrary(hMapi32);
|
|
}
|