diff --git a/configure b/configure
index d777ef38b13cdbd76e79668ba8ecdf9cb86723cd..755829de6f65a68755a8931e9ede576339bdde5d 100755
--- a/configure
+++ b/configure
@@ -20031,7 +20031,7 @@ MAKE_LIB_RULES=libs/Makelib.rules
 MAKE_PROG_RULES=programs/Makeprog.rules
 
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/amstream/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/capi2032/Makefile dlls/cards/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dbghelp/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnet/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxdiagn/Makefile dlls/dxerr8/Makefile dlls/dxerr9/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/hhctrl.ocx/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvidc32/Makefile dlls/msvideo/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/secur32/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/vdmdbg/Makefile dlls/version/Makefile dlls/version/tests/Makefile dlls/vmm.vxd/Makefile dlls/vnbt.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/taskmgr/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        ac_config_files="$ac_config_files Make.rules dlls/Makedll.rules dlls/Maketest.rules libs/Makelib.rules programs/Makeprog.rules Makefile dlls/Makefile dlls/advapi32/Makefile dlls/advapi32/tests/Makefile dlls/amstream/Makefile dlls/avicap32/Makefile dlls/avifil32/Makefile dlls/cabinet/Makefile dlls/capi2032/Makefile dlls/cards/Makefile dlls/cfgmgr32/Makefile dlls/comcat/Makefile dlls/comctl32/Makefile dlls/comctl32/tests/Makefile dlls/commdlg/Makefile dlls/crtdll/Makefile dlls/crypt32/Makefile dlls/ctl3d/Makefile dlls/d3d8/Makefile dlls/d3d9/Makefile dlls/d3dim/Makefile dlls/d3dx8/Makefile dlls/dbghelp/Makefile dlls/dciman32/Makefile dlls/ddraw/Makefile dlls/ddraw/tests/Makefile dlls/devenum/Makefile dlls/dinput/Makefile dlls/dinput8/Makefile dlls/dmband/Makefile dlls/dmcompos/Makefile dlls/dmime/Makefile dlls/dmloader/Makefile dlls/dmscript/Makefile dlls/dmstyle/Makefile dlls/dmsynth/Makefile dlls/dmusic/Makefile dlls/dmusic32/Makefile dlls/dplay/Makefile dlls/dplayx/Makefile dlls/dpnet/Makefile dlls/dpnhpast/Makefile dlls/dsound/Makefile dlls/dsound/tests/Makefile dlls/dswave/Makefile dlls/dxdiagn/Makefile dlls/dxerr8/Makefile dlls/dxerr9/Makefile dlls/dxguid/Makefile dlls/gdi/Makefile dlls/gdi/tests/Makefile dlls/glu32/Makefile dlls/glut32/Makefile dlls/hhctrl.ocx/Makefile dlls/iccvid/Makefile dlls/icmp/Makefile dlls/ifsmgr.vxd/Makefile dlls/imagehlp/Makefile dlls/imm32/Makefile dlls/iphlpapi/Makefile dlls/iphlpapi/tests/Makefile dlls/kernel/Makefile dlls/kernel/tests/Makefile dlls/lzexpand/Makefile dlls/mapi32/Makefile dlls/mapi32/tests/Makefile dlls/mmdevldr.vxd/Makefile dlls/monodebg.vxd/Makefile dlls/mpr/Makefile dlls/msacm/Makefile dlls/msacm/imaadp32/Makefile dlls/msacm/msadp32/Makefile dlls/msacm/msg711/Makefile dlls/msacm/winemp3/Makefile dlls/msdmo/Makefile dlls/mshtml/Makefile dlls/msi/Makefile dlls/msimg32/Makefile dlls/msisys/Makefile dlls/msnet32/Makefile dlls/msrle32/Makefile dlls/msvcrt/Makefile dlls/msvcrt/tests/Makefile dlls/msvcrt20/Makefile dlls/msvcrt40/Makefile dlls/msvcrtd/Makefile dlls/msvidc32/Makefile dlls/msvideo/Makefile dlls/mswsock/Makefile dlls/netapi32/Makefile dlls/netapi32/tests/Makefile dlls/newdev/Makefile dlls/ntdll/Makefile dlls/ntdll/tests/Makefile dlls/odbc32/Makefile dlls/ole32/Makefile dlls/oleacc/Makefile dlls/oleaut32/Makefile dlls/oleaut32/tests/Makefile dlls/olecli/Makefile dlls/oledlg/Makefile dlls/olepro32/Makefile dlls/olesvr/Makefile dlls/opengl32/Makefile dlls/psapi/Makefile dlls/qcap/Makefile dlls/quartz/Makefile dlls/rasapi32/Makefile dlls/richedit/Makefile dlls/rpcrt4/Makefile dlls/rpcrt4/tests/Makefile dlls/rsabase/Makefile dlls/secur32/Makefile dlls/serialui/Makefile dlls/setupapi/Makefile dlls/shdocvw/Makefile dlls/shell32/Makefile dlls/shell32/tests/Makefile dlls/shfolder/Makefile dlls/shlwapi/Makefile dlls/shlwapi/tests/Makefile dlls/snmpapi/Makefile dlls/sti/Makefile dlls/tapi32/Makefile dlls/ttydrv/Makefile dlls/twain/Makefile dlls/unicows/Makefile dlls/url/Makefile dlls/urlmon/Makefile dlls/urlmon/tests/Makefile dlls/user/Makefile dlls/user/tests/Makefile dlls/uuid/Makefile dlls/uxtheme/Makefile dlls/vdhcp.vxd/Makefile dlls/vdmdbg/Makefile dlls/version/Makefile dlls/version/tests/Makefile dlls/vmm.vxd/Makefile dlls/vnbt.vxd/Makefile dlls/vnetbios.vxd/Makefile dlls/vtdapi.vxd/Makefile dlls/vwin32.vxd/Makefile dlls/win32s/Makefile dlls/winaspi/Makefile dlls/wined3d/Makefile dlls/winedos/Makefile dlls/wineps/Makefile dlls/wininet/Makefile dlls/wininet/tests/Makefile dlls/winmm/Makefile dlls/winmm/joystick/Makefile dlls/winmm/mcianim/Makefile dlls/winmm/mciavi/Makefile dlls/winmm/mcicda/Makefile dlls/winmm/mciseq/Makefile dlls/winmm/mciwave/Makefile dlls/winmm/midimap/Makefile dlls/winmm/tests/Makefile dlls/winmm/wavemap/Makefile dlls/winmm/winealsa/Makefile dlls/winmm/winearts/Makefile dlls/winmm/wineaudioio/Makefile dlls/winmm/winejack/Makefile dlls/winmm/winenas/Makefile dlls/winmm/wineoss/Makefile dlls/winnls/Makefile dlls/winsock/Makefile dlls/winsock/tests/Makefile dlls/winspool/Makefile dlls/winspool/tests/Makefile dlls/wintab32/Makefile dlls/wintrust/Makefile dlls/wow32/Makefile dlls/wsock32/Makefile dlls/x11drv/Makefile documentation/Makefile include/Makefile libs/Makefile libs/port/Makefile libs/unicode/Makefile libs/wine/Makefile libs/wpp/Makefile loader/Makefile programs/Makefile programs/avitools/Makefile programs/clock/Makefile programs/cmdlgtst/Makefile programs/control/Makefile programs/expand/Makefile programs/notepad/Makefile programs/progman/Makefile programs/regedit/Makefile programs/regsvr32/Makefile programs/rpcss/Makefile programs/rundll32/Makefile programs/start/Makefile programs/taskmgr/Makefile programs/uninstaller/Makefile programs/view/Makefile programs/wcmd/Makefile programs/wineboot/Makefile programs/winebrowser/Makefile programs/winecfg/Makefile programs/wineconsole/Makefile programs/winedbg/Makefile programs/winefile/Makefile programs/winemenubuilder/Makefile programs/winemine/Makefile programs/winepath/Makefile programs/winetest/Makefile programs/winevdm/Makefile programs/winhelp/Makefile programs/winver/Makefile server/Makefile tools/Makefile tools/widl/Makefile tools/winapi/Makefile tools/winebuild/Makefile tools/winedump/Makefile tools/winegcc/Makefile tools/wmc/Makefile tools/wrc/Makefile"
 
 
 cat >confcache <<\_ACEOF
@@ -20632,6 +20632,7 @@ do
   "dlls/kernel/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/kernel/tests/Makefile" ;;
   "dlls/lzexpand/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/lzexpand/Makefile" ;;
   "dlls/mapi32/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/mapi32/Makefile" ;;
+  "dlls/mapi32/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/mapi32/tests/Makefile" ;;
   "dlls/mmdevldr.vxd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/mmdevldr.vxd/Makefile" ;;
   "dlls/monodebg.vxd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/monodebg.vxd/Makefile" ;;
   "dlls/mpr/Makefile" ) CONFIG_FILES="$CONFIG_FILES dlls/mpr/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index d08842452ceb4d9c693d2cc8757ce7c16eabb01d..fba45a3467684e8caa08a21d49cab0eb359f8f4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1557,6 +1557,7 @@ dlls/kernel/Makefile
 dlls/kernel/tests/Makefile
 dlls/lzexpand/Makefile
 dlls/mapi32/Makefile
+dlls/mapi32/tests/Makefile
 dlls/mmdevldr.vxd/Makefile
 dlls/monodebg.vxd/Makefile
 dlls/mpr/Makefile
diff --git a/dlls/mapi32/tests/.cvsignore b/dlls/mapi32/tests/.cvsignore
new file mode 100644
index 0000000000000000000000000000000000000000..526e3c48625c268c27954171fe007c259a839684
--- /dev/null
+++ b/dlls/mapi32/tests/.cvsignore
@@ -0,0 +1,4 @@
+Makefile
+prop.ok
+testlist.c
+util.ok
diff --git a/dlls/mapi32/tests/Makefile.in b/dlls/mapi32/tests/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..9b938766716efa934785b5d500f085c2d346b3e7
--- /dev/null
+++ b/dlls/mapi32/tests/Makefile.in
@@ -0,0 +1,15 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+TESTDLL   = mapi32.dll
+IMPORTS   = mapi32
+EXTRALIBS = -luuid
+
+CTESTS = \
+	prop.c \
+	util.c
+
+@MAKE_TEST_RULES@
+
+### Dependencies:
diff --git a/dlls/mapi32/tests/prop.c b/dlls/mapi32/tests/prop.c
new file mode 100644
index 0000000000000000000000000000000000000000..f223c6cc0821e5cbc677085519fed877628ee9d1
--- /dev/null
+++ b/dlls/mapi32/tests/prop.c
@@ -0,0 +1,1073 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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"
+
+HRESULT WINAPI MAPIInitialize(LPVOID);
+
+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 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 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 = MAPIAllocateBuffer(sizeof(LPSPropValue), (LPVOID *)lpDest);
+    if (FAILED(scode))
+        return;
+        
+    scode = MAPIAllocateMore(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, MAPIAllocateMore, lpDest);
+        ok(!scode && lpDest->ulPropTag == lpSrc->ulPropTag,
+           "PropCopyMore: Expected 0x0,%ld, got 0x%08lx,%ld\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 */
+    MAPIFreeBuffer(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= %ld: Expected %ld, got %ld\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= %ld: 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 = lbuffa;
+                pvRight.Value.bin.lpb = rbuffa;
+                lbuffa[0] = lVal;
+                rbuffa[0] = rVal;
+                break;
+            }
+
+            bRet = pFPropCompareProp(&pvLeft, FPCProp_Results[j].relOp, &pvRight);
+            ok(bRet == bExp, "pt %ld (%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 = lbuffa;
+                pvRight.Value.bin.lpb = rbuffa;
+                lbuffa[0] = lVal;
+                rbuffa[0] = rVal;
+                break;
+            }
+
+            iRet = pLPropCompareProp(&pvLeft, &pvRight);
+            ok(iRet == iExp, "pt %ld (%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[%ld]: Didn't find existing propery\n",
+           ptTypes[i]);
+
+        pRet = pPpropFindProp(&pvProp, 1u, i ? ptTypes[i-1] : ptTypes[i+1]);
+        ok(pRet == NULL, "PpropFindProp[%ld]: Found non-existing 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;
+
+    pScCountProps = (void*)GetProcAddress(hMapi32, "ScCountProps@12");
+
+    if (!pScCountProps)
+        return;
+
+    for (pt = 0; pt < PROP_ID_INVALID; 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;
+            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)
+            ok(res == MAPI_E_INVALID_PARAMETER && ulRet == 0xffffffff,
+               "pt= %ld: Expected failure, got %ld, ret=0x%08lX\n", pt, ulRet, res);
+        else
+            ok(res == S_OK && ulRet == exp, "pt= %ld: Expected %ld, got %ld, ret=0x%08lX\n", 
+               pt, exp, ulRet, res);
+    }
+
+}
+
+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[%ld]: Didn't find existing propery id/type\n",
+           ptTypes[i]);
+
+        pRet = pLpValFindProp(PROP_TAG(ptTypes[i], 0u), 1u, &pvProp);
+        ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id\n",
+           ptTypes[i]);
+           
+        pRet = pLpValFindProp(PROP_TAG(PT_NULL, 0u), 1u, &pvProp);
+        ok(pRet == NULL, "LpValFindProp[%ld]: Found non-existing propery id/type\n",
+           ptTypes[i]);
+        
+        pRet = pLpValFindProp(PROP_TAG(PT_NULL, 1u), 1u, &pvProp);
+        ok(pRet == &pvProp, "LpValFindProp[%ld]: Didn't find existing propery id\n",
+           ptTypes[i]);
+    }
+}
+
+static void test_FBadRglpszA(void)
+{
+    LPSTR lpStrs[4];
+    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];
+    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= %ld: Expected non-zero, got 0\n", pt);
+        else
+            ok(res == 0, "pt= %ld: Expected zero, got %ld\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)
+{
+    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= %ld: Expected non-zero, got 0\n", pt);
+        else
+            ok(res == 0, "pt= %ld: Expected zero, got %ld\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= %ld: Expected non-zero, got 0\n", pt);
+        else
+            ok(res == 0, "pt= %ld: Expected zero, got %ld\n", pt, res);
+    }
+}
+
+START_TEST(prop)
+{  
+    hMapi32 = LoadLibraryA("mapi32.dll");
+    
+    pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
+    if (!pScInitMapiUtil)
+        return;
+    pScInitMapiUtil(0);
+
+    test_PropCopyMore();
+    test_UlPropSize();
+    test_FPropContainsProp();
+    test_FPropCompareProp();
+    test_LPropCompareProp();
+    test_PpropFindProp();
+    test_ScCountProps();
+    test_LpValFindProp();
+    test_FBadRglpszA();
+    test_FBadRglpszW();
+    test_FBadRowSet();
+    test_FBadPropTag();
+    test_FBadRow();
+    test_FBadProp();
+    test_FBadColumnSet();
+}
diff --git a/dlls/mapi32/tests/util.c b/dlls/mapi32/tests/util.c
new file mode 100644
index 0000000000000000000000000000000000000000..4aaf98da0f2d3375baac6e7527741d1c8c1e2493
--- /dev/null
+++ b/dlls/mapi32/tests/util.c
@@ -0,0 +1,83 @@
+/*
+ * Unit test suite for MAPI utility 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 void  (WINAPI *pSwapPword)(PUSHORT,ULONG);
+static void  (WINAPI *pSwapPlong)(PULONG,ULONG);
+
+static void test_SwapPword(void)
+{
+    USHORT shorts[3];
+
+    pSwapPword = (void*)GetProcAddress(hMapi32, "SwapPword@8");
+    if (!pSwapPword)
+        return;
+
+    shorts[0] = 0xff01;
+    shorts[1] = 0x10ff;
+    shorts[2] = 0x2001;
+    pSwapPword(shorts, 2);
+    ok(shorts[0] == 0x01ff && shorts[1] == 0xff10 && shorts[2] == 0x2001,
+       "Expected {0x01ff,0xff10,0x2001}, got {0x%04x,0x%04x,0x%04x}\n",
+       shorts[0], shorts[1], shorts[2]);
+}
+
+static void test_SwapPlong(void)
+{
+    ULONG longs[3];
+
+    pSwapPlong = (void*)GetProcAddress(hMapi32, "SwapPlong@8");
+    if (!pSwapPlong)
+        return;
+
+    longs[0] = 0xffff0001;
+    longs[1] = 0x1000ffff;
+    longs[2] = 0x20000001;
+    pSwapPlong(longs, 2);
+    ok(longs[0] == 0x0100ffff && longs[1] == 0xffff0010 && longs[2] == 0x20000001,
+       "Expected {0x0100ffff,0xffff0010,0x20000001}, got {0x%08lx,0x%08lx,0x%08lx}\n",
+       longs[0], longs[1], longs[2]);
+}
+
+START_TEST(util)
+{
+    hMapi32 = LoadLibraryA("mapi32.dll");
+    
+    pScInitMapiUtil = (void*)GetProcAddress(hMapi32, "ScInitMapiUtil@4");
+    if (!pScInitMapiUtil)
+        return;
+    pScInitMapiUtil(0);
+
+    test_SwapPword();
+    test_SwapPlong();
+}