--- /dev/null
+/* File generated automatically from tools/winapi/test.dat; do not edit! */
+/* This file can be copied, modified and distributed without restriction. */
+
+/*
+ * Unit tests for data structure packing
+ */
+
+#define WINVER 0x0501
+#define _WIN32_IE 0x0501
+#define _WIN32_WINNT 0x0501
+
+#define WINE_NOWINSOCK
+
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wtypes.h"
+#include "shellapi.h"
+#include "winuser.h"
+#include "wingdi.h"
+#include "shlobj.h"
+
+#include "wine/test.h"
+
+/***********************************************************************
+ * Compability macros
+ */
+
+#define DWORD_PTR UINT_PTR
+#define LONG_PTR INT_PTR
+#define ULONG_PTR UINT_PTR
+
+/***********************************************************************
+ * Windows API extension
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus)
+# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field)
+#elif defined(__GNUC__)
+# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field)
+#else
+/* FIXME: Not sure if is possible to do without compiler extension */
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus)
+# define _TYPE_ALIGNMENT(type) __alignof(type)
+#elif defined(__GNUC__)
+# define _TYPE_ALIGNMENT(type) __alignof__(type)
+#else
+/*
+ * FIXME: Not sure if is possible to do without compiler extension
+ * (if type is not just a name that is, if so the normal)
+ * TYPE_ALIGNMENT can be used)
+ */
+#endif
+
+#if defined(TYPE_ALIGNMENT) && defined(_MSC_VER) && _MSC_VER >= 800 && !defined(__cplusplus)
+#pragma warning(disable:4116)
+#endif
+
+#if !defined(TYPE_ALIGNMENT) && defined(_TYPE_ALIGNMENT)
+# define TYPE_ALIGNMENT _TYPE_ALIGNMENT
+#endif
+
+/***********************************************************************
+ * Test helper macros
+ */
+
+#ifdef FIELD_ALIGNMENT
+# define TEST_FIELD_ALIGNMENT(type, field, align) \
+ ok(FIELD_ALIGNMENT(type, field) == align, \
+ "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \
+ (int)FIELD_ALIGNMENT(type, field))
+#else
+# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0)
+#endif
+
+#define TEST_FIELD_OFFSET(type, field, offset) \
+ ok(FIELD_OFFSET(type, field) == offset, \
+ "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \
+ (long int)FIELD_OFFSET(type, field))
+
+#ifdef _TYPE_ALIGNMENT
+#define TEST__TYPE_ALIGNMENT(type, align) \
+ ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type))
+#else
+# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0)
+#endif
+
+#ifdef TYPE_ALIGNMENT
+#define TEST_TYPE_ALIGNMENT(type, align) \
+ ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type))
+#else
+# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0)
+#endif
+
+#define TEST_TYPE_SIZE(type, size) \
+ ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type)))
+
+/***********************************************************************
+ * Test macros
+ */
+
+#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \
+ TEST_TYPE_SIZE(field_type, field_size); \
+ TEST_FIELD_ALIGNMENT(type, field_name, field_align); \
+ TEST_FIELD_OFFSET(type, field_name, field_offset); \
+
+#define TEST_TYPE(type, size, align) \
+ TEST_TYPE_ALIGNMENT(type, align); \
+ TEST_TYPE_SIZE(type, size)
+
+#define TEST_TYPE_POINTER(type, size, align) \
+ TEST__TYPE_ALIGNMENT(*(type)0, align); \
+ TEST_TYPE_SIZE(*(type)0, size)
+
+#define TEST_TYPE_SIGNED(type) \
+ ok((type) -1 < 0, "(" #type ") -1 < 0\n");
+
+#define TEST_TYPE_UNSIGNED(type) \
+ ok((type) -1 > 0, "(" #type ") -1 > 0\n");
+
+static void test_pack_BLOB(void)
+{
+ /* BLOB (pack 4) */
+ TEST_TYPE(BLOB, 8, 4);
+ TEST_FIELD(BLOB, ULONG, cbSize, 0, 4, 4);
+ TEST_FIELD(BLOB, BYTE *, pBlobData, 4, 4, 4);
+}
+
+static void test_pack_BSTR(void)
+{
+ /* BSTR */
+ TEST_TYPE(BSTR, 4, 4);
+ TEST_TYPE_POINTER(BSTR, 2, 2);
+}
+
+static void test_pack_BSTRBLOB(void)
+{
+ /* BSTRBLOB (pack 4) */
+ TEST_TYPE(BSTRBLOB, 8, 4);
+ TEST_FIELD(BSTRBLOB, ULONG, cbSize, 0, 4, 4);
+ TEST_FIELD(BSTRBLOB, BYTE *, pData, 4, 4, 4);
+}
+
+static void test_pack_BYTE_BLOB(void)
+{
+ /* BYTE_BLOB (pack 4) */
+ TEST_TYPE(BYTE_BLOB, 8, 4);
+ TEST_FIELD(BYTE_BLOB, unsigned long, clSize, 0, 4, 4);
+ TEST_FIELD(BYTE_BLOB, byte[1], abData, 4, 1, 1);
+}
+
+static void test_pack_BYTE_SIZEDARR(void)
+{
+ /* BYTE_SIZEDARR (pack 4) */
+ TEST_TYPE(BYTE_SIZEDARR, 8, 4);
+ TEST_FIELD(BYTE_SIZEDARR, unsigned long, clSize, 0, 4, 4);
+ TEST_FIELD(BYTE_SIZEDARR, byte *, pData, 4, 4, 4);
+}
+
+static void test_pack_CLIPDATA(void)
+{
+ /* CLIPDATA (pack 4) */
+ TEST_TYPE(CLIPDATA, 12, 4);
+ TEST_FIELD(CLIPDATA, ULONG, cbSize, 0, 4, 4);
+ TEST_FIELD(CLIPDATA, long, ulClipFmt, 4, 4, 4);
+ TEST_FIELD(CLIPDATA, BYTE *, pClipData, 8, 4, 4);
+}
+
+static void test_pack_CLIPFORMAT(void)
+{
+ /* CLIPFORMAT */
+ TEST_TYPE(CLIPFORMAT, 2, 2);
+ TEST_TYPE_UNSIGNED(CLIPFORMAT);
+}
+
+static void test_pack_COAUTHIDENTITY(void)
+{
+ /* COAUTHIDENTITY (pack 4) */
+ TEST_TYPE(COAUTHIDENTITY, 28, 4);
+ TEST_FIELD(COAUTHIDENTITY, USHORT *, User, 0, 4, 4);
+ TEST_FIELD(COAUTHIDENTITY, ULONG, UserLength, 4, 4, 4);
+ TEST_FIELD(COAUTHIDENTITY, USHORT *, Domain, 8, 4, 4);
+ TEST_FIELD(COAUTHIDENTITY, ULONG, DomainLength, 12, 4, 4);
+ TEST_FIELD(COAUTHIDENTITY, USHORT *, Password, 16, 4, 4);
+ TEST_FIELD(COAUTHIDENTITY, ULONG, PasswordLength, 20, 4, 4);
+ TEST_FIELD(COAUTHIDENTITY, ULONG, Flags, 24, 4, 4);
+}
+
+static void test_pack_COAUTHINFO(void)
+{
+ /* COAUTHINFO (pack 4) */
+ TEST_TYPE(COAUTHINFO, 28, 4);
+ TEST_FIELD(COAUTHINFO, DWORD, dwAuthnSvc, 0, 4, 4);
+ TEST_FIELD(COAUTHINFO, DWORD, dwAuthzSvc, 4, 4, 4);
+ TEST_FIELD(COAUTHINFO, LPWSTR, pwszServerPrincName, 8, 4, 4);
+ TEST_FIELD(COAUTHINFO, DWORD, dwAuthnLevel, 12, 4, 4);
+ TEST_FIELD(COAUTHINFO, DWORD, dwImpersonationLevel, 16, 4, 4);
+ TEST_FIELD(COAUTHINFO, COAUTHIDENTITY *, pAuthIdentityData, 20, 4, 4);
+ TEST_FIELD(COAUTHINFO, DWORD, dwCapabilities, 24, 4, 4);
+}
+
+static void test_pack_COSERVERINFO(void)
+{
+ /* COSERVERINFO (pack 4) */
+ TEST_TYPE(COSERVERINFO, 16, 4);
+ TEST_FIELD(COSERVERINFO, DWORD, dwReserved1, 0, 4, 4);
+ TEST_FIELD(COSERVERINFO, LPWSTR, pwszName, 4, 4, 4);
+ TEST_FIELD(COSERVERINFO, COAUTHINFO *, pAuthInfo, 8, 4, 4);
+ TEST_FIELD(COSERVERINFO, DWORD, dwReserved2, 12, 4, 4);
+}
+
+static void test_pack_DWORD_SIZEDARR(void)
+{
+ /* DWORD_SIZEDARR (pack 4) */
+ TEST_TYPE(DWORD_SIZEDARR, 8, 4);
+ TEST_FIELD(DWORD_SIZEDARR, unsigned long, clSize, 0, 4, 4);
+ TEST_FIELD(DWORD_SIZEDARR, unsigned long *, pData, 4, 4, 4);
+}
+
+static void test_pack_FLAGGED_BYTE_BLOB(void)
+{
+ /* FLAGGED_BYTE_BLOB (pack 4) */
+ TEST_TYPE(FLAGGED_BYTE_BLOB, 12, 4);
+ TEST_FIELD(FLAGGED_BYTE_BLOB, unsigned long, fFlags, 0, 4, 4);
+ TEST_FIELD(FLAGGED_BYTE_BLOB, unsigned long, clSize, 4, 4, 4);
+ TEST_FIELD(FLAGGED_BYTE_BLOB, byte[1], abData, 8, 1, 1);
+}
+
+static void test_pack_FLAGGED_WORD_BLOB(void)
+{
+ /* FLAGGED_WORD_BLOB (pack 4) */
+ TEST_TYPE(FLAGGED_WORD_BLOB, 12, 4);
+ TEST_FIELD(FLAGGED_WORD_BLOB, unsigned long, fFlags, 0, 4, 4);
+ TEST_FIELD(FLAGGED_WORD_BLOB, unsigned long, clSize, 4, 4, 4);
+ TEST_FIELD(FLAGGED_WORD_BLOB, unsigned short[1], asData, 8, 2, 2);
+}
+
+static void test_pack_HMETAFILEPICT(void)
+{
+ /* HMETAFILEPICT */
+ TEST_TYPE(HMETAFILEPICT, 4, 4);
+}
+
+static void test_pack_HYPER_SIZEDARR(void)
+{
+ /* HYPER_SIZEDARR (pack 4) */
+ TEST_TYPE(HYPER_SIZEDARR, 8, 4);
+ TEST_FIELD(HYPER_SIZEDARR, unsigned long, clSize, 0, 4, 4);
+ TEST_FIELD(HYPER_SIZEDARR, hyper *, pData, 4, 4, 4);
+}
+
+static void test_pack_LPBLOB(void)
+{
+ /* LPBLOB */
+ TEST_TYPE(LPBLOB, 4, 4);
+ TEST_TYPE_POINTER(LPBLOB, 8, 4);
+}
+
+static void test_pack_LPBSTR(void)
+{
+ /* LPBSTR */
+ TEST_TYPE(LPBSTR, 4, 4);
+ TEST_TYPE_POINTER(LPBSTR, 4, 4);
+}
+
+static void test_pack_LPBSTRBLOB(void)
+{
+ /* LPBSTRBLOB */
+ TEST_TYPE(LPBSTRBLOB, 4, 4);
+ TEST_TYPE_POINTER(LPBSTRBLOB, 8, 4);
+}
+
+static void test_pack_LPCOLESTR(void)
+{
+ /* LPCOLESTR */
+ TEST_TYPE(LPCOLESTR, 4, 4);
+ TEST_TYPE_POINTER(LPCOLESTR, 2, 2);
+}
+
+static void test_pack_LPCY(void)
+{
+ /* LPCY */
+ TEST_TYPE(LPCY, 4, 4);
+}
+
+static void test_pack_LPDECIMAL(void)
+{
+ /* LPDECIMAL */
+ TEST_TYPE(LPDECIMAL, 4, 4);
+}
+
+static void test_pack_LPOLESTR(void)
+{
+ /* LPOLESTR */
+ TEST_TYPE(LPOLESTR, 4, 4);
+ TEST_TYPE_POINTER(LPOLESTR, 2, 2);
+}
+
+static void test_pack_OLECHAR(void)
+{
+ /* OLECHAR */
+ TEST_TYPE(OLECHAR, 2, 2);
+}
+
+static void test_pack_PROPID(void)
+{
+ /* PROPID */
+ TEST_TYPE(PROPID, 4, 4);
+}
+
+static void test_pack_RemHBITMAP(void)
+{
+ /* RemHBITMAP (pack 4) */
+ TEST_TYPE(RemHBITMAP, 8, 4);
+ TEST_FIELD(RemHBITMAP, unsigned long, cbData, 0, 4, 4);
+ TEST_FIELD(RemHBITMAP, byte[1], data, 4, 1, 1);
+}
+
+static void test_pack_RemHENHMETAFILE(void)
+{
+ /* RemHENHMETAFILE (pack 4) */
+ TEST_TYPE(RemHENHMETAFILE, 8, 4);
+ TEST_FIELD(RemHENHMETAFILE, unsigned long, cbData, 0, 4, 4);
+ TEST_FIELD(RemHENHMETAFILE, byte[1], data, 4, 1, 1);
+}
+
+static void test_pack_RemHGLOBAL(void)
+{
+ /* RemHGLOBAL (pack 4) */
+ TEST_TYPE(RemHGLOBAL, 12, 4);
+ TEST_FIELD(RemHGLOBAL, long, fNullHGlobal, 0, 4, 4);
+ TEST_FIELD(RemHGLOBAL, unsigned long, cbData, 4, 4, 4);
+ TEST_FIELD(RemHGLOBAL, byte[1], data, 8, 1, 1);
+}
+
+static void test_pack_RemHMETAFILEPICT(void)
+{
+ /* RemHMETAFILEPICT (pack 4) */
+ TEST_TYPE(RemHMETAFILEPICT, 20, 4);
+ TEST_FIELD(RemHMETAFILEPICT, long, mm, 0, 4, 4);
+ TEST_FIELD(RemHMETAFILEPICT, long, xExt, 4, 4, 4);
+ TEST_FIELD(RemHMETAFILEPICT, long, yExt, 8, 4, 4);
+ TEST_FIELD(RemHMETAFILEPICT, unsigned long, cbData, 12, 4, 4);
+ TEST_FIELD(RemHMETAFILEPICT, byte[1], data, 16, 1, 1);
+}
+
+static void test_pack_RemHPALETTE(void)
+{
+ /* RemHPALETTE (pack 4) */
+ TEST_TYPE(RemHPALETTE, 8, 4);
+ TEST_FIELD(RemHPALETTE, unsigned long, cbData, 0, 4, 4);
+ TEST_FIELD(RemHPALETTE, byte[1], data, 4, 1, 1);
+}
+
+static void test_pack_SCODE(void)
+{
+ /* SCODE */
+ TEST_TYPE(SCODE, 4, 4);
+}
+
+static void test_pack_UP_BYTE_BLOB(void)
+{
+ /* UP_BYTE_BLOB */
+ TEST_TYPE(UP_BYTE_BLOB, 4, 4);
+ TEST_TYPE_POINTER(UP_BYTE_BLOB, 8, 4);
+}
+
+static void test_pack_UP_FLAGGED_BYTE_BLOB(void)
+{
+ /* UP_FLAGGED_BYTE_BLOB */
+ TEST_TYPE(UP_FLAGGED_BYTE_BLOB, 4, 4);
+ TEST_TYPE_POINTER(UP_FLAGGED_BYTE_BLOB, 12, 4);
+}
+
+static void test_pack_UP_FLAGGED_WORD_BLOB(void)
+{
+ /* UP_FLAGGED_WORD_BLOB */
+ TEST_TYPE(UP_FLAGGED_WORD_BLOB, 4, 4);
+ TEST_TYPE_POINTER(UP_FLAGGED_WORD_BLOB, 12, 4);
+}
+
+static void test_pack_VARIANT_BOOL(void)
+{
+ /* VARIANT_BOOL */
+ TEST_TYPE(VARIANT_BOOL, 2, 2);
+ TEST_TYPE_SIGNED(VARIANT_BOOL);
+}
+
+static void test_pack_VARTYPE(void)
+{
+ /* VARTYPE */
+ TEST_TYPE(VARTYPE, 2, 2);
+ TEST_TYPE_UNSIGNED(VARTYPE);
+}
+
+static void test_pack_WORD_SIZEDARR(void)
+{
+ /* WORD_SIZEDARR (pack 4) */
+ TEST_TYPE(WORD_SIZEDARR, 8, 4);
+ TEST_FIELD(WORD_SIZEDARR, unsigned long, clSize, 0, 4, 4);
+ TEST_FIELD(WORD_SIZEDARR, unsigned short *, pData, 4, 4, 4);
+}
+
+static void test_pack_remoteMETAFILEPICT(void)
+{
+ /* remoteMETAFILEPICT (pack 4) */
+ TEST_TYPE(remoteMETAFILEPICT, 16, 4);
+ TEST_FIELD(remoteMETAFILEPICT, long, mm, 0, 4, 4);
+ TEST_FIELD(remoteMETAFILEPICT, long, xExt, 4, 4, 4);
+ TEST_FIELD(remoteMETAFILEPICT, long, yExt, 8, 4, 4);
+ TEST_FIELD(remoteMETAFILEPICT, userHMETAFILE *, hMF, 12, 4, 4);
+}
+
+static void test_pack_userBITMAP(void)
+{
+ /* userBITMAP (pack 4) */
+ TEST_TYPE(userBITMAP, 28, 4);
+ TEST_FIELD(userBITMAP, LONG, bmType, 0, 4, 4);
+ TEST_FIELD(userBITMAP, LONG, bmWidth, 4, 4, 4);
+ TEST_FIELD(userBITMAP, LONG, bmHeight, 8, 4, 4);
+ TEST_FIELD(userBITMAP, LONG, bmWidthBytes, 12, 4, 4);
+ TEST_FIELD(userBITMAP, WORD, bmPlanes, 16, 2, 2);
+ TEST_FIELD(userBITMAP, WORD, bmBitsPixel, 18, 2, 2);
+ TEST_FIELD(userBITMAP, ULONG, cbSize, 20, 4, 4);
+ TEST_FIELD(userBITMAP, byte[1], pBuffer, 24, 1, 1);
+}
+
+static void test_pack_userCLIPFORMAT(void)
+{
+ /* userCLIPFORMAT (pack 4) */
+ TEST_FIELD(userCLIPFORMAT, long, fContext, 0, 4, 4);
+}
+
+static void test_pack_userHBITMAP(void)
+{
+ /* userHBITMAP (pack 4) */
+ TEST_FIELD(userHBITMAP, long, fContext, 0, 4, 4);
+}
+
+static void test_pack_userHENHMETAFILE(void)
+{
+ /* userHENHMETAFILE (pack 4) */
+ TEST_FIELD(userHENHMETAFILE, long, fContext, 0, 4, 4);
+}
+
+static void test_pack_userHGLOBAL(void)
+{
+ /* userHGLOBAL (pack 4) */
+ TEST_FIELD(userHGLOBAL, long, fContext, 0, 4, 4);
+}
+
+static void test_pack_userHMETAFILE(void)
+{
+ /* userHMETAFILE (pack 4) */
+ TEST_FIELD(userHMETAFILE, long, fContext, 0, 4, 4);
+}
+
+static void test_pack_userHMETAFILEPICT(void)
+{
+ /* userHMETAFILEPICT (pack 4) */
+ TEST_FIELD(userHMETAFILEPICT, long, fContext, 0, 4, 4);
+}
+
+static void test_pack_userHPALETTE(void)
+{
+ /* userHPALETTE (pack 4) */
+ TEST_FIELD(userHPALETTE, long, fContext, 0, 4, 4);
+}
+
+static void test_pack_wireBSTR(void)
+{
+ /* wireBSTR */
+ TEST_TYPE(wireBSTR, 4, 4);
+ TEST_TYPE_POINTER(wireBSTR, 12, 4);
+}
+
+static void test_pack_wireCLIPFORMAT(void)
+{
+ /* wireCLIPFORMAT */
+ TEST_TYPE(wireCLIPFORMAT, 4, 4);
+}
+
+static void test_pack_wireHBITMAP(void)
+{
+ /* wireHBITMAP */
+ TEST_TYPE(wireHBITMAP, 4, 4);
+}
+
+static void test_pack_wireHENHMETAFILE(void)
+{
+ /* wireHENHMETAFILE */
+ TEST_TYPE(wireHENHMETAFILE, 4, 4);
+}
+
+static void test_pack_wireHGLOBAL(void)
+{
+ /* wireHGLOBAL */
+ TEST_TYPE(wireHGLOBAL, 4, 4);
+}
+
+static void test_pack_wireHMETAFILE(void)
+{
+ /* wireHMETAFILE */
+ TEST_TYPE(wireHMETAFILE, 4, 4);
+}
+
+static void test_pack_wireHMETAFILEPICT(void)
+{
+ /* wireHMETAFILEPICT */
+ TEST_TYPE(wireHMETAFILEPICT, 4, 4);
+}
+
+static void test_pack_wireHPALETTE(void)
+{
+ /* wireHPALETTE */
+ TEST_TYPE(wireHPALETTE, 4, 4);
+}
+
+static void test_pack_CLSID(void)
+{
+ /* CLSID */
+ TEST_TYPE(CLSID, 16, 4);
+}
+
+static void test_pack_FMTID(void)
+{
+ /* FMTID */
+ TEST_TYPE(FMTID, 16, 4);
+}
+
+static void test_pack_GUID(void)
+{
+ /* GUID (pack 4) */
+ TEST_TYPE(GUID, 16, 4);
+ TEST_FIELD(GUID, unsigned long, Data1, 0, 4, 4);
+ TEST_FIELD(GUID, unsigned short, Data2, 4, 2, 2);
+ TEST_FIELD(GUID, unsigned short, Data3, 6, 2, 2);
+ TEST_FIELD(GUID, unsigned char[ 8 ], Data4, 8, 8, 1);
+}
+
+static void test_pack_IID(void)
+{
+ /* IID */
+ TEST_TYPE(IID, 16, 4);
+}
+
+static void test_pack_LPGUID(void)
+{
+ /* LPGUID */
+ TEST_TYPE(LPGUID, 4, 4);
+ TEST_TYPE_POINTER(LPGUID, 16, 4);
+}
+
+static void test_pack_APPBARDATA(void)
+{
+ /* APPBARDATA (pack 1) */
+ TEST_TYPE(APPBARDATA, 36, 1);
+ TEST_FIELD(APPBARDATA, DWORD, cbSize, 0, 4, 1);
+ TEST_FIELD(APPBARDATA, HWND, hWnd, 4, 4, 1);
+ TEST_FIELD(APPBARDATA, UINT, uCallbackMessage, 8, 4, 1);
+ TEST_FIELD(APPBARDATA, UINT, uEdge, 12, 4, 1);
+ TEST_FIELD(APPBARDATA, RECT, rc, 16, 16, 1);
+ TEST_FIELD(APPBARDATA, LPARAM, lParam, 32, 4, 1);
+}
+
+static void test_pack_DRAGINFOA(void)
+{
+ /* DRAGINFOA (pack 1) */
+ TEST_TYPE(DRAGINFOA, 24, 1);
+ TEST_FIELD(DRAGINFOA, UINT, uSize, 0, 4, 1);
+ TEST_FIELD(DRAGINFOA, POINT, pt, 4, 8, 1);
+ TEST_FIELD(DRAGINFOA, BOOL, fNC, 12, 4, 1);
+ TEST_FIELD(DRAGINFOA, LPSTR, lpFileList, 16, 4, 1);
+ TEST_FIELD(DRAGINFOA, DWORD, grfKeyState, 20, 4, 1);
+}
+
+static void test_pack_DRAGINFOW(void)
+{
+ /* DRAGINFOW (pack 1) */
+ TEST_TYPE(DRAGINFOW, 24, 1);
+ TEST_FIELD(DRAGINFOW, UINT, uSize, 0, 4, 1);
+ TEST_FIELD(DRAGINFOW, POINT, pt, 4, 8, 1);
+ TEST_FIELD(DRAGINFOW, BOOL, fNC, 12, 4, 1);
+ TEST_FIELD(DRAGINFOW, LPWSTR, lpFileList, 16, 4, 1);
+ TEST_FIELD(DRAGINFOW, DWORD, grfKeyState, 20, 4, 1);
+}
+
+static void test_pack_FILEOP_FLAGS(void)
+{
+ /* FILEOP_FLAGS */
+ TEST_TYPE(FILEOP_FLAGS, 2, 2);
+ TEST_TYPE_UNSIGNED(FILEOP_FLAGS);
+}
+
+static void test_pack_LPDRAGINFOA(void)
+{
+ /* LPDRAGINFOA */
+ TEST_TYPE(LPDRAGINFOA, 4, 4);
+ TEST_TYPE_POINTER(LPDRAGINFOA, 24, 1);
+}
+
+static void test_pack_LPDRAGINFOW(void)
+{
+ /* LPDRAGINFOW */
+ TEST_TYPE(LPDRAGINFOW, 4, 4);
+ TEST_TYPE_POINTER(LPDRAGINFOW, 24, 1);
+}
+
+static void test_pack_LPSHELLEXECUTEINFOA(void)
+{
+ /* LPSHELLEXECUTEINFOA */
+ TEST_TYPE(LPSHELLEXECUTEINFOA, 4, 4);
+}
+
+static void test_pack_LPSHELLEXECUTEINFOW(void)
+{
+ /* LPSHELLEXECUTEINFOW */
+ TEST_TYPE(LPSHELLEXECUTEINFOW, 4, 4);
+}
+
+static void test_pack_LPSHFILEOPSTRUCTA(void)
+{
+ /* LPSHFILEOPSTRUCTA */
+ TEST_TYPE(LPSHFILEOPSTRUCTA, 4, 4);
+ TEST_TYPE_POINTER(LPSHFILEOPSTRUCTA, 30, 1);
+}
+
+static void test_pack_LPSHFILEOPSTRUCTW(void)
+{
+ /* LPSHFILEOPSTRUCTW */
+ TEST_TYPE(LPSHFILEOPSTRUCTW, 4, 4);
+ TEST_TYPE_POINTER(LPSHFILEOPSTRUCTW, 30, 1);
+}
+
+static void test_pack_LPSHNAMEMAPPINGA(void)
+{
+ /* LPSHNAMEMAPPINGA */
+ TEST_TYPE(LPSHNAMEMAPPINGA, 4, 4);
+ TEST_TYPE_POINTER(LPSHNAMEMAPPINGA, 16, 1);
+}
+
+static void test_pack_LPSHNAMEMAPPINGW(void)
+{
+ /* LPSHNAMEMAPPINGW */
+ TEST_TYPE(LPSHNAMEMAPPINGW, 4, 4);
+ TEST_TYPE_POINTER(LPSHNAMEMAPPINGW, 16, 1);
+}
+
+static void test_pack_NOTIFYICONDATAA(void)
+{
+ /* NOTIFYICONDATAA (pack 1) */
+ TEST_FIELD(NOTIFYICONDATAA, DWORD, cbSize, 0, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, HWND, hWnd, 4, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, UINT, uID, 8, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, UINT, uFlags, 12, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, UINT, uCallbackMessage, 16, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, HICON, hIcon, 20, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, CHAR[128], szTip, 24, 128, 1);
+ TEST_FIELD(NOTIFYICONDATAA, DWORD, dwState, 152, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, DWORD, dwStateMask, 156, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAA, CHAR[256], szInfo, 160, 256, 1);
+}
+
+static void test_pack_NOTIFYICONDATAW(void)
+{
+ /* NOTIFYICONDATAW (pack 1) */
+ TEST_FIELD(NOTIFYICONDATAW, DWORD, cbSize, 0, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, HWND, hWnd, 4, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, UINT, uID, 8, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, UINT, uFlags, 12, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, UINT, uCallbackMessage, 16, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, HICON, hIcon, 20, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, WCHAR[128], szTip, 24, 256, 1);
+ TEST_FIELD(NOTIFYICONDATAW, DWORD, dwState, 280, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, DWORD, dwStateMask, 284, 4, 1);
+ TEST_FIELD(NOTIFYICONDATAW, WCHAR[256], szInfo, 288, 512, 1);
+}
+
+static void test_pack_PAPPBARDATA(void)
+{
+ /* PAPPBARDATA */
+ TEST_TYPE(PAPPBARDATA, 4, 4);
+ TEST_TYPE_POINTER(PAPPBARDATA, 36, 1);
+}
+
+static void test_pack_PNOTIFYICONDATAA(void)
+{
+ /* PNOTIFYICONDATAA */
+ TEST_TYPE(PNOTIFYICONDATAA, 4, 4);
+}
+
+static void test_pack_PNOTIFYICONDATAW(void)
+{
+ /* PNOTIFYICONDATAW */
+ TEST_TYPE(PNOTIFYICONDATAW, 4, 4);
+}
+
+static void test_pack_PRINTEROP_FLAGS(void)
+{
+ /* PRINTEROP_FLAGS */
+ TEST_TYPE(PRINTEROP_FLAGS, 2, 2);
+ TEST_TYPE_UNSIGNED(PRINTEROP_FLAGS);
+}
+
+static void test_pack_SHELLEXECUTEINFOA(void)
+{
+ /* SHELLEXECUTEINFOA (pack 1) */
+ TEST_FIELD(SHELLEXECUTEINFOA, DWORD, cbSize, 0, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, ULONG, fMask, 4, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, HWND, hwnd, 8, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpVerb, 12, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpFile, 16, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpParameters, 20, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpDirectory, 24, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, INT, nShow, 28, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, HINSTANCE, hInstApp, 32, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, LPVOID, lpIDList, 36, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, LPCSTR, lpClass, 40, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, HKEY, hkeyClass, 44, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOA, DWORD, dwHotKey, 48, 4, 1);
+}
+
+static void test_pack_SHELLEXECUTEINFOW(void)
+{
+ /* SHELLEXECUTEINFOW (pack 1) */
+ TEST_FIELD(SHELLEXECUTEINFOW, DWORD, cbSize, 0, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, ULONG, fMask, 4, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, HWND, hwnd, 8, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpVerb, 12, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpFile, 16, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpParameters, 20, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpDirectory, 24, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, INT, nShow, 28, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, HINSTANCE, hInstApp, 32, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, LPVOID, lpIDList, 36, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, LPCWSTR, lpClass, 40, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, HKEY, hkeyClass, 44, 4, 1);
+ TEST_FIELD(SHELLEXECUTEINFOW, DWORD, dwHotKey, 48, 4, 1);
+}
+
+static void test_pack_SHFILEINFOA(void)
+{
+ /* SHFILEINFOA (pack 1) */
+ TEST_TYPE(SHFILEINFOA, 352, 1);
+ TEST_FIELD(SHFILEINFOA, HICON, hIcon, 0, 4, 1);
+ TEST_FIELD(SHFILEINFOA, int, iIcon, 4, 4, 1);
+ TEST_FIELD(SHFILEINFOA, DWORD, dwAttributes, 8, 4, 1);
+ TEST_FIELD(SHFILEINFOA, CHAR[MAX_PATH], szDisplayName, 12, 260, 1);
+ TEST_FIELD(SHFILEINFOA, CHAR[80], szTypeName, 272, 80, 1);
+}
+
+static void test_pack_SHFILEINFOW(void)
+{
+ /* SHFILEINFOW (pack 1) */
+ TEST_TYPE(SHFILEINFOW, 692, 1);
+ TEST_FIELD(SHFILEINFOW, HICON, hIcon, 0, 4, 1);
+ TEST_FIELD(SHFILEINFOW, int, iIcon, 4, 4, 1);
+ TEST_FIELD(SHFILEINFOW, DWORD, dwAttributes, 8, 4, 1);
+ TEST_FIELD(SHFILEINFOW, WCHAR[MAX_PATH], szDisplayName, 12, 520, 1);
+ TEST_FIELD(SHFILEINFOW, WCHAR[80], szTypeName, 532, 160, 1);
+}
+
+static void test_pack_SHFILEOPSTRUCTA(void)
+{
+ /* SHFILEOPSTRUCTA (pack 1) */
+ TEST_TYPE(SHFILEOPSTRUCTA, 30, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, HWND, hwnd, 0, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, UINT, wFunc, 4, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, LPCSTR, pFrom, 8, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, LPCSTR, pTo, 12, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, FILEOP_FLAGS, fFlags, 16, 2, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, BOOL, fAnyOperationsAborted, 18, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, LPVOID, hNameMappings, 22, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTA, LPCSTR, lpszProgressTitle, 26, 4, 1);
+}
+
+static void test_pack_SHFILEOPSTRUCTW(void)
+{
+ /* SHFILEOPSTRUCTW (pack 1) */
+ TEST_TYPE(SHFILEOPSTRUCTW, 30, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, HWND, hwnd, 0, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, UINT, wFunc, 4, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, LPCWSTR, pFrom, 8, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, LPCWSTR, pTo, 12, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, FILEOP_FLAGS, fFlags, 16, 2, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, BOOL, fAnyOperationsAborted, 18, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, LPVOID, hNameMappings, 22, 4, 1);
+ TEST_FIELD(SHFILEOPSTRUCTW, LPCWSTR, lpszProgressTitle, 26, 4, 1);
+}
+
+static void test_pack_SHNAMEMAPPINGA(void)
+{
+ /* SHNAMEMAPPINGA (pack 1) */
+ TEST_TYPE(SHNAMEMAPPINGA, 16, 1);
+ TEST_FIELD(SHNAMEMAPPINGA, LPSTR, pszOldPath, 0, 4, 1);
+ TEST_FIELD(SHNAMEMAPPINGA, LPSTR, pszNewPath, 4, 4, 1);
+ TEST_FIELD(SHNAMEMAPPINGA, int, cchOldPath, 8, 4, 1);
+ TEST_FIELD(SHNAMEMAPPINGA, int, cchNewPath, 12, 4, 1);
+}
+
+static void test_pack_SHNAMEMAPPINGW(void)
+{
+ /* SHNAMEMAPPINGW (pack 1) */
+ TEST_TYPE(SHNAMEMAPPINGW, 16, 1);
+ TEST_FIELD(SHNAMEMAPPINGW, LPWSTR, pszOldPath, 0, 4, 1);
+ TEST_FIELD(SHNAMEMAPPINGW, LPWSTR, pszNewPath, 4, 4, 1);
+ TEST_FIELD(SHNAMEMAPPINGW, int, cchOldPath, 8, 4, 1);
+ TEST_FIELD(SHNAMEMAPPINGW, int, cchNewPath, 12, 4, 1);
+}
+
+static void test_pack_ITEMIDLIST(void)
+{
+ /* ITEMIDLIST (pack 1) */
+ TEST_TYPE(ITEMIDLIST, 3, 1);
+ TEST_FIELD(ITEMIDLIST, SHITEMID, mkid, 0, 3, 1);
+}
+
+static void test_pack_LPCITEMIDLIST(void)
+{
+ /* LPCITEMIDLIST */
+ TEST_TYPE(LPCITEMIDLIST, 4, 4);
+ TEST_TYPE_POINTER(LPCITEMIDLIST, 3, 1);
+}
+
+static void test_pack_LPCSHITEMID(void)
+{
+ /* LPCSHITEMID */
+ TEST_TYPE(LPCSHITEMID, 4, 4);
+ TEST_TYPE_POINTER(LPCSHITEMID, 3, 1);
+}
+
+static void test_pack_LPITEMIDLIST(void)
+{
+ /* LPITEMIDLIST */
+ TEST_TYPE(LPITEMIDLIST, 4, 4);
+ TEST_TYPE_POINTER(LPITEMIDLIST, 3, 1);
+}
+
+static void test_pack_LPSHELLDETAILS(void)
+{
+ /* LPSHELLDETAILS */
+ TEST_TYPE(LPSHELLDETAILS, 4, 4);
+}
+
+static void test_pack_LPSHITEMID(void)
+{
+ /* LPSHITEMID */
+ TEST_TYPE(LPSHITEMID, 4, 4);
+ TEST_TYPE_POINTER(LPSHITEMID, 3, 1);
+}
+
+static void test_pack_LPSTRRET(void)
+{
+ /* LPSTRRET */
+ TEST_TYPE(LPSTRRET, 4, 4);
+}
+
+static void test_pack_SHELLDETAILS(void)
+{
+ /* SHELLDETAILS (pack 1) */
+ TEST_FIELD(SHELLDETAILS, int, fmt, 0, 4, 1);
+ TEST_FIELD(SHELLDETAILS, int, cxChar, 4, 4, 1);
+}
+
+static void test_pack_SHITEMID(void)
+{
+ /* SHITEMID (pack 1) */
+ TEST_TYPE(SHITEMID, 3, 1);
+ TEST_FIELD(SHITEMID, WORD, cb, 0, 2, 1);
+ TEST_FIELD(SHITEMID, BYTE[1], abID, 2, 1, 1);
+}
+
+static void test_pack_STRRET(void)
+{
+ /* STRRET (pack 4) */
+ TEST_FIELD(STRRET, UINT, uType, 0, 4, 4);
+}
+
+static void test_pack_AUTO_SCROLL_DATA(void)
+{
+ /* AUTO_SCROLL_DATA (pack 1) */
+ TEST_TYPE(AUTO_SCROLL_DATA, 48, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, int, iNextSample, 0, 4, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, DWORD, dwLastScroll, 4, 4, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, BOOL, bFull, 8, 4, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, POINT[NUM_POINTS], pts, 12, 24, 1);
+ TEST_FIELD(AUTO_SCROLL_DATA, DWORD[NUM_POINTS], dwTimes, 36, 12, 1);
+}
+
+static void test_pack_BFFCALLBACK(void)
+{
+ /* BFFCALLBACK */
+ TEST_TYPE(BFFCALLBACK, 4, 4);
+}
+
+static void test_pack_BROWSEINFOA(void)
+{
+ /* BROWSEINFOA (pack 8) */
+ TEST_TYPE(BROWSEINFOA, 32, 4);
+ TEST_FIELD(BROWSEINFOA, HWND, hwndOwner, 0, 4, 4);
+ TEST_FIELD(BROWSEINFOA, LPCITEMIDLIST, pidlRoot, 4, 4, 4);
+ TEST_FIELD(BROWSEINFOA, LPSTR, pszDisplayName, 8, 4, 4);
+ TEST_FIELD(BROWSEINFOA, LPCSTR, lpszTitle, 12, 4, 4);
+ TEST_FIELD(BROWSEINFOA, UINT, ulFlags, 16, 4, 4);
+ TEST_FIELD(BROWSEINFOA, BFFCALLBACK, lpfn, 20, 4, 4);
+ TEST_FIELD(BROWSEINFOA, LPARAM, lParam, 24, 4, 4);
+ TEST_FIELD(BROWSEINFOA, INT, iImage, 28, 4, 4);
+}
+
+static void test_pack_BROWSEINFOW(void)
+{
+ /* BROWSEINFOW (pack 8) */
+ TEST_TYPE(BROWSEINFOW, 32, 4);
+ TEST_FIELD(BROWSEINFOW, HWND, hwndOwner, 0, 4, 4);
+ TEST_FIELD(BROWSEINFOW, LPCITEMIDLIST, pidlRoot, 4, 4, 4);
+ TEST_FIELD(BROWSEINFOW, LPWSTR, pszDisplayName, 8, 4, 4);
+ TEST_FIELD(BROWSEINFOW, LPCWSTR, lpszTitle, 12, 4, 4);
+ TEST_FIELD(BROWSEINFOW, UINT, ulFlags, 16, 4, 4);
+ TEST_FIELD(BROWSEINFOW, BFFCALLBACK, lpfn, 20, 4, 4);
+ TEST_FIELD(BROWSEINFOW, LPARAM, lParam, 24, 4, 4);
+ TEST_FIELD(BROWSEINFOW, INT, iImage, 28, 4, 4);
+}
+
+static void test_pack_CABINETSTATE(void)
+{
+ /* CABINETSTATE (pack 1) */
+ TEST_TYPE(CABINETSTATE, 12, 1);
+ TEST_FIELD(CABINETSTATE, WORD, cLength, 0, 2, 1);
+ TEST_FIELD(CABINETSTATE, WORD, nVersion, 2, 2, 1);
+ TEST_FIELD(CABINETSTATE, UINT, fMenuEnumFilter, 8, 4, 1);
+}
+
+static void test_pack_CIDA(void)
+{
+ /* CIDA (pack 1) */
+ TEST_TYPE(CIDA, 8, 1);
+ TEST_FIELD(CIDA, UINT, cidl, 0, 4, 1);
+ TEST_FIELD(CIDA, UINT[1], aoffset, 4, 4, 1);
+}
+
+static void test_pack_CSFV(void)
+{
+ /* CSFV (pack 1) */
+ TEST_FIELD(CSFV, UINT, cbSize, 0, 4, 1);
+ TEST_FIELD(CSFV, IShellFolder*, pshf, 4, 4, 1);
+ TEST_FIELD(CSFV, IShellView*, psvOuter, 8, 4, 1);
+ TEST_FIELD(CSFV, LPCITEMIDLIST, pidl, 12, 4, 1);
+ TEST_FIELD(CSFV, LONG, lEvents, 16, 4, 1);
+ TEST_FIELD(CSFV, LPFNVIEWCALLBACK, pfnCallback, 20, 4, 1);
+}
+
+static void test_pack_DROPFILES(void)
+{
+ /* DROPFILES (pack 1) */
+ TEST_TYPE(DROPFILES, 20, 1);
+ TEST_FIELD(DROPFILES, DWORD, pFiles, 0, 4, 1);
+ TEST_FIELD(DROPFILES, POINT, pt, 4, 8, 1);
+ TEST_FIELD(DROPFILES, BOOL, fNC, 12, 4, 1);
+ TEST_FIELD(DROPFILES, BOOL, fWide, 16, 4, 1);
+}
+
+static void test_pack_FILEDESCRIPTORA(void)
+{
+ /* FILEDESCRIPTORA (pack 1) */
+ TEST_TYPE(FILEDESCRIPTORA, 332, 1);
+ TEST_FIELD(FILEDESCRIPTORA, DWORD, dwFlags, 0, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORA, CLSID, clsid, 4, 16, 1);
+ TEST_FIELD(FILEDESCRIPTORA, SIZEL, sizel, 20, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORA, POINTL, pointl, 28, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORA, DWORD, dwFileAttributes, 36, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORA, FILETIME, ftCreationTime, 40, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORA, FILETIME, ftLastAccessTime, 48, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORA, FILETIME, ftLastWriteTime, 56, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORA, DWORD, nFileSizeHigh, 64, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORA, DWORD, nFileSizeLow, 68, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORA, CHAR[MAX_PATH], cFileName, 72, 260, 1);
+}
+
+static void test_pack_FILEDESCRIPTORW(void)
+{
+ /* FILEDESCRIPTORW (pack 1) */
+ TEST_TYPE(FILEDESCRIPTORW, 592, 1);
+ TEST_FIELD(FILEDESCRIPTORW, DWORD, dwFlags, 0, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORW, CLSID, clsid, 4, 16, 1);
+ TEST_FIELD(FILEDESCRIPTORW, SIZEL, sizel, 20, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORW, POINTL, pointl, 28, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORW, DWORD, dwFileAttributes, 36, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORW, FILETIME, ftCreationTime, 40, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORW, FILETIME, ftLastAccessTime, 48, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORW, FILETIME, ftLastWriteTime, 56, 8, 1);
+ TEST_FIELD(FILEDESCRIPTORW, DWORD, nFileSizeHigh, 64, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORW, DWORD, nFileSizeLow, 68, 4, 1);
+ TEST_FIELD(FILEDESCRIPTORW, WCHAR[MAX_PATH], cFileName, 72, 520, 1);
+}
+
+static void test_pack_FILEGROUPDESCRIPTORA(void)
+{
+ /* FILEGROUPDESCRIPTORA (pack 1) */
+ TEST_TYPE(FILEGROUPDESCRIPTORA, 336, 1);
+ TEST_FIELD(FILEGROUPDESCRIPTORA, UINT, cItems, 0, 4, 1);
+ TEST_FIELD(FILEGROUPDESCRIPTORA, FILEDESCRIPTORA[1], fgd, 4, 332, 1);
+}
+
+static void test_pack_FILEGROUPDESCRIPTORW(void)
+{
+ /* FILEGROUPDESCRIPTORW (pack 1) */
+ TEST_TYPE(FILEGROUPDESCRIPTORW, 596, 1);
+ TEST_FIELD(FILEGROUPDESCRIPTORW, UINT, cItems, 0, 4, 1);
+ TEST_FIELD(FILEGROUPDESCRIPTORW, FILEDESCRIPTORW[1], fgd, 4, 592, 1);
+}
+
+static void test_pack_IFileSystemBindData(void)
+{
+ /* IFileSystemBindData */
+}
+
+static void test_pack_IFileSystemBindDataVtbl(void)
+{
+ /* IFileSystemBindDataVtbl */
+}
+
+static void test_pack_IShellChangeNotify(void)
+{
+ /* IShellChangeNotify */
+}
+
+static void test_pack_IShellIcon(void)
+{
+ /* IShellIcon */
+}
+
+static void test_pack_LPBROWSEINFOA(void)
+{
+ /* LPBROWSEINFOA */
+ TEST_TYPE(LPBROWSEINFOA, 4, 4);
+ TEST_TYPE_POINTER(LPBROWSEINFOA, 32, 4);
+}
+
+static void test_pack_LPBROWSEINFOW(void)
+{
+ /* LPBROWSEINFOW */
+ TEST_TYPE(LPBROWSEINFOW, 4, 4);
+ TEST_TYPE_POINTER(LPBROWSEINFOW, 32, 4);
+}
+
+static void test_pack_LPCABINETSTATE(void)
+{
+ /* LPCABINETSTATE */
+ TEST_TYPE(LPCABINETSTATE, 4, 4);
+ TEST_TYPE_POINTER(LPCABINETSTATE, 12, 1);
+}
+
+static void test_pack_LPCSFV(void)
+{
+ /* LPCSFV */
+ TEST_TYPE(LPCSFV, 4, 4);
+}
+
+static void test_pack_LPDROPFILES(void)
+{
+ /* LPDROPFILES */
+ TEST_TYPE(LPDROPFILES, 4, 4);
+ TEST_TYPE_POINTER(LPDROPFILES, 20, 1);
+}
+
+static void test_pack_LPFILEDESCRIPTORA(void)
+{
+ /* LPFILEDESCRIPTORA */
+ TEST_TYPE(LPFILEDESCRIPTORA, 4, 4);
+ TEST_TYPE_POINTER(LPFILEDESCRIPTORA, 332, 1);
+}
+
+static void test_pack_LPFILEDESCRIPTORW(void)
+{
+ /* LPFILEDESCRIPTORW */
+ TEST_TYPE(LPFILEDESCRIPTORW, 4, 4);
+ TEST_TYPE_POINTER(LPFILEDESCRIPTORW, 592, 1);
+}
+
+static void test_pack_LPFILEGROUPDESCRIPTORA(void)
+{
+ /* LPFILEGROUPDESCRIPTORA */
+ TEST_TYPE(LPFILEGROUPDESCRIPTORA, 4, 4);
+ TEST_TYPE_POINTER(LPFILEGROUPDESCRIPTORA, 336, 1);
+}
+
+static void test_pack_LPFILEGROUPDESCRIPTORW(void)
+{
+ /* LPFILEGROUPDESCRIPTORW */
+ TEST_TYPE(LPFILEGROUPDESCRIPTORW, 4, 4);
+ TEST_TYPE_POINTER(LPFILEGROUPDESCRIPTORW, 596, 1);
+}
+
+static void test_pack_LPFNVIEWCALLBACK(void)
+{
+ /* LPFNVIEWCALLBACK */
+ TEST_TYPE(LPFNVIEWCALLBACK, 4, 4);
+}
+
+static void test_pack_LPIDA(void)
+{
+ /* LPIDA */
+ TEST_TYPE(LPIDA, 4, 4);
+ TEST_TYPE_POINTER(LPIDA, 8, 1);
+}
+
+static void test_pack_LPQCMINFO(void)
+{
+ /* LPQCMINFO */
+ TEST_TYPE(LPQCMINFO, 4, 4);
+ TEST_TYPE_POINTER(LPQCMINFO, 20, 4);
+}
+
+static void test_pack_LPSHChangeDWORDAsIDList(void)
+{
+ /* LPSHChangeDWORDAsIDList */
+ TEST_TYPE(LPSHChangeDWORDAsIDList, 4, 4);
+ TEST_TYPE_POINTER(LPSHChangeDWORDAsIDList, 12, 1);
+}
+
+static void test_pack_LPSHChangeProductKeyAsIDList(void)
+{
+ /* LPSHChangeProductKeyAsIDList */
+ TEST_TYPE(LPSHChangeProductKeyAsIDList, 4, 4);
+ TEST_TYPE_POINTER(LPSHChangeProductKeyAsIDList, 82, 1);
+}
+
+static void test_pack_LPSHDESCRIPTIONID(void)
+{
+ /* LPSHDESCRIPTIONID */
+ TEST_TYPE(LPSHDESCRIPTIONID, 4, 4);
+ TEST_TYPE_POINTER(LPSHDESCRIPTIONID, 20, 4);
+}
+
+static void test_pack_LPSHELLFLAGSTATE(void)
+{
+ /* LPSHELLFLAGSTATE */
+ TEST_TYPE(LPSHELLFLAGSTATE, 4, 4);
+ TEST_TYPE_POINTER(LPSHELLFLAGSTATE, 4, 1);
+}
+
+static void test_pack_LPSHELLSTATE(void)
+{
+ /* LPSHELLSTATE */
+ TEST_TYPE(LPSHELLSTATE, 4, 4);
+ TEST_TYPE_POINTER(LPSHELLSTATE, 32, 1);
+}
+
+static void test_pack_LPTBINFO(void)
+{
+ /* LPTBINFO */
+ TEST_TYPE(LPTBINFO, 4, 4);
+ TEST_TYPE_POINTER(LPTBINFO, 8, 4);
+}
+
+static void test_pack_PBROWSEINFOA(void)
+{
+ /* PBROWSEINFOA */
+ TEST_TYPE(PBROWSEINFOA, 4, 4);
+ TEST_TYPE_POINTER(PBROWSEINFOA, 32, 4);
+}
+
+static void test_pack_PBROWSEINFOW(void)
+{
+ /* PBROWSEINFOW */
+ TEST_TYPE(PBROWSEINFOW, 4, 4);
+ TEST_TYPE_POINTER(PBROWSEINFOW, 32, 4);
+}
+
+static void test_pack_QCMINFO(void)
+{
+ /* QCMINFO (pack 8) */
+ TEST_TYPE(QCMINFO, 20, 4);
+ TEST_FIELD(QCMINFO, HMENU, hmenu, 0, 4, 4);
+ TEST_FIELD(QCMINFO, UINT, indexMenu, 4, 4, 4);
+ TEST_FIELD(QCMINFO, UINT, idCmdFirst, 8, 4, 4);
+ TEST_FIELD(QCMINFO, UINT, idCmdLast, 12, 4, 4);
+ TEST_FIELD(QCMINFO, QCMINFO_IDMAP const*, pIdMap, 16, 4, 4);
+}
+
+static void test_pack_QCMINFO_IDMAP(void)
+{
+ /* QCMINFO_IDMAP (pack 8) */
+ TEST_TYPE(QCMINFO_IDMAP, 12, 4);
+ TEST_FIELD(QCMINFO_IDMAP, UINT, nMaxIds, 0, 4, 4);
+ TEST_FIELD(QCMINFO_IDMAP, QCMINFO_IDMAP_PLACEMENT[1], pIdList, 4, 8, 4);
+}
+
+static void test_pack_QCMINFO_IDMAP_PLACEMENT(void)
+{
+ /* QCMINFO_IDMAP_PLACEMENT (pack 8) */
+ TEST_TYPE(QCMINFO_IDMAP_PLACEMENT, 8, 4);
+ TEST_FIELD(QCMINFO_IDMAP_PLACEMENT, UINT, id, 0, 4, 4);
+ TEST_FIELD(QCMINFO_IDMAP_PLACEMENT, UINT, fFlags, 4, 4, 4);
+}
+
+static void test_pack_SHChangeDWORDAsIDList(void)
+{
+ /* SHChangeDWORDAsIDList (pack 1) */
+ TEST_TYPE(SHChangeDWORDAsIDList, 12, 1);
+ TEST_FIELD(SHChangeDWORDAsIDList, USHORT, cb, 0, 2, 1);
+ TEST_FIELD(SHChangeDWORDAsIDList, DWORD, dwItem1, 2, 4, 1);
+ TEST_FIELD(SHChangeDWORDAsIDList, DWORD, dwItem2, 6, 4, 1);
+ TEST_FIELD(SHChangeDWORDAsIDList, USHORT, cbZero, 10, 2, 1);
+}
+
+static void test_pack_SHChangeNotifyEntry(void)
+{
+ /* SHChangeNotifyEntry (pack 1) */
+ TEST_TYPE(SHChangeNotifyEntry, 8, 1);
+ TEST_FIELD(SHChangeNotifyEntry, LPCITEMIDLIST, pidl, 0, 4, 1);
+ TEST_FIELD(SHChangeNotifyEntry, BOOL, fRecursive, 4, 4, 1);
+}
+
+static void test_pack_SHChangeProductKeyAsIDList(void)
+{
+ /* SHChangeProductKeyAsIDList (pack 1) */
+ TEST_TYPE(SHChangeProductKeyAsIDList, 82, 1);
+ TEST_FIELD(SHChangeProductKeyAsIDList, USHORT, cb, 0, 2, 1);
+ TEST_FIELD(SHChangeProductKeyAsIDList, WCHAR[39], wszProductKey, 2, 78, 1);
+ TEST_FIELD(SHChangeProductKeyAsIDList, USHORT, cbZero, 80, 2, 1);
+}
+
+static void test_pack_SHDESCRIPTIONID(void)
+{
+ /* SHDESCRIPTIONID (pack 8) */
+ TEST_TYPE(SHDESCRIPTIONID, 20, 4);
+ TEST_FIELD(SHDESCRIPTIONID, DWORD, dwDescriptionId, 0, 4, 4);
+ TEST_FIELD(SHDESCRIPTIONID, CLSID, clsid, 4, 16, 4);
+}
+
+static void test_pack_SHELLFLAGSTATE(void)
+{
+ /* SHELLFLAGSTATE (pack 1) */
+ TEST_TYPE(SHELLFLAGSTATE, 4, 1);
+}
+
+static void test_pack_SHELLSTATE(void)
+{
+ /* SHELLSTATE (pack 1) */
+ TEST_TYPE(SHELLSTATE, 32, 1);
+ TEST_FIELD(SHELLSTATE, DWORD, dwWin95Unused, 4, 4, 1);
+ TEST_FIELD(SHELLSTATE, UINT, uWin95Unused, 8, 4, 1);
+ TEST_FIELD(SHELLSTATE, LONG, lParamSort, 12, 4, 1);
+ TEST_FIELD(SHELLSTATE, int, iSortDirection, 16, 4, 1);
+ TEST_FIELD(SHELLSTATE, UINT, version, 20, 4, 1);
+ TEST_FIELD(SHELLSTATE, UINT, uNotUsed, 24, 4, 1);
+}
+
+static void test_pack_SHELLVIEWID(void)
+{
+ /* SHELLVIEWID */
+ TEST_TYPE(SHELLVIEWID, 16, 4);
+}
+
+static void test_pack_TBINFO(void)
+{
+ /* TBINFO (pack 8) */
+ TEST_TYPE(TBINFO, 8, 4);
+ TEST_FIELD(TBINFO, UINT, cbuttons, 0, 4, 4);
+ TEST_FIELD(TBINFO, UINT, uFlags, 4, 4, 4);
+}
+
+static void test_pack(void)
+{
+ test_pack_APPBARDATA();
+ test_pack_AUTO_SCROLL_DATA();
+ test_pack_BFFCALLBACK();
+ test_pack_BLOB();
+ test_pack_BROWSEINFOA();
+ test_pack_BROWSEINFOW();
+ test_pack_BSTR();
+ test_pack_BSTRBLOB();
+ test_pack_BYTE_BLOB();
+ test_pack_BYTE_SIZEDARR();
+ test_pack_CABINETSTATE();
+ test_pack_CIDA();
+ test_pack_CLIPDATA();
+ test_pack_CLIPFORMAT();
+ test_pack_CLSID();
+ test_pack_COAUTHIDENTITY();
+ test_pack_COAUTHINFO();
+ test_pack_COSERVERINFO();
+ test_pack_CSFV();
+ test_pack_DRAGINFOA();
+ test_pack_DRAGINFOW();
+ test_pack_DROPFILES();
+ test_pack_DWORD_SIZEDARR();
+ test_pack_FILEDESCRIPTORA();
+ test_pack_FILEDESCRIPTORW();
+ test_pack_FILEGROUPDESCRIPTORA();
+ test_pack_FILEGROUPDESCRIPTORW();
+ test_pack_FILEOP_FLAGS();
+ test_pack_FLAGGED_BYTE_BLOB();
+ test_pack_FLAGGED_WORD_BLOB();
+ test_pack_FMTID();
+ test_pack_GUID();
+ test_pack_HMETAFILEPICT();
+ test_pack_HYPER_SIZEDARR();
+ test_pack_IFileSystemBindData();
+ test_pack_IFileSystemBindDataVtbl();
+ test_pack_IID();
+ test_pack_IShellChangeNotify();
+ test_pack_IShellIcon();
+ test_pack_ITEMIDLIST();
+ test_pack_LPBLOB();
+ test_pack_LPBROWSEINFOA();
+ test_pack_LPBROWSEINFOW();
+ test_pack_LPBSTR();
+ test_pack_LPBSTRBLOB();
+ test_pack_LPCABINETSTATE();
+ test_pack_LPCITEMIDLIST();
+ test_pack_LPCOLESTR();
+ test_pack_LPCSFV();
+ test_pack_LPCSHITEMID();
+ test_pack_LPCY();
+ test_pack_LPDECIMAL();
+ test_pack_LPDRAGINFOA();
+ test_pack_LPDRAGINFOW();
+ test_pack_LPDROPFILES();
+ test_pack_LPFILEDESCRIPTORA();
+ test_pack_LPFILEDESCRIPTORW();
+ test_pack_LPFILEGROUPDESCRIPTORA();
+ test_pack_LPFILEGROUPDESCRIPTORW();
+ test_pack_LPFNVIEWCALLBACK();
+ test_pack_LPGUID();
+ test_pack_LPIDA();
+ test_pack_LPITEMIDLIST();
+ test_pack_LPOLESTR();
+ test_pack_LPQCMINFO();
+ test_pack_LPSHChangeDWORDAsIDList();
+ test_pack_LPSHChangeProductKeyAsIDList();
+ test_pack_LPSHDESCRIPTIONID();
+ test_pack_LPSHELLDETAILS();
+ test_pack_LPSHELLEXECUTEINFOA();
+ test_pack_LPSHELLEXECUTEINFOW();
+ test_pack_LPSHELLFLAGSTATE();
+ test_pack_LPSHELLSTATE();
+ test_pack_LPSHFILEOPSTRUCTA();
+ test_pack_LPSHFILEOPSTRUCTW();
+ test_pack_LPSHITEMID();
+ test_pack_LPSHNAMEMAPPINGA();
+ test_pack_LPSHNAMEMAPPINGW();
+ test_pack_LPSTRRET();
+ test_pack_LPTBINFO();
+ test_pack_NOTIFYICONDATAA();
+ test_pack_NOTIFYICONDATAW();
+ test_pack_OLECHAR();
+ test_pack_PAPPBARDATA();
+ test_pack_PBROWSEINFOA();
+ test_pack_PBROWSEINFOW();
+ test_pack_PNOTIFYICONDATAA();
+ test_pack_PNOTIFYICONDATAW();
+ test_pack_PRINTEROP_FLAGS();
+ test_pack_PROPID();
+ test_pack_QCMINFO();
+ test_pack_QCMINFO_IDMAP();
+ test_pack_QCMINFO_IDMAP_PLACEMENT();
+ test_pack_RemHBITMAP();
+ test_pack_RemHENHMETAFILE();
+ test_pack_RemHGLOBAL();
+ test_pack_RemHMETAFILEPICT();
+ test_pack_RemHPALETTE();
+ test_pack_SCODE();
+ test_pack_SHChangeDWORDAsIDList();
+ test_pack_SHChangeNotifyEntry();
+ test_pack_SHChangeProductKeyAsIDList();
+ test_pack_SHDESCRIPTIONID();
+ test_pack_SHELLDETAILS();
+ test_pack_SHELLEXECUTEINFOA();
+ test_pack_SHELLEXECUTEINFOW();
+ test_pack_SHELLFLAGSTATE();
+ test_pack_SHELLSTATE();
+ test_pack_SHELLVIEWID();
+ test_pack_SHFILEINFOA();
+ test_pack_SHFILEINFOW();
+ test_pack_SHFILEOPSTRUCTA();
+ test_pack_SHFILEOPSTRUCTW();
+ test_pack_SHITEMID();
+ test_pack_SHNAMEMAPPINGA();
+ test_pack_SHNAMEMAPPINGW();
+ test_pack_STRRET();
+ test_pack_TBINFO();
+ test_pack_UP_BYTE_BLOB();
+ test_pack_UP_FLAGGED_BYTE_BLOB();
+ test_pack_UP_FLAGGED_WORD_BLOB();
+ test_pack_VARIANT_BOOL();
+ test_pack_VARTYPE();
+ test_pack_WORD_SIZEDARR();
+ test_pack_remoteMETAFILEPICT();
+ test_pack_userBITMAP();
+ test_pack_userCLIPFORMAT();
+ test_pack_userHBITMAP();
+ test_pack_userHENHMETAFILE();
+ test_pack_userHGLOBAL();
+ test_pack_userHMETAFILE();
+ test_pack_userHMETAFILEPICT();
+ test_pack_userHPALETTE();
+ test_pack_wireBSTR();
+ test_pack_wireCLIPFORMAT();
+ test_pack_wireHBITMAP();
+ test_pack_wireHENHMETAFILE();
+ test_pack_wireHGLOBAL();
+ test_pack_wireHMETAFILE();
+ test_pack_wireHMETAFILEPICT();
+ test_pack_wireHPALETTE();
+}
+
+START_TEST(generated)
+{
+ test_pack();
+}
--- /dev/null
+<module name="shell32_winetest" type="win32cui" installbase="bin" installname="shell32_winetest.exe" warnings="true">
+ <include base="shell32_winetest">.</include>
+ <define name="__USE_W32API" />
+ <library>ntdll</library>
+ <library>shell32</library>
+ <library>shlwapi</library>
+ <library>ole32</library>
+ <library>uuid</library>
+ <file>shelllink.c</file>
+ <file>shellpath.c</file>
+ <file>shlexec.c</file>
+ <file>shlfileop.c</file>
+ <file>shlfolder.c</file>
+ <file>string.c</file>
+ <file>testlist.c</file>
+</module>
--- /dev/null
+/*
+ * Unit test suite for shell32 functions
+ *
+ * Copyright 2005 Francois Gougett for CodeWeavers
+ *
+ * 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
+ */
+
+
+/* Helper function for creating .lnk files */
+typedef struct
+{
+ const char* description;
+ const char* workdir;
+ const char* path;
+ LPITEMIDLIST pidl;
+ const char* arguments;
+ int showcmd;
+ const char* icon;
+ int icon_id;
+ WORD hotkey;
+} lnk_desc_t;
+
+#define create_lnk(a,b,c) create_lnk_(__LINE__, (a), (b), (c))
+void create_lnk_(int,const WCHAR*,lnk_desc_t*,int);
--- /dev/null
+/*
+ * Unit tests for shelllinks
+ *
+ * Copyright 2004 Mike McCormack
+ *
+ * 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
+ * This is a test program for the SHGet{Special}Folder{Path|Location} functions
+ * of shell32, that get either a filesytem path or a LPITEMIDLIST (shell
+ * namespace) path for a given folder (CSIDL value).
+ *
+ */
+
+#define _WIN32_IE 0x0400
+
+#define COBJMACROS
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "windef.h"
+#include "winbase.h"
+#include "shlguid.h"
+//#include "wine/shobjidl.h"
+#include "shlobj.h"
+#include "wine/test.h"
+
+#include "shell32_test.h"
+
+extern BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
+extern HRESULT WINAPI SHILCreateFromPath(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes);
+extern void WINAPI ILFree(LPITEMIDLIST pidl);
+
+static const WCHAR lnkfile[]= { 'C',':','\\','t','e','s','t','.','l','n','k',0 };
+static const WCHAR notafile[]= { 'C',':','\\','n','o','n','e','x','i','s','t','e','n','t','\\','f','i','l','e',0 };
+
+
+/* For some reason SHILCreateFromPath does not work on Win98 and
+ * SHSimpleIDListFromPathA does not work on NT4. But if we call both we
+ * get what we want on all platforms.
+ */
+static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathA)(LPCSTR)=NULL;
+
+static LPITEMIDLIST path_to_pidl(const char* path)
+{
+ LPITEMIDLIST pidl;
+
+ if (!pSHSimpleIDListFromPathA)
+ {
+ HMODULE hdll=LoadLibraryA("shell32.dll");
+ pSHSimpleIDListFromPathA=(void*)GetProcAddress(hdll, (char*)162);
+ if (!pSHSimpleIDListFromPathA)
+ trace("SHSimpleIDListFromPathA not found in shell32.dll\n");
+ }
+
+ pidl=NULL;
+ if (pSHSimpleIDListFromPathA)
+ pidl=pSHSimpleIDListFromPathA(path);
+
+ if (!pidl)
+ {
+ WCHAR* pathW;
+ HRESULT r;
+ int len;
+
+ len=MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
+ pathW=HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
+
+ r=SHILCreateFromPath(pathW, &pidl, NULL);
+ todo_wine {
+ ok(SUCCEEDED(r), "SHILCreateFromPath failed (0x%08lx)\n", r);
+ }
+ HeapFree(GetProcessHeap(), 0, pathW);
+ }
+ return pidl;
+}
+
+
+/*
+ * Test manipulation of an IShellLink's properties.
+ */
+
+static void test_get_set(void)
+{
+ HRESULT r;
+ IShellLinkA *sl;
+ char mypath[MAX_PATH];
+ char buffer[INFOTIPSIZE];
+ LPITEMIDLIST pidl, tmp_pidl;
+ const char * str;
+ int i;
+ WORD w;
+
+ r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkA, (LPVOID*)&sl);
+ ok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
+ if (!SUCCEEDED(r))
+ return;
+
+ /* Test Getting / Setting the description */
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
+ ok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
+ ok(*buffer=='\0', "GetDescription returned '%s'\n", buffer);
+
+ str="Some description";
+ r = IShellLinkA_SetDescription(sl, str);
+ ok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
+
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
+ ok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
+ ok(lstrcmp(buffer,str)==0, "GetDescription returned '%s'\n", buffer);
+
+ /* Test Getting / Setting the work directory */
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
+ ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
+ ok(*buffer=='\0', "GetWorkingDirectory returned '%s'\n", buffer);
+
+ str="c:\\nonexistent\\directory";
+ r = IShellLinkA_SetWorkingDirectory(sl, str);
+ ok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08lx)\n", r);
+
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
+ ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
+ ok(lstrcmpi(buffer,str)==0, "GetWorkingDirectory returned '%s'\n", buffer);
+
+ /* Test Getting / Setting the work directory */
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
+
+ r = IShellLinkA_SetPath(sl, "");
+ ok(r==S_OK, "SetPath failed (0x%08lx)\n", r);
+
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
+
+ str="c:\\nonexistent\\file";
+ r = IShellLinkA_SetPath(sl, str);
+ ok(r==S_FALSE, "SetPath failed (0x%08lx)\n", r);
+
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(lstrcmpi(buffer,str)==0, "GetPath returned '%s'\n", buffer);
+
+ /* Get some a real path to play with */
+ r=GetModuleFileName(NULL, mypath, sizeof(mypath));
+ ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%ld)\n", r);
+
+ /* Test the interaction of SetPath and SetIDList */
+ tmp_pidl=NULL;
+ r = IShellLinkA_GetIDList(sl, &tmp_pidl);
+ ok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
+ if (SUCCEEDED(r))
+ {
+ strcpy(buffer,"garbage");
+ r=SHGetPathFromIDListA(tmp_pidl, buffer);
+ todo_wine {
+ ok(r, "SHGetPathFromIDListA failed\n");
+ }
+ if (r)
+ ok(lstrcmpi(buffer,str)==0, "GetIDList returned '%s'\n", buffer);
+ }
+
+ pidl=path_to_pidl(mypath);
+ todo_wine {
+ ok(pidl!=NULL, "path_to_pidl returned a NULL pidl\n");
+ }
+
+ if (pidl)
+ {
+ r = IShellLinkA_SetIDList(sl, pidl);
+ ok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\n", r);
+
+ tmp_pidl=NULL;
+ r = IShellLinkA_GetIDList(sl, &tmp_pidl);
+ ok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
+ ok(tmp_pidl && ILIsEqual(pidl, tmp_pidl),
+ "GetIDList returned an incorrect pidl\n");
+
+ /* tmp_pidl is owned by IShellLink so we don't free it */
+ ILFree(pidl);
+
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
+ ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ ok(lstrcmpi(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
+ }
+
+ /* Test Getting / Setting the arguments */
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
+ ok(SUCCEEDED(r), "GetArguments failed (0x%08lx)\n", r);
+ ok(*buffer=='\0', "GetArguments returned '%s'\n", buffer);
+
+ str="param1 \"spaced param2\"";
+ r = IShellLinkA_SetArguments(sl, str);
+ ok(SUCCEEDED(r), "SetArguments failed (0x%08lx)\n", r);
+
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
+ ok(SUCCEEDED(r), "GetArguments failed (0x%08lx)\n", r);
+ ok(lstrcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
+
+ /* Test Getting / Setting showcmd */
+ i=0xdeadbeef;
+ r = IShellLinkA_GetShowCmd(sl, &i);
+ ok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
+ ok(i==SW_SHOWNORMAL, "GetShowCmd returned %d\n", i);
+
+ r = IShellLinkA_SetShowCmd(sl, SW_SHOWMAXIMIZED);
+ ok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
+
+ i=0xdeadbeef;
+ r = IShellLinkA_GetShowCmd(sl, &i);
+ ok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
+ ok(i==SW_SHOWMAXIMIZED, "GetShowCmd returned %d'\n", i);
+
+ /* Test Getting / Setting the icon */
+ i=0xdeadbeef;
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+ todo_wine {
+ ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
+ }
+ ok(*buffer=='\0', "GetIconLocation returned '%s'\n", buffer);
+ ok(i==0, "GetIconLocation returned %d\n", i);
+
+ str="c:\\nonexistent\\file";
+ r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
+ ok(SUCCEEDED(r), "SetIconLocation failed (0x%08lx)\n", r);
+
+ i=0xdeadbeef;
+ r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+ ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
+ ok(lstrcmpi(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
+ ok(i==0xbabecafe, "GetIconLocation returned %d'\n", i);
+
+ /* Test Getting / Setting the hot key */
+ w=0xbeef;
+ r = IShellLinkA_GetHotkey(sl, &w);
+ ok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
+ ok(w==0, "GetHotkey returned %d\n", w);
+
+ r = IShellLinkA_SetHotkey(sl, 0x5678);
+ ok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
+
+ w=0xbeef;
+ r = IShellLinkA_GetHotkey(sl, &w);
+ ok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
+ ok(w==0x5678, "GetHotkey returned %d'\n", w);
+
+ IShellLinkA_Release(sl);
+}
+
+
+/*
+ * Test saving and loading .lnk files
+ */
+
+#define lok ok_(__FILE__, line)
+#define check_lnk(a,b) check_lnk_(__LINE__, (a), (b))
+
+void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int save_fails)
+{
+ HRESULT r;
+ IShellLinkA *sl;
+ IPersistFile *pf;
+
+ r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkA, (LPVOID*)&sl);
+ lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
+ if (!SUCCEEDED(r))
+ return;
+
+ if (desc->description)
+ {
+ r = IShellLinkA_SetDescription(sl, desc->description);
+ lok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
+ }
+ if (desc->workdir)
+ {
+ r = IShellLinkA_SetWorkingDirectory(sl, desc->workdir);
+ lok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08lx)\n", r);
+ }
+ if (desc->path)
+ {
+ r = IShellLinkA_SetPath(sl, desc->path);
+ lok(SUCCEEDED(r), "SetPath failed (0x%08lx)\n", r);
+ }
+ if (desc->pidl)
+ {
+ r = IShellLinkA_SetIDList(sl, desc->pidl);
+ lok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\n", r);
+ }
+ if (desc->arguments)
+ {
+ r = IShellLinkA_SetArguments(sl, desc->arguments);
+ lok(SUCCEEDED(r), "SetArguments failed (0x%08lx)\n", r);
+ }
+ if (desc->showcmd)
+ {
+ r = IShellLinkA_SetShowCmd(sl, desc->showcmd);
+ lok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
+ }
+ if (desc->icon)
+ {
+ r = IShellLinkA_SetIconLocation(sl, desc->icon, desc->icon_id);
+ lok(SUCCEEDED(r), "SetIconLocation failed (0x%08lx)\n", r);
+ }
+ if (desc->hotkey)
+ {
+ r = IShellLinkA_SetHotkey(sl, desc->hotkey);
+ lok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
+ }
+
+ r = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
+ lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\n", r);
+ if (SUCCEEDED(r))
+ {
+ r = IPersistFile_Save(pf, path, TRUE);
+ if (save_fails)
+ {
+ todo_wine {
+ lok(SUCCEEDED(r), "save failed (0x%08lx)\n", r);
+ }
+ }
+ else
+ {
+ lok(SUCCEEDED(r), "save failed (0x%08lx)\n", r);
+ }
+ IPersistFile_Release(pf);
+ }
+
+ IShellLinkA_Release(sl);
+}
+
+static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
+{
+ HRESULT r;
+ IShellLinkA *sl;
+ IPersistFile *pf;
+ char buffer[INFOTIPSIZE];
+
+ r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkA, (LPVOID*)&sl);
+ lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
+ if (!SUCCEEDED(r))
+ return;
+
+ r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
+ lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\n", r);
+ if (!SUCCEEDED(r))
+ {
+ IShellLinkA_Release(sl);
+ return;
+ }
+
+ r = IPersistFile_Load(pf, path, STGM_READ);
+ lok(SUCCEEDED(r), "load failed (0x%08lx)\n", r);
+ IPersistFile_Release(pf);
+ if (!SUCCEEDED(r))
+ {
+ IShellLinkA_Release(sl);
+ return;
+ }
+
+ if (desc->description)
+ {
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
+ lok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
+ lok(lstrcmp(buffer, desc->description)==0,
+ "GetDescription returned '%s' instead of '%s'\n",
+ buffer, desc->description);
+ }
+ if (desc->workdir)
+ {
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
+ lok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
+ lok(lstrcmpi(buffer, desc->workdir)==0,
+ "GetWorkingDirectory returned '%s' instead of '%s'\n",
+ buffer, desc->workdir);
+ }
+ if (desc->path)
+ {
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
+ lok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
+ lok(lstrcmpi(buffer, desc->path)==0,
+ "GetPath returned '%s' instead of '%s'\n",
+ buffer, desc->path);
+ }
+ if (desc->pidl)
+ {
+ LPITEMIDLIST pidl=NULL;
+ r = IShellLinkA_GetIDList(sl, &pidl);
+ lok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
+ lok(ILIsEqual(pidl, desc->pidl),
+ "GetIDList returned an incorrect pidl\n");
+ }
+ if (desc->showcmd)
+ {
+ int i=0xdeadbeef;
+ r = IShellLinkA_GetShowCmd(sl, &i);
+ lok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
+ lok(i==desc->showcmd,
+ "GetShowCmd returned 0x%0x instead of 0x%0x\n",
+ i, desc->showcmd);
+ }
+ if (desc->icon)
+ {
+ int i=0xdeadbeef;
+ strcpy(buffer,"garbage");
+ r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+ lok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
+ lok(lstrcmpi(buffer, desc->icon)==0,
+ "GetIconLocation returned '%s' instead of '%s'\n",
+ buffer, desc->icon);
+ lok(i==desc->icon_id,
+ "GetIconLocation returned 0x%0x instead of 0x%0x\n",
+ i, desc->icon_id);
+ }
+ if (desc->hotkey)
+ {
+ WORD i=0xbeef;
+ r = IShellLinkA_GetHotkey(sl, &i);
+ lok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
+ lok(i==desc->hotkey,
+ "GetHotkey returned 0x%04x instead of 0x%04x\n",
+ i, desc->hotkey);
+ }
+
+ IShellLinkA_Release(sl);
+}
+
+static void test_load_save(void)
+{
+ lnk_desc_t desc;
+ char mypath[MAX_PATH];
+ char mydir[MAX_PATH];
+ char* p;
+ DWORD r;
+
+ /* Save an empty .lnk file */
+ memset(&desc, 0, sizeof(desc));
+ create_lnk(lnkfile, &desc, 0);
+
+ /* It should come back as a bunch of empty strings */
+ desc.description="";
+ desc.workdir="";
+ desc.path="";
+ desc.arguments="";
+ desc.icon="";
+ check_lnk(lnkfile, &desc);
+
+
+ /* Point a .lnk file to nonexistent files */
+ desc.description="";
+ desc.workdir="c:\\Nonexitent\\work\\directory";
+ desc.path="c:\\nonexistent\\path";
+ desc.pidl=NULL;
+ desc.arguments="";
+ desc.showcmd=0;
+ desc.icon="c:\\nonexistent\\icon\\file";
+ desc.icon_id=1234;
+ desc.hotkey=0;
+ create_lnk(lnkfile, &desc, 0);
+ check_lnk(lnkfile, &desc);
+
+ r=GetModuleFileName(NULL, mypath, sizeof(mypath));
+ ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%ld)\n", r);
+ strcpy(mydir, mypath);
+ p=strrchr(mydir, '\\');
+ if (p)
+ *p='\0';
+
+
+ /* Overwrite the existing lnk file and point it to existing files */
+ desc.description="test 2";
+ desc.workdir=mydir;
+ desc.path=mypath;
+ desc.pidl=NULL;
+ desc.arguments="/option1 /option2 \"Some string\"";
+ desc.showcmd=SW_SHOWNORMAL;
+ desc.icon=mypath;
+ desc.icon_id=0;
+ desc.hotkey=0x1234;
+ create_lnk(lnkfile, &desc, 0);
+ check_lnk(lnkfile, &desc);
+
+ /* FIXME: Also test saving a .lnk pointing to a pidl that cannot be
+ * represented as a path.
+ */
+
+ /* DeleteFileW is not implemented on Win9x */
+ r=DeleteFileA("c:\\test.lnk");
+ ok(r, "failed to delete link (%ld)\n", GetLastError());
+}
+
+START_TEST(shelllink)
+{
+ HRESULT r;
+
+ r = CoInitialize(NULL);
+ ok(SUCCEEDED(r), "CoInitialize failed (0x%08lx)\n", r);
+ if (!SUCCEEDED(r))
+ return;
+
+ test_get_set();
+ test_load_save();
+
+ CoUninitialize();
+}
--- /dev/null
+/*
+ * Unit tests for shell32 SHGet{Special}Folder{Path|Location} functions.
+ *
+ * Copyright 2004 Juan Lang
+ *
+ * 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
+ * This is a test program for the SHGet{Special}Folder{Path|Location} functions
+ * of shell32, that get either a filesytem path or a LPITEMIDLIST (shell
+ * namespace) path for a given folder (CSIDL value).
+ *
+ * FIXME:
+ * - Need to verify on more systems.
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "windef.h"
+#include "winbase.h"
+#include "initguid.h"
+#include "shlguid.h"
+#include "shlobj.h"
+#include "shlwapi.h"
+#include "wine/test.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) ( sizeof(x) / sizeof((x)[0]) )
+#endif
+
+/* from pidl.h, not included here: */
+#ifndef PT_GUID
+#define PT_GUID 0x1f /* no path */
+#endif
+#ifndef PT_DRIVE
+#define PT_DRIVE 0x23 /* has path */
+#endif
+#ifndef PT_DRIVE2
+#define PT_DRIVE2 0x25 /* has path */
+#endif
+#ifndef PT_SHELLEXT
+#define PT_SHELLEXT 0x2e /* no path */
+#endif
+#ifndef PT_FOLDER
+#define PT_FOLDER 0x31 /* has path */
+#endif
+#ifndef PT_WORKGRP
+#define PT_WORKGRP 0x41 /* no path */
+#endif
+#ifndef PT_YAGUID
+#define PT_YAGUID 0x70 /* no path */
+#endif
+/* FIXME: this is used for history/favorites folders; what's a better name? */
+#ifndef PT_IESPECIAL2
+#define PT_IESPECIAL2 0xb1 /* has path */
+#endif
+
+static GUID CLSID_CommonDocuments = { 0x0000000c, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1a } };
+
+struct shellExpectedValues {
+ int folder;
+ BYTE pidlType;
+};
+
+static HMODULE hShell32;
+static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
+static HRESULT (WINAPI *pSHGetFolderLocation)(HWND, int, HANDLE, DWORD,
+ LPITEMIDLIST *);
+static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
+static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
+static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
+static int (WINAPI *pSHFileOperationA)(LPSHFILEOPSTRUCTA);
+static HRESULT (WINAPI *pSHGetMalloc)(LPMALLOC *);
+static DLLVERSIONINFO shellVersion = { 0 };
+static LPMALLOC pMalloc;
+static const struct shellExpectedValues requiredShellValues[] = {
+ { CSIDL_BITBUCKET, PT_GUID },
+ { CSIDL_CONTROLS, PT_SHELLEXT },
+ { CSIDL_COOKIES, PT_FOLDER },
+ { CSIDL_DESKTOPDIRECTORY, PT_FOLDER },
+ { CSIDL_DRIVES, PT_GUID },
+ { CSIDL_FAVORITES, PT_FOLDER },
+ { CSIDL_FONTS, PT_FOLDER },
+/* FIXME: the following fails in Wine, returns type PT_FOLDER
+ { CSIDL_HISTORY, PT_IESPECIAL2 },
+ */
+ { CSIDL_INTERNET, PT_GUID },
+ { CSIDL_NETHOOD, PT_FOLDER },
+ { CSIDL_NETWORK, PT_GUID },
+ { CSIDL_PRINTERS, PT_YAGUID },
+ { CSIDL_PRINTHOOD, PT_FOLDER },
+ { CSIDL_PROGRAMS, PT_FOLDER },
+ { CSIDL_RECENT, PT_FOLDER },
+ { CSIDL_SENDTO, PT_FOLDER },
+ { CSIDL_STARTMENU, PT_FOLDER },
+ { CSIDL_STARTUP, PT_FOLDER },
+ { CSIDL_TEMPLATES, PT_FOLDER },
+};
+static const struct shellExpectedValues optionalShellValues[] = {
+/* FIXME: the following only semi-succeed; they return NULL PIDLs on XP.. hmm.
+ { CSIDL_ALTSTARTUP, PT_FOLDER },
+ { CSIDL_COMMON_ALTSTARTUP, PT_FOLDER },
+ { CSIDL_COMMON_OEM_LINKS, PT_FOLDER },
+ */
+/* Windows NT-only: */
+ { CSIDL_COMMON_DESKTOPDIRECTORY, PT_FOLDER },
+ { CSIDL_COMMON_DOCUMENTS, PT_SHELLEXT },
+ { CSIDL_COMMON_FAVORITES, PT_FOLDER },
+ { CSIDL_COMMON_PROGRAMS, PT_FOLDER },
+ { CSIDL_COMMON_STARTMENU, PT_FOLDER },
+ { CSIDL_COMMON_STARTUP, PT_FOLDER },
+ { CSIDL_COMMON_TEMPLATES, PT_FOLDER },
+/* first appearing in shell32 version 4.71: */
+ { CSIDL_APPDATA, PT_FOLDER },
+/* first appearing in shell32 version 4.72: */
+ { CSIDL_INTERNET_CACHE, PT_IESPECIAL2 },
+/* first appearing in shell32 version 5.0: */
+ { CSIDL_ADMINTOOLS, PT_FOLDER },
+ { CSIDL_COMMON_APPDATA, PT_FOLDER },
+ { CSIDL_LOCAL_APPDATA, PT_FOLDER },
+ { CSIDL_MYDOCUMENTS, PT_FOLDER },
+ { CSIDL_MYMUSIC, PT_FOLDER },
+ { CSIDL_MYPICTURES, PT_FOLDER },
+ { CSIDL_MYVIDEO, PT_FOLDER },
+ { CSIDL_PROFILE, PT_FOLDER },
+ { CSIDL_PROGRAM_FILES, PT_FOLDER },
+ { CSIDL_PROGRAM_FILESX86, PT_FOLDER },
+ { CSIDL_PROGRAM_FILES_COMMON, PT_FOLDER },
+ { CSIDL_PROGRAM_FILES_COMMONX86, PT_FOLDER },
+ { CSIDL_SYSTEM, PT_FOLDER },
+ { CSIDL_WINDOWS, PT_FOLDER },
+/* first appearing in shell32 6.0: */
+ { CSIDL_CDBURN_AREA, PT_FOLDER },
+ { CSIDL_COMMON_MUSIC, PT_FOLDER },
+ { CSIDL_COMMON_PICTURES, PT_FOLDER },
+ { CSIDL_COMMON_VIDEO, PT_FOLDER },
+ { CSIDL_COMPUTERSNEARME, PT_WORKGRP },
+ { CSIDL_RESOURCES, PT_FOLDER },
+ { CSIDL_RESOURCES_LOCALIZED, PT_FOLDER },
+};
+
+static void loadShell32(void)
+{
+ hShell32 = LoadLibraryA("shell32");
+ if (hShell32)
+ {
+ HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO *);
+
+ pSHGetFolderPathA = (void *)GetProcAddress(hShell32,
+ "SHGetFolderPathA");
+ pSHGetFolderLocation = (void *)GetProcAddress(hShell32,
+ "SHGetFolderLocation");
+ pSHGetSpecialFolderPathA = (void *)GetProcAddress(hShell32,
+ "SHGetSpecialFolderPathA");
+ pSHGetSpecialFolderLocation = (void *)GetProcAddress(hShell32,
+ "SHGetSpecialFolderLocation");
+ pDllGetVersion = (void *)GetProcAddress(hShell32, "DllGetVersion");
+ pILFindLastID = (void *)GetProcAddress(hShell32, "ILFindLastID");
+ if (!pILFindLastID)
+ pILFindLastID = (void *)GetProcAddress(hShell32, (LPCSTR)16);
+ pSHFileOperationA = (void *)GetProcAddress(hShell32,
+ "SHFileOperationA");
+ pSHGetMalloc = (void *)GetProcAddress(hShell32, "SHGetMalloc");
+
+ ok(pSHGetMalloc != NULL, "shell32 is missing SHGetMalloc\n");
+ if (pSHGetMalloc)
+ {
+ HRESULT hr = pSHGetMalloc(&pMalloc);
+
+ ok(SUCCEEDED(hr), "SHGetMalloc failed: 0x%08lx\n", hr);
+ ok(pMalloc != NULL, "SHGetMalloc returned a NULL IMalloc\n");
+ }
+
+ if (pDllGetVersion)
+ {
+ shellVersion.cbSize = sizeof(shellVersion);
+ pDllGetVersion(&shellVersion);
+ if (winetest_interactive)
+ printf("shell32 version is %ld.%ld\n",
+ shellVersion.dwMajorVersion, shellVersion.dwMinorVersion);
+ }
+ }
+}
+
+#ifndef CSIDL_PROFILES
+#define CSIDL_PROFILES 0x003e
+#endif
+
+/* A couple utility printing functions */
+static const char *getFolderName(int folder)
+{
+ static char unknown[17];
+
+#define CSIDL_TO_STR(x) case x: return#x;
+ switch (folder)
+ {
+ CSIDL_TO_STR(CSIDL_DESKTOP);
+ CSIDL_TO_STR(CSIDL_INTERNET);
+ CSIDL_TO_STR(CSIDL_PROGRAMS);
+ CSIDL_TO_STR(CSIDL_CONTROLS);
+ CSIDL_TO_STR(CSIDL_PRINTERS);
+ CSIDL_TO_STR(CSIDL_PERSONAL);
+ CSIDL_TO_STR(CSIDL_FAVORITES);
+ CSIDL_TO_STR(CSIDL_STARTUP);
+ CSIDL_TO_STR(CSIDL_RECENT);
+ CSIDL_TO_STR(CSIDL_SENDTO);
+ CSIDL_TO_STR(CSIDL_BITBUCKET);
+ CSIDL_TO_STR(CSIDL_STARTMENU);
+ CSIDL_TO_STR(CSIDL_MYDOCUMENTS);
+ CSIDL_TO_STR(CSIDL_MYMUSIC);
+ CSIDL_TO_STR(CSIDL_MYVIDEO);
+ CSIDL_TO_STR(CSIDL_DESKTOPDIRECTORY);
+ CSIDL_TO_STR(CSIDL_DRIVES);
+ CSIDL_TO_STR(CSIDL_NETWORK);
+ CSIDL_TO_STR(CSIDL_NETHOOD);
+ CSIDL_TO_STR(CSIDL_FONTS);
+ CSIDL_TO_STR(CSIDL_TEMPLATES);
+ CSIDL_TO_STR(CSIDL_COMMON_STARTMENU);
+ CSIDL_TO_STR(CSIDL_COMMON_PROGRAMS);
+ CSIDL_TO_STR(CSIDL_COMMON_STARTUP);
+ CSIDL_TO_STR(CSIDL_COMMON_DESKTOPDIRECTORY);
+ CSIDL_TO_STR(CSIDL_APPDATA);
+ CSIDL_TO_STR(CSIDL_PRINTHOOD);
+ CSIDL_TO_STR(CSIDL_LOCAL_APPDATA);
+ CSIDL_TO_STR(CSIDL_ALTSTARTUP);
+ CSIDL_TO_STR(CSIDL_COMMON_ALTSTARTUP);
+ CSIDL_TO_STR(CSIDL_COMMON_FAVORITES);
+ CSIDL_TO_STR(CSIDL_INTERNET_CACHE);
+ CSIDL_TO_STR(CSIDL_COOKIES);
+ CSIDL_TO_STR(CSIDL_HISTORY);
+ CSIDL_TO_STR(CSIDL_COMMON_APPDATA);
+ CSIDL_TO_STR(CSIDL_WINDOWS);
+ CSIDL_TO_STR(CSIDL_SYSTEM);
+ CSIDL_TO_STR(CSIDL_PROGRAM_FILES);
+ CSIDL_TO_STR(CSIDL_MYPICTURES);
+ CSIDL_TO_STR(CSIDL_PROFILE);
+ CSIDL_TO_STR(CSIDL_SYSTEMX86);
+ CSIDL_TO_STR(CSIDL_PROGRAM_FILESX86);
+ CSIDL_TO_STR(CSIDL_PROGRAM_FILES_COMMON);
+ CSIDL_TO_STR(CSIDL_PROGRAM_FILES_COMMONX86);
+ CSIDL_TO_STR(CSIDL_COMMON_TEMPLATES);
+ CSIDL_TO_STR(CSIDL_COMMON_DOCUMENTS);
+ CSIDL_TO_STR(CSIDL_COMMON_ADMINTOOLS);
+ CSIDL_TO_STR(CSIDL_ADMINTOOLS);
+ CSIDL_TO_STR(CSIDL_CONNECTIONS);
+ CSIDL_TO_STR(CSIDL_PROFILES);
+ CSIDL_TO_STR(CSIDL_COMMON_MUSIC);
+ CSIDL_TO_STR(CSIDL_COMMON_PICTURES);
+ CSIDL_TO_STR(CSIDL_COMMON_VIDEO);
+ CSIDL_TO_STR(CSIDL_RESOURCES);
+ CSIDL_TO_STR(CSIDL_RESOURCES_LOCALIZED);
+ CSIDL_TO_STR(CSIDL_COMMON_OEM_LINKS);
+ CSIDL_TO_STR(CSIDL_CDBURN_AREA);
+ CSIDL_TO_STR(CSIDL_COMPUTERSNEARME);
+#undef CSIDL_TO_STR
+ default:
+ wnsprintfA(unknown, sizeof(unknown), "unknown (0x%04x)", folder);
+ return unknown;
+ }
+}
+
+static const char *printGUID(const GUID *guid)
+{
+ static char guidSTR[39];
+
+ if (!guid) return NULL;
+
+ wnsprintfA(guidSTR, sizeof(guidSTR),
+ "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+ guid->Data1, guid->Data2, guid->Data3,
+ guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+ guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+ return guidSTR;
+}
+
+static void testSHGetFolderLocationInvalidArgs(void)
+{
+ LPITEMIDLIST pidl;
+ HRESULT hr;
+
+ if (!pSHGetFolderLocation) return;
+
+ /* check a bogus CSIDL: */
+ pidl = NULL;
+ hr = pSHGetFolderLocation(NULL, 0xeeee, NULL, 0, &pidl);
+ ok(hr == E_INVALIDARG,
+ "SHGetFolderLocation(NULL, 0xeeee, NULL, 0, &pidl)\n"
+ "returned 0x%08lx, expected E_INVALIDARG\n", hr);
+ if (SUCCEEDED(hr))
+ IMalloc_Free(pMalloc, pidl);
+ /* check a bogus user token: */
+ pidl = NULL;
+ hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, (HANDLE)2, 0, &pidl);
+ ok(hr == E_FAIL,
+ "SHGetFolderLocation(NULL, CSIDL_FAVORITES, 2, 0, &pidl)\n"
+ "returned 0x%08lx, expected E_FAIL\n", hr);
+ if (SUCCEEDED(hr))
+ IMalloc_Free(pMalloc, pidl);
+ /* check reserved is not zero: */
+ pidl = NULL;
+ hr = pSHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 1, &pidl);
+ ok(hr == E_INVALIDARG,
+ "SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 1, &pidl)\n"
+ "returned 0x%08lx, expected E_INVALIDARG\n", hr);
+ if (SUCCEEDED(hr))
+ IMalloc_Free(pMalloc, pidl);
+ /* a NULL pidl pointer crashes, so don't test it */
+}
+
+static void testSHGetSpecialFolderLocationInvalidArgs(void)
+{
+ LPITEMIDLIST pidl = NULL;
+ HRESULT hr;
+
+ if (!pSHGetSpecialFolderLocation) return;
+
+ /* SHGetSpecialFolderLocation(NULL, 0, NULL) crashes */
+ hr = pSHGetSpecialFolderLocation(NULL, 0xeeee, &pidl);
+ ok(hr == E_INVALIDARG,
+ "SHGetSpecialFolderLocation(NULL, 0xeeee, &pidl) returned 0x%08lx, "
+ "expected E_INVALIDARG\n", hr);
+}
+
+static void testSHGetFolderPathInvalidArgs(void)
+{
+ char path[MAX_PATH];
+ HRESULT hr;
+
+ if (!pSHGetFolderPathA) return;
+
+ /* expect 2's a bogus handle, especially since we didn't open it */
+ hr = pSHGetFolderPathA(NULL, CSIDL_DESKTOP, (HANDLE)2,
+ SHGFP_TYPE_DEFAULT, path);
+ ok(hr == E_FAIL,
+ "SHGetFolderPathA(NULL, CSIDL_DESKTOP, 2, SHGFP_TYPE_DEFAULT, path)\n"
+ "returned 0x%08lx, expected E_FAIL\n", hr);
+ hr = pSHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path);
+ ok(hr == E_INVALIDARG,
+ "SHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path)\n"
+ "returned 0x%08lx, expected E_INVALIDARG\n", hr);
+}
+
+static void testSHGetSpecialFolderPathInvalidArgs(void)
+{
+ char path[MAX_PATH];
+ BOOL ret;
+
+ if (!pSHGetSpecialFolderPathA) return;
+
+ ret = pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE);
+ ok(!ret,
+ "SHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE)\n"
+ "returned TRUE, expected FALSE\n");
+ /* odd but true: calling with a NULL path still succeeds if it's a real
+ * dir
+ */
+ ret = pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_PROGRAMS, FALSE);
+ ok(ret,
+ "SHGetSpecialFolderPathA(NULL, NULL, CSIDL_PROGRAMS, FALSE)\n"
+ "returned FALSE, expected TRUE\n");
+ ret = pSHGetSpecialFolderPathA(NULL, path, 0xeeee, FALSE);
+ ok(!ret,
+ "SHGetSpecialFolderPathA(NULL, path, 0xeeee, FALSE)\n"
+ "returned TRUE, expected FALSE\n");
+}
+
+static void testApiParameters(void)
+{
+ testSHGetFolderLocationInvalidArgs();
+ testSHGetSpecialFolderLocationInvalidArgs();
+ testSHGetFolderPathInvalidArgs();
+ testSHGetSpecialFolderPathInvalidArgs();
+}
+
+/* Returns the folder's PIDL type, or 0xff if one can't be found. */
+static BYTE testSHGetFolderLocation(BOOL optional, int folder)
+{
+ LPITEMIDLIST pidl;
+ HRESULT hr;
+ BYTE ret = 0xff;
+
+ /* treat absence of function as success */
+ if (!pSHGetFolderLocation) return TRUE;
+
+ pidl = NULL;
+ hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
+ ok(SUCCEEDED(hr) || optional,
+ "SHGetFolderLocation(NULL, %s, NULL, 0, &pidl)\n"
+ "failed: 0x%08lx\n", getFolderName(folder), hr);
+ if (SUCCEEDED(hr))
+ {
+ ok(pidl != NULL,
+ "SHGetFolderLocation(NULL, %s, NULL, 0, &pidl)\n"
+ "succeeded, but returned pidl is NULL\n", getFolderName(folder));
+ if (pidl)
+ {
+ LPITEMIDLIST pidlLast = pILFindLastID(pidl);
+
+ ok(pidlLast != NULL, "%s: ILFindLastID failed\n",
+ getFolderName(folder));
+ if (pidlLast)
+ ret = pidlLast->mkid.abID[0];
+ IMalloc_Free(pMalloc, pidl);
+ }
+ }
+ return ret;
+}
+
+/* Returns the folder's PIDL type, or 0xff if one can't be found. */
+static BYTE testSHGetSpecialFolderLocation(BOOL optional, int folder)
+{
+ LPITEMIDLIST pidl;
+ HRESULT hr;
+ BYTE ret = 0xff;
+
+ /* treat absence of function as success */
+ if (!pSHGetSpecialFolderLocation) return TRUE;
+
+ pidl = NULL;
+ hr = pSHGetSpecialFolderLocation(NULL, folder, &pidl);
+ ok(SUCCEEDED(hr) || optional,
+ "SHGetSpecialFolderLocation(NULL, %s, &pidl)\n"
+ "failed: 0x%08lx\n", getFolderName(folder), hr);
+ if (SUCCEEDED(hr))
+ {
+ ok(pidl != NULL,
+ "SHGetSpecialFolderLocation(NULL, %s, &pidl)\n"
+ "succeeded, but returned pidl is NULL\n", getFolderName(folder));
+ if (pidl)
+ {
+ LPITEMIDLIST pidlLast = pILFindLastID(pidl);
+
+ ok(pidlLast != NULL,
+ "%s: ILFindLastID failed\n", getFolderName(folder));
+ if (pidlLast)
+ ret = pidlLast->mkid.abID[0];
+ IMalloc_Free(pMalloc, pidl);
+ }
+ }
+ return ret;
+}
+
+static void testSHGetFolderPath(BOOL optional, int folder)
+{
+ char path[MAX_PATH];
+ HRESULT hr;
+
+ if (!pSHGetFolderPathA) return;
+
+ hr = pSHGetFolderPathA(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path);
+ ok(SUCCEEDED(hr) || optional,
+ "SHGetFolderPathA(NULL, %s, NULL, SHGFP_TYPE_CURRENT, path)\n"
+ "failed: 0x%08lx\n", getFolderName(folder), hr);
+}
+
+static void testSHGetSpecialFolderPath(BOOL optional, int folder)
+{
+ char path[MAX_PATH];
+ BOOL ret;
+
+ if (!pSHGetSpecialFolderPathA) return;
+
+ ret = pSHGetSpecialFolderPathA(NULL, path, folder, FALSE);
+ if (ret && winetest_interactive)
+ printf("%s: %s\n", getFolderName(folder), path);
+ ok(ret || optional,
+ "SHGetSpecialFolderPathA(NULL, path, %s, FALSE) failed\n",
+ getFolderName(folder));
+}
+
+static void testShellValues(const struct shellExpectedValues testEntries[],
+ int numEntries, BOOL optional)
+{
+ int i;
+
+ for (i = 0; i < numEntries; i++)
+ {
+ BYTE type;
+
+ type = testSHGetFolderLocation(optional, testEntries[i].folder);
+ ok(type == testEntries[i].pidlType || optional,
+ "%s has type %d (0x%02x), expected %d (0x%02x)\n",
+ getFolderName(testEntries[i].folder), type, type,
+ testEntries[i].pidlType, testEntries[i].pidlType);
+ type = testSHGetSpecialFolderLocation(optional, testEntries[i].folder);
+ ok(type == testEntries[i].pidlType || optional,
+ "%s has type %d (0x%02x), expected %d (0x%02x)\n",
+ getFolderName(testEntries[i].folder), type, type,
+ testEntries[i].pidlType, testEntries[i].pidlType);
+ switch (type)
+ {
+ case PT_FOLDER:
+ case PT_DRIVE:
+ case PT_DRIVE2:
+ case PT_IESPECIAL2:
+ testSHGetFolderPath(optional, testEntries[i].folder);
+ testSHGetSpecialFolderPath(optional, testEntries[i].folder);
+ break;
+ }
+ }
+}
+
+/* Attempts to verify that the folder path corresponding to the folder CSIDL
+ * value has the same value as the environment variable with name envVar.
+ * Doesn't mind if SHGetSpecialFolderPath fails for folder or if envVar isn't
+ * set in this environment; different OS and shell version behave differently.
+ * However, if both are present, fails if envVar's value is not the same
+ * (byte-for-byte) as what SHGetSpecialFolderPath returns.
+ */
+static void matchSpecialFolderPathToEnv(int folder, const char *envVar)
+{
+ char path[MAX_PATH];
+
+ if (!pSHGetSpecialFolderPathA) return;
+
+ if (pSHGetSpecialFolderPathA(NULL, path, folder, FALSE))
+ {
+ char *envVal = getenv(envVar);
+
+ ok(!envVal || !lstrcmpiA(envVal, path),
+ "%%%s%% does not match SHGetSpecialFolderPath:\n"
+ "%%%s%% is %s\nSHGetSpecialFolderPath returns %s\n",
+ envVar, envVar, envVal, path);
+ }
+}
+
+/* Attempts to match the GUID returned by SHGetFolderLocation for folder with
+ * GUID. Assumes the type of the returned PIDL is in fact a GUID, but doesn't
+ * fail if it isn't--that check should already have been done.
+ * Fails if the returned PIDL is a GUID whose value does not match guid.
+ */
+static void matchGUID(int folder, const GUID *guid)
+{
+ LPITEMIDLIST pidl;
+ HRESULT hr;
+
+ if (!pSHGetFolderLocation) return;
+ if (!guid) return;
+
+ pidl = NULL;
+ hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
+ if (SUCCEEDED(hr))
+ {
+ LPITEMIDLIST pidlLast = pILFindLastID(pidl);
+
+ if (pidlLast && (pidlLast->mkid.abID[0] == PT_SHELLEXT ||
+ pidlLast->mkid.abID[0] == PT_GUID))
+ {
+ GUID *shellGuid = (GUID *)(pidlLast->mkid.abID + 2);
+
+ ok(IsEqualIID(shellGuid, guid),
+ "%s: got GUID %s, expected %s\n", getFolderName(folder),
+ printGUID(shellGuid), printGUID(guid));
+ }
+ IMalloc_Free(pMalloc, pidl);
+ }
+}
+
+static void testDesktop(void)
+{
+ testSHGetFolderPath(FALSE, CSIDL_DESKTOP);
+ testSHGetSpecialFolderPath(FALSE, CSIDL_DESKTOP);
+ /* Test the desktop; even though SHITEMID should always contain abID of at
+ * least one type, when cb is 0 its value is undefined. So don't check
+ * what the returned type is, just make sure it exists.
+ */
+ testSHGetFolderLocation(FALSE, CSIDL_DESKTOP);
+ testSHGetSpecialFolderLocation(FALSE, CSIDL_DESKTOP);
+}
+
+static void testPersonal(void)
+{
+ BYTE type;
+
+ /* The pidl may be a real folder, or a virtual directory, or a drive if the
+ * home directory is set to the root directory of a drive.
+ */
+ type = testSHGetFolderLocation(FALSE, CSIDL_PERSONAL);
+ ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE,
+ "CSIDL_PERSONAL returned invalid type 0x%02x, "
+ "expected PT_FOLDER or PT_GUID\n", type);
+ if (type == PT_FOLDER)
+ testSHGetFolderPath(FALSE, CSIDL_PERSONAL);
+ type = testSHGetSpecialFolderLocation(FALSE, CSIDL_PERSONAL);
+ ok(type == PT_FOLDER || type == PT_GUID || type == PT_DRIVE,
+ "CSIDL_PERSONAL returned invalid type 0x%02x, "
+ "expected PT_FOLDER or PT_GUID\n", type);
+ if (type == PT_FOLDER)
+ testSHGetSpecialFolderPath(FALSE, CSIDL_PERSONAL);
+}
+
+/* Checks the PIDL type of all the known values. */
+static void testPidlTypes(void)
+{
+ testDesktop();
+ testPersonal();
+ testShellValues(requiredShellValues, ARRAY_SIZE(requiredShellValues),
+ FALSE);
+ testShellValues(optionalShellValues, ARRAY_SIZE(optionalShellValues),
+ TRUE);
+}
+
+/* Verifies various shell virtual folders have the correct well-known GUIDs. */
+static void testGUIDs(void)
+{
+ matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin);
+ matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel);
+ matchGUID(CSIDL_DRIVES, &CLSID_MyComputer);
+ matchGUID(CSIDL_INTERNET, &CLSID_Internet);
+ matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces);
+ matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments);
+ matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments);
+}
+
+/* Verifies various shell paths match the environment variables to which they
+ * correspond.
+ */
+static void testEnvVars(void)
+{
+ matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES, "ProgramFiles");
+ matchSpecialFolderPathToEnv(CSIDL_APPDATA, "APPDATA");
+ matchSpecialFolderPathToEnv(CSIDL_PROFILE, "USERPROFILE");
+ matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "SystemRoot");
+ matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "windir");
+ matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES_COMMON,
+ "CommonProgramFiles");
+ /* this is only set on Wine, but can't hurt to verify it: */
+ matchSpecialFolderPathToEnv(CSIDL_SYSTEM, "winsysdir");
+}
+
+/* Verifies the shell path for CSIDL_WINDOWS matches the return from
+ * GetWindowsDirectory. If SHGetSpecialFolderPath fails, no harm, no foul--not
+ * every shell32 version supports CSIDL_WINDOWS.
+ */
+static void testWinDir(void)
+{
+ char windowsShellPath[MAX_PATH], windowsDir[MAX_PATH] = { 0 };
+
+ if (!pSHGetSpecialFolderPathA) return;
+
+ if (pSHGetSpecialFolderPathA(NULL, windowsShellPath, CSIDL_WINDOWS, FALSE))
+ {
+ PathRemoveBackslashA(windowsShellPath);
+ GetWindowsDirectoryA(windowsDir, sizeof(windowsDir));
+ PathRemoveBackslashA(windowsDir);
+ ok(!lstrcmpiA(windowsDir, windowsShellPath),
+ "GetWindowsDirectory does not match SHGetSpecialFolderPath:\n"
+ "GetWindowsDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
+ windowsDir, windowsShellPath);
+ }
+}
+
+/* Verifies the shell path for CSIDL_SYSTEM and CSIDL_SYSTEMX86 matches the
+ * return from GetSystemDirectory. If SHGetSpecialFolderPath fails, no harm,
+ * no foul--not every shell32 version supports CSIDL_SYSTEM.
+ */
+static void testSystemDir(void)
+{
+ char systemShellPath[MAX_PATH], systemDir[MAX_PATH] = { 0 };
+
+ if (!pSHGetSpecialFolderPathA) return;
+
+ GetSystemDirectoryA(systemDir, sizeof(systemDir));
+ PathRemoveBackslashA(systemDir);
+ if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEM, FALSE))
+ {
+ PathRemoveBackslashA(systemShellPath);
+ ok(!lstrcmpiA(systemDir, systemShellPath),
+ "GetSystemDirectory does not match SHGetSpecialFolderPath:\n"
+ "GetSystemDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
+ systemDir, systemShellPath);
+ }
+ /* check CSIDL_SYSTEMX86; note that this isn't always present, so don't
+ * worry if it fails
+ */
+ if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEMX86, FALSE))
+ {
+ PathRemoveBackslashA(systemShellPath);
+ ok(!lstrcmpiA(systemDir, systemShellPath),
+ "GetSystemDirectory does not match SHGetSpecialFolderPath:\n"
+ "GetSystemDirectory returns %s\nSHGetSpecialFolderPath returns %s\n",
+ systemDir, systemShellPath);
+ }
+}
+
+/* Globals used by subprocesses */
+static int myARGC;
+static char **myARGV;
+static char base[MAX_PATH];
+static char selfname[MAX_PATH];
+
+static int init(void)
+{
+ myARGC = winetest_get_mainargs(&myARGV);
+ if (!GetCurrentDirectoryA(sizeof(base), base)) return 0;
+ strcpy(selfname, myARGV[0]);
+ return 1;
+}
+
+/* Subprocess helper 1: test what happens when CSIDL_FAVORITES is set to a
+ * nonexistent directory.
+ */
+static void testNonExistentPath1(void)
+{
+ HRESULT hr;
+ LPITEMIDLIST pidl;
+ char path[MAX_PATH];
+
+ /* test some failure cases first: */
+ hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL,
+ SHGFP_TYPE_CURRENT, NULL);
+ ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+ "SHGetFolderPath returned 0x%08lx, expected 0x80070002\n", hr);
+ pidl = NULL;
+ hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, NULL, 0,
+ &pidl);
+ ok(hr == E_FAIL,
+ "SHGetFolderLocation returned 0x%08lx, expected E_FAIL\n", hr);
+ if (SUCCEEDED(hr) && pidl)
+ IMalloc_Free(pMalloc, pidl);
+ ok(!pSHGetSpecialFolderPathA(NULL, path, CSIDL_FAVORITES, FALSE),
+ "SHGetSpecialFolderPath succeeded, expected failure\n");
+ pidl = NULL;
+ hr = pSHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
+ ok(hr == E_FAIL, "SHGetFolderLocation returned 0x%08lx, expected E_FAIL\n",
+ hr);
+ if (SUCCEEDED(hr) && pidl)
+ IMalloc_Free(pMalloc, pidl);
+ /* now test success: */
+ hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
+ SHGFP_TYPE_CURRENT, path);
+ if (SUCCEEDED(hr))
+ {
+ BOOL ret;
+
+ if (winetest_interactive)
+ printf("CSIDL_FAVORITES was changed to %s\n", path);
+ ret = CreateDirectoryA(path, NULL);
+ ok(!ret,
+ "CreateDirectoryA succeeded but should have failed "
+ "with ERROR_ALREADY_EXISTS\n");
+ if (!ret)
+ ok(GetLastError() == ERROR_ALREADY_EXISTS,
+ "CreateDirectoryA failed with %ld, "
+ "expected ERROR_ALREADY_EXISTS\n",
+ GetLastError());
+ }
+ ok(SUCCEEDED(hr),
+ "SHGetFolderPath(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, "
+ "NULL, SHGFP_TYPE_CURRENT, path)\nfailed: 0x%08lx\n", hr);
+}
+
+/* Subprocess helper 2: make sure SHGetFolderPath still succeeds when the
+ * original value of CSIDL_FAVORITES is restored.
+ */
+static void testNonExistentPath2(void)
+{
+ HRESULT hr;
+
+ hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
+ SHGFP_TYPE_CURRENT, NULL);
+ ok(SUCCEEDED(hr), "SHGetFolderPath failed: 0x%08lx\n", hr);
+}
+
+static void doChild(const char *arg)
+{
+ if (arg[0] == '1')
+ testNonExistentPath1();
+ else if (arg[0] == '2')
+ testNonExistentPath2();
+}
+
+/* Tests the return values from the various shell functions both with and
+ * without the use of the CSIDL_FLAG_CREATE flag. This flag only appeared in
+ * version 5 of the shell, so don't test unless it's at least version 5.
+ * The test reads a value from the registry, modifies it, calls
+ * SHGetFolderPath once with the CSIDL_FLAG_CREATE flag, and immediately
+ * afterward without it. Then it restores the registry and deletes the folder
+ * that was created.
+ * One oddity with respect to restoration: shell32 caches somehow, so it needs
+ * to be reloaded in order to see the correct (restored) value.
+ * Some APIs unrelated to the ones under test may fail, but I expect they're
+ * covered by other unit tests; I just print out something about failure to
+ * help trace what's going on.
+ */
+static void testNonExistentPath(void)
+{
+ static const char userShellFolders[] =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
+ char originalPath[MAX_PATH], modifiedPath[MAX_PATH];
+ HKEY key;
+
+ if (!pSHGetFolderPathA) return;
+ if (!pSHGetFolderLocation) return;
+ if (!pSHGetSpecialFolderPathA) return;
+ if (!pSHGetSpecialFolderLocation) return;
+ if (!pSHFileOperationA) return;
+ if (shellVersion.dwMajorVersion < 5) return;
+
+ if (!RegOpenKeyExA(HKEY_CURRENT_USER, userShellFolders, 0, KEY_ALL_ACCESS,
+ &key))
+ {
+ DWORD len, type;
+
+ len = sizeof(originalPath);
+ if (!RegQueryValueExA(key, "Favorites", NULL, &type,
+ (LPBYTE)&originalPath, &len))
+ {
+ size_t len = strlen(originalPath);
+
+ memcpy(modifiedPath, originalPath, len);
+ modifiedPath[len++] = '2';
+ modifiedPath[len++] = '\0';
+ if (winetest_interactive)
+ printf("Changing CSIDL_FAVORITES to %s\n", modifiedPath);
+ if (!RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) modifiedPath, len))
+ {
+ char buffer[MAX_PATH];
+ STARTUPINFOA startup;
+ PROCESS_INFORMATION info;
+ HRESULT hr;
+ BOOL ret;
+
+ wnsprintfA(buffer, sizeof(buffer), "%s tests/shellpath.c 1",
+ selfname);
+ memset(&startup, 0, sizeof(startup));
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW;
+ startup.dwFlags = SW_SHOWNORMAL;
+ CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
+ &startup, &info);
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
+ "child process termination\n");
+
+ /* Query the path to be able to delete it below */
+ hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL,
+ SHGFP_TYPE_CURRENT, modifiedPath);
+ ok(SUCCEEDED(hr), "SHGetFolderPathA failed: 0x%08lx\n", hr);
+
+ /* restore original values: */
+ if (winetest_interactive)
+ printf("Restoring CSIDL_FAVORITES to %s\n", originalPath);
+ RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) originalPath,
+ strlen(originalPath) + 1);
+ RegFlushKey(key);
+
+ wnsprintfA(buffer, sizeof(buffer), "%s tests/shellpath.c 2",
+ selfname);
+ memset(&startup, 0, sizeof(startup));
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW;
+ startup.dwFlags = SW_SHOWNORMAL;
+ CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
+ &startup, &info);
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
+ "child process termination\n");
+
+ ret = RemoveDirectoryA(modifiedPath);
+ ok( ret, "RemoveDirectoryA failed: %ld\n", GetLastError());
+ }
+ }
+ else if (winetest_interactive)
+ printf("RegQueryValueExA(key, Favorites, ...) failed\n");
+ if (key)
+ RegCloseKey(key);
+ }
+ else if (winetest_interactive)
+ printf("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n",
+ userShellFolders);
+}
+
+START_TEST(shellpath)
+{
+ if (!init()) return;
+
+ loadShell32();
+ if (!hShell32) return;
+
+ if (myARGC >= 3)
+ doChild(myARGV[2]);
+ else
+ {
+ /* first test various combinations of parameters: */
+ testApiParameters();
+
+ /* check known values: */
+ testPidlTypes();
+ testGUIDs();
+ testEnvVars();
+ testWinDir();
+ testSystemDir();
+ testNonExistentPath();
+ }
+}
--- /dev/null
+/*
+ * Unit test of the ShellExecute function.
+ *
+ * Copyright 2005 Francois Gouget for CodeWeavers
+ *
+ * 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
+ */
+
+/* TODO:
+ * - test the default verb selection
+ * - test selection of an alternate class
+ * - try running executables in more ways
+ * - try passing arguments to executables
+ * - ShellExecute("foo.shlexec") with no path should work if foo.shlexec is
+ * in the PATH
+ * - test associations that use %l, %L or "%1" instead of %1
+ * - we may want to test ShellExecuteEx() instead of ShellExecute()
+ * and then we could also check its return value
+ * - ShellExecuteEx() also calls SetLastError() with meaningful values which
+ * we could check
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "wtypes.h"
+#include "winbase.h"
+#include "windef.h"
+#include "shellapi.h"
+#include "shlwapi.h"
+#include "wine/test.h"
+
+#include "shell32_test.h"
+
+
+static char argv0[MAX_PATH];
+static int myARGC;
+static char** myARGV;
+static char tmpdir[MAX_PATH];
+
+static const char* testfiles[]=
+{
+ "%s\\test file.shlexec",
+ "%s\\test file.noassoc",
+ "%s\\test file.noassoc.shlexec",
+ "%s\\test file.shlexec.noassoc",
+ "%s\\test_shortcut_shlexec.lnk",
+ NULL
+};
+
+
+static void strcat_param(char* str, const char* param)
+{
+ if (param!=NULL)
+ {
+ strcat(str, "\"");
+ strcat(str, param);
+ strcat(str, "\"");
+ }
+ else
+ {
+ strcat(str, "null");
+ }
+}
+
+static char shell_call[2048]="";
+static int shell_execute(LPCSTR operation, LPCSTR file, LPCSTR parameters, LPCSTR directory)
+{
+ strcpy(shell_call, "ShellExecute(");
+ strcat_param(shell_call, operation);
+ strcat(shell_call, ", ");
+ strcat_param(shell_call, file);
+ strcat(shell_call, ", ");
+ strcat_param(shell_call, parameters);
+ strcat(shell_call, ", ");
+ strcat_param(shell_call, directory);
+ strcat(shell_call, ")");
+ if (winetest_debug > 1)
+ trace("%s\n", shell_call);
+
+ SetLastError(0xcafebabe);
+ /* FIXME: We cannot use ShellExecuteEx() here because if there is no
+ * association it displays the 'Open With' dialog and I could not find
+ * a flag to prevent this.
+ */
+ return (int)ShellExecute(NULL, operation, file, parameters, directory,
+ SW_SHOWNORMAL);
+}
+
+static int shell_execute_ex(DWORD mask, LPCSTR operation, LPCSTR file,
+ LPCSTR parameters, LPCSTR directory)
+{
+ SHELLEXECUTEINFO sei;
+ BOOL success;
+ int rc;
+
+ strcpy(shell_call, "ShellExecuteEx(");
+ strcat_param(shell_call, operation);
+ strcat(shell_call, ", ");
+ strcat_param(shell_call, file);
+ strcat(shell_call, ", ");
+ strcat_param(shell_call, parameters);
+ strcat(shell_call, ", ");
+ strcat_param(shell_call, directory);
+ strcat(shell_call, ")");
+ if (winetest_debug > 1)
+ trace("%s\n", shell_call);
+
+ sei.cbSize=sizeof(sei);
+ sei.fMask=mask;
+ sei.hwnd=NULL;
+ sei.lpVerb=operation;
+ sei.lpFile=file;
+ sei.lpParameters=parameters;
+ sei.lpDirectory=directory;
+ sei.nShow=SW_SHOWNORMAL;
+ sei.hInstApp=NULL; /* Out */
+ sei.lpIDList=NULL;
+ sei.lpClass=NULL;
+ sei.hkeyClass=NULL;
+ sei.dwHotKey=0;
+ sei.hIcon=NULL;
+
+ SetLastError(0xcafebabe);
+ success=ShellExecuteEx(&sei);
+ rc=(int)sei.hInstApp;
+ ok((success && rc >= 32) || (!success && rc < 32),
+ "%s rc=%d and hInstApp=%d is not allowed\n", shell_call, success, rc);
+ return rc;
+}
+
+static void create_test_association(const char* extension)
+{
+ HKEY hkey, hkey_shell;
+ char class[MAX_PATH];
+ LONG rc;
+
+ sprintf(class, "shlexec%s", extension);
+ rc=RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey, NULL);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegSetValueEx(hkey, NULL, 0, REG_SZ, class, strlen(class)+1);
+ assert(rc==ERROR_SUCCESS);
+ CloseHandle(hkey);
+
+ rc=RegCreateKeyEx(HKEY_CLASSES_ROOT, class, 0, NULL, 0,
+ KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS, NULL, &hkey, NULL);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegCreateKeyEx(hkey, "shell", 0, NULL, 0,
+ KEY_CREATE_SUB_KEY, NULL, &hkey_shell, NULL);
+ assert(rc==ERROR_SUCCESS);
+ CloseHandle(hkey);
+ CloseHandle(hkey_shell);
+}
+
+static void delete_test_association(const char* extension)
+{
+ char class[MAX_PATH];
+
+ sprintf(class, "shlexec%s", extension);
+ SHDeleteKey(HKEY_CLASSES_ROOT, class);
+ SHDeleteKey(HKEY_CLASSES_ROOT, extension);
+}
+
+static void create_test_verb(const char* extension, const char* verb)
+{
+ HKEY hkey_shell, hkey_verb, hkey_cmd;
+ char shell[MAX_PATH];
+ char* cmd;
+ LONG rc;
+
+ sprintf(shell, "shlexec%s\\shell", extension);
+ rc=RegOpenKeyEx(HKEY_CLASSES_ROOT, shell, 0,
+ KEY_CREATE_SUB_KEY, &hkey_shell);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegCreateKeyEx(hkey_shell, verb, 0, NULL, 0, KEY_CREATE_SUB_KEY,
+ NULL, &hkey_verb, NULL);
+ assert(rc==ERROR_SUCCESS);
+ rc=RegCreateKeyEx(hkey_verb, "command", 0, NULL, 0, KEY_SET_VALUE,
+ NULL, &hkey_cmd, NULL);
+ assert(rc==ERROR_SUCCESS);
+
+ cmd=malloc(strlen(argv0)+13+1);
+ sprintf(cmd,"%s shlexec \"%%1\"", argv0);
+ rc=RegSetValueEx(hkey_cmd, NULL, 0, REG_SZ, cmd, strlen(cmd)+1);
+ assert(rc==ERROR_SUCCESS);
+
+ free(cmd);
+ CloseHandle(hkey_shell);
+ CloseHandle(hkey_verb);
+ CloseHandle(hkey_cmd);
+}
+
+
+typedef struct
+{
+ char* basename;
+ int rc;
+ int todo;
+} filename_tests_t;
+
+static filename_tests_t filename_tests[]=
+{
+ /* Test bad / nonexistent filenames */
+ {"%s\\nonexistent.shlexec", ERROR_FILE_NOT_FOUND, 1},
+ {"%s\\nonexistent.noassoc", ERROR_FILE_NOT_FOUND, 1},
+
+ /* Standard tests */
+ {"%s\\test file.shlexec", 0, 0},
+ {"%s\\test file.shlexec.", 0, 0},
+ {"%s/test file.shlexec", 0, 0},
+
+ /* Test filenames with no association */
+ {"%s\\test file.noassoc", SE_ERR_NOASSOC, 0},
+
+ /* Test double extensions */
+ {"%s\\test file.noassoc.shlexec", 0, 0},
+ {"%s\\test file.shlexec.noassoc", SE_ERR_NOASSOC, 0},
+
+ /* Test shortcuts */
+ {"%s\\test_shortcut_shlexec.lnk", 0, 0},
+
+ {NULL, 0, 0}
+};
+
+static void test_filename()
+{
+ char filename[MAX_PATH];
+ const filename_tests_t* test;
+ HMODULE hdll;
+ DLLVERSIONINFO dllver;
+ HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO*);
+ char* c;
+ int rc;
+
+ test=filename_tests;
+ while (test->basename)
+ {
+ sprintf(filename, test->basename, tmpdir);
+ if (strchr(filename, '/'))
+ {
+ c=filename;
+ while (*c)
+ {
+ if (*c=='\\')
+ *c='/';
+ c++;
+ }
+ }
+ rc=shell_execute(NULL, filename, NULL, NULL);
+ if (test->rc==0)
+ {
+ if (test->todo)
+ {
+ todo_wine
+ {
+ ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call,
+ rc, GetLastError());
+ }
+ }
+ else
+ {
+ ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call,
+ rc, GetLastError());
+ }
+ }
+ else
+ {
+ if (test->todo)
+ {
+ todo_wine
+ {
+ ok(rc==test->rc, "%s returned %d\n", shell_call, rc);
+ }
+ }
+ else
+ {
+ ok(rc==test->rc, "%s returned %d\n", shell_call, rc);
+ }
+ }
+ test++;
+ }
+
+ hdll=GetModuleHandleA("shell32.dll");
+ pDllGetVersion=(void*)GetProcAddress(hdll, "DllGetVersion");
+ if (pDllGetVersion)
+ {
+ dllver.cbSize=sizeof(dllver);
+ pDllGetVersion(&dllver);
+ trace("major=%ld minor=%ld build=%ld platform=%ld\n",
+ dllver.dwMajorVersion, dllver.dwMinorVersion,
+ dllver.dwBuildNumber, dllver.dwPlatformID);
+
+ /* The more recent versions of shell32.dll accept quoted filenames
+ * while older ones (e.g. 4.00) don't. Still we want to test this
+ * because IE 6 depends on the new behavior.
+ * One day we may need to check the exact version of the dll but for
+ * now making sure DllGetVersion() is present is sufficient.
+ */
+ sprintf(filename, "\"%s\\test file.shlexec\"", tmpdir);
+ rc=shell_execute(NULL, filename, NULL, NULL);
+ ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call, rc,
+ GetLastError());
+
+ if (dllver.dwMajorVersion>=6)
+ {
+ /* Recent versions of shell32.dll accept '/'s in shortcut paths.
+ * Older versions don't or are quite buggy in this regard.
+ */
+ sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
+ c=filename;
+ while (*c)
+ {
+ if (*c=='\\')
+ *c='/';
+ c++;
+ }
+ rc=shell_execute(NULL, filename, NULL, NULL);
+ todo_wine {
+ ok(rc>=32, "%s failed: rc=%d err=%ld\n", shell_call, rc,
+ GetLastError());
+ }
+ }
+ }
+}
+
+
+static void test_exes()
+{
+ char filename[MAX_PATH];
+ int rc;
+
+ /* We need NOZONECHECKS on Win2003 to block a dialog */
+ rc=shell_execute_ex(SEE_MASK_NOZONECHECKS, NULL, argv0, "shlexec -nop",
+ NULL);
+ ok(rc>=32, "%s returned %d\n", shell_call, rc);
+
+ sprintf(filename, "%s\\test file.noassoc", tmpdir);
+ if (CopyFile(argv0, filename, FALSE))
+ {
+ rc=shell_execute(NULL, filename, "shlexec -nop", NULL);
+ todo_wine {
+ ok(rc==SE_ERR_NOASSOC, "%s succeeded: rc=%d\n", shell_call, rc);
+ }
+ }
+}
+
+
+static void init_test()
+{
+ char filename[MAX_PATH];
+ WCHAR lnkfile[MAX_PATH];
+ const char* const * testfile;
+ lnk_desc_t desc;
+ DWORD rc;
+ HRESULT r;
+
+ r = CoInitialize(NULL);
+ ok(SUCCEEDED(r), "CoInitialize failed (0x%08lx)\n", r);
+ if (!SUCCEEDED(r))
+ exit(1);
+
+ rc=GetModuleFileName(NULL, argv0, sizeof(argv0));
+ assert(rc!=0 && rc<sizeof(argv0));
+ if (GetFileAttributes(argv0)==INVALID_FILE_ATTRIBUTES)
+ {
+ strcat(argv0, ".so");
+ ok(GetFileAttributes(argv0)!=INVALID_FILE_ATTRIBUTES,
+ "unable to find argv0!\n");
+ }
+
+ GetTempPathA(sizeof(tmpdir)/sizeof(*tmpdir), tmpdir);
+
+ /* Set up the test files */
+ testfile=testfiles;
+ while (*testfile)
+ {
+ HANDLE hfile;
+
+ sprintf(filename, *testfile, tmpdir);
+ hfile=CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hfile==INVALID_HANDLE_VALUE)
+ {
+ trace("unable to create '%s': err=%ld\n", filename, GetLastError());
+ assert(0);
+ }
+ CloseHandle(hfile);
+ testfile++;
+ }
+
+ /* Setup the test shortcuts */
+ sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
+ MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, sizeof(lnkfile)/sizeof(*lnkfile));
+ desc.description=NULL;
+ desc.workdir=NULL;
+ sprintf(filename, "%s\\test file.shlexec", tmpdir);
+ desc.path=filename;
+ desc.pidl=NULL;
+ desc.arguments="";
+ desc.showcmd=0;
+ desc.icon=NULL;
+ desc.icon_id=0;
+ desc.hotkey=0;
+ create_lnk(lnkfile, &desc, 0);
+
+ /* Create a basic association suitable for most tests */
+ create_test_association(".shlexec");
+ create_test_verb(".shlexec", "Open");
+}
+
+static void cleanup_test()
+{
+ char filename[MAX_PATH];
+ const char* const * testfile;
+
+ /* Delete the test files */
+ testfile=testfiles;
+ while (*testfile)
+ {
+ sprintf(filename, *testfile, tmpdir);
+ DeleteFile(filename);
+ testfile++;
+ }
+
+ /* Delete the test association */
+ delete_test_association(".shlexec");
+
+ CoUninitialize();
+}
+
+START_TEST(shlexec)
+{
+
+ myARGC = winetest_get_mainargs(&myARGV);
+ if (myARGC>=3)
+ {
+ /* FIXME: We should dump the parameters we got
+ * and have the parent verify them
+ */
+ exit(0);
+ }
+
+ init_test();
+
+ test_filename();
+ test_exes();
+
+ cleanup_test();
+}
--- /dev/null
+/*
+ * Unit test of the SHFileOperation function.
+ *
+ * Copyright 2002 Andriy Palamarchuk
+ *
+ * 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
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#define WINE_NOWINSOCK
+#include "windef.h"
+#include "winbase.h"
+#include "wtypes.h"
+#include "shellapi.h"
+#include "shlobj.h"
+
+#include "wine/test.h"
+
+CHAR CURR_DIR[MAX_PATH];
+
+static HMODULE hshell32;
+static int (WINAPI *pSHCreateDirectoryExA)(HWND, LPCSTR, LPSECURITY_ATTRIBUTES);
+
+static void InitFunctionPointers(void)
+{
+ hshell32 = GetModuleHandleA("shell32.dll");
+
+ if(hshell32)
+ pSHCreateDirectoryExA = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExA");
+}
+
+/* creates a file with the specified name for tests */
+static void createTestFile(const CHAR *name)
+{
+ HANDLE file;
+ DWORD written;
+
+ file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
+ WriteFile(file, name, strlen(name), &written, NULL);
+ WriteFile(file, "\n", strlen("\n"), &written, NULL);
+ CloseHandle(file);
+}
+
+static BOOL file_exists(const CHAR *name)
+{
+ return GetFileAttributesA(name) != INVALID_FILE_ATTRIBUTES;
+}
+
+/* initializes the tests */
+static void init_shfo_tests(void)
+{
+ int len;
+
+ GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
+ len = lstrlenA(CURR_DIR);
+
+ if(len && (CURR_DIR[len-1] == '\\'))
+ CURR_DIR[len-1] = 0;
+
+ createTestFile(".\\test1.txt");
+ createTestFile(".\\test2.txt");
+ createTestFile(".\\test3.txt");
+ CreateDirectoryA(".\\test4.txt", NULL);
+ CreateDirectoryA(".\\testdir2", NULL);
+}
+
+/* cleans after tests */
+static void clean_after_shfo_tests(void)
+{
+ DeleteFileA(".\\test1.txt");
+ DeleteFileA(".\\test2.txt");
+ DeleteFileA(".\\test3.txt");
+ DeleteFileA(".\\test4.txt\\test1.txt");
+ DeleteFileA(".\\test4.txt\\test2.txt");
+ DeleteFileA(".\\test4.txt\\test3.txt");
+ RemoveDirectoryA(".\\test4.txt");
+ DeleteFileA(".\\testdir2\\test1.txt");
+ DeleteFileA(".\\testdir2\\test2.txt");
+ DeleteFileA(".\\testdir2\\test3.txt");
+ DeleteFileA(".\\testdir2\\test4.txt\\test1.txt");
+ RemoveDirectoryA(".\\testdir2\\test4.txt");
+ RemoveDirectoryA(".\\testdir2");
+}
+
+/*
+ puts into the specified buffer file names with current directory.
+ files - string with file names, separated by null characters. Ends on a double
+ null characters
+*/
+static void set_curr_dir_path(CHAR *buf, const CHAR* files)
+{
+ buf[0] = 0;
+ while (files[0])
+ {
+ strcpy(buf, CURR_DIR);
+ buf += strlen(buf);
+ buf[0] = '\\';
+ buf++;
+ strcpy(buf, files);
+ buf += strlen(buf) + 1;
+ files += strlen(files) + 1;
+ }
+ buf[0] = 0;
+}
+
+
+/* tests the FO_DELETE action */
+static void test_delete(void)
+{
+ SHFILEOPSTRUCTA shfo;
+ DWORD ret;
+ CHAR buf[MAX_PATH];
+
+ sprintf(buf, "%s\\%s", CURR_DIR, "test?.txt");
+ buf[strlen(buf) + 1] = '\0';
+
+ shfo.hwnd = NULL;
+ shfo.wFunc = FO_DELETE;
+ shfo.pFrom = buf;
+ shfo.pTo = "\0";
+ shfo.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT;
+ shfo.hNameMappings = NULL;
+ shfo.lpszProgressTitle = NULL;
+
+ ok(!SHFileOperationA(&shfo), "Deletion was successful\n");
+ ok(file_exists(".\\test4.txt"), "Directory should not be removed\n");
+ ok(!file_exists(".\\test1.txt"), "File should be removed\n");
+
+ ret = SHFileOperationA(&shfo);
+ ok(!ret, "Directory exists, but is not removed, ret=%ld\n", ret);
+ ok(file_exists(".\\test4.txt"), "Directory should not be removed\n");
+
+ shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
+
+ ok(!SHFileOperationA(&shfo), "Directory removed\n");
+ ok(!file_exists(".\\test4.txt"), "Directory should be removed\n");
+
+ ret = SHFileOperationA(&shfo);
+ ok(!ret, "The requested file does not exist, ret=%ld\n", ret);
+
+ init_shfo_tests();
+ sprintf(buf, "%s\\%s", CURR_DIR, "test4.txt");
+ buf[strlen(buf) + 1] = '\0';
+ ok(MoveFileA(".\\test1.txt", ".\\test4.txt\\test1.txt"), "Fill the subdirectory\n");
+ ok(!SHFileOperationA(&shfo), "Directory removed\n");
+ ok(!file_exists(".\\test4.txt"), "Directory is removed\n");
+
+ init_shfo_tests();
+ shfo.pFrom = ".\\test1.txt\0.\\test4.txt\0";
+ ok(!SHFileOperationA(&shfo), "Directory and a file removed\n");
+ ok(!file_exists(".\\test1.txt"), "The file should be removed\n");
+ ok(!file_exists(".\\test4.txt"), "Directory should be removed\n");
+ ok(file_exists(".\\test2.txt"), "This file should not be removed\n");
+}
+
+/* tests the FO_RENAME action */
+static void test_rename(void)
+{
+ SHFILEOPSTRUCTA shfo, shfo2;
+ CHAR from[MAX_PATH];
+ CHAR to[MAX_PATH];
+ DWORD retval;
+
+ shfo.hwnd = NULL;
+ shfo.wFunc = FO_RENAME;
+ shfo.pFrom = from;
+ shfo.pTo = to;
+ shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
+ shfo.hNameMappings = NULL;
+ shfo.lpszProgressTitle = NULL;
+
+ set_curr_dir_path(from, "test1.txt\0");
+ set_curr_dir_path(to, "test4.txt\0");
+ ok(SHFileOperationA(&shfo), "File is not renamed moving to other directory "
+ "when specifying directory name only\n");
+ ok(file_exists(".\\test1.txt"), "The file is removed\n");
+
+ set_curr_dir_path(from, "test3.txt\0");
+ set_curr_dir_path(to, "test4.txt\\test1.txt\0");
+ ok(!SHFileOperationA(&shfo), "File is renamed moving to other directory\n");
+ ok(file_exists(".\\test4.txt\\test1.txt"), "The file is not renamed\n");
+
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
+ retval = SHFileOperationA(&shfo); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */
+ ok(!retval || retval == ERROR_GEN_FAILURE || retval == ERROR_INVALID_TARGET_HANDLE,
+ "Can't rename many files, retval = %ld\n", retval);
+ ok(file_exists(".\\test1.txt"), "The file is renamed - many files are specified\n");
+
+ memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
+ shfo2.fFlags |= FOF_MULTIDESTFILES;
+
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
+ retval = SHFileOperationA(&shfo2); /* W98 returns 0, W2K and newer returns ERROR_GEN_FAILURE, both do nothing */
+ ok(!retval || retval == ERROR_GEN_FAILURE || retval == ERROR_INVALID_TARGET_HANDLE,
+ "Can't rename many files, retval = %ld\n", retval);
+ ok(file_exists(".\\test1.txt"), "The file is not renamed - many files are specified\n");
+
+ set_curr_dir_path(from, "test1.txt\0");
+ set_curr_dir_path(to, "test6.txt\0");
+ retval = SHFileOperationA(&shfo);
+ ok(!retval, "Rename file failed, retval = %ld\n", retval);
+ ok(!file_exists(".\\test1.txt"), "The file is not renamed\n");
+ ok(file_exists(".\\test6.txt"), "The file is not renamed\n");
+
+ set_curr_dir_path(from, "test6.txt\0");
+ set_curr_dir_path(to, "test1.txt\0");
+ retval = SHFileOperationA(&shfo);
+ ok(!retval, "Rename file back failed, retval = %ld\n", retval);
+
+ set_curr_dir_path(from, "test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0");
+ retval = SHFileOperationA(&shfo);
+ ok(!retval, "Rename dir failed, retval = %ld\n", retval);
+ ok(!file_exists(".\\test4.txt"), "The dir is not renamed\n");
+ ok(file_exists(".\\test6.txt"), "The dir is not renamed\n");
+
+ set_curr_dir_path(from, "test6.txt\0");
+ set_curr_dir_path(to, "test4.txt\0");
+ retval = SHFileOperationA(&shfo);
+ ok(!retval, "Rename dir back failed, retval = %ld\n", retval);
+}
+
+/* tests the FO_COPY action */
+static void test_copy(void)
+{
+ SHFILEOPSTRUCTA shfo, shfo2;
+ CHAR from[MAX_PATH];
+ CHAR to[MAX_PATH];
+ FILEOP_FLAGS tmp_flags;
+ DWORD retval;
+
+ shfo.hwnd = NULL;
+ shfo.wFunc = FO_COPY;
+ shfo.pFrom = from;
+ shfo.pTo = to;
+ shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
+ shfo.hNameMappings = NULL;
+ shfo.lpszProgressTitle = NULL;
+
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
+ ok(SHFileOperationA(&shfo), "Can't copy many files\n");
+ ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
+ "specified as a target\n");
+
+ memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
+ shfo2.fFlags |= FOF_MULTIDESTFILES;
+
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
+ ok(!SHFileOperationA(&shfo2), "Can't copy many files\n");
+ ok(file_exists(".\\test6.txt"), "The file is copied - many files are "
+ "specified as a target\n");
+ DeleteFileA(".\\test6.txt");
+ DeleteFileA(".\\test7.txt");
+ RemoveDirectoryA(".\\test8.txt");
+
+ /* number of sources do not correspond to number of targets */
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0");
+ ok(SHFileOperationA(&shfo2), "Can't copy many files\n");
+ ok(!file_exists(".\\test6.txt"), "The file is not copied - many files are "
+ "specified as a target\n");
+
+ set_curr_dir_path(from, "test1.txt\0");
+ set_curr_dir_path(to, "test4.txt\0");
+ ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are copied recursively\n");
+ ok(file_exists(".\\test4.txt\\test1.txt"), "The file is copied\n");
+
+ set_curr_dir_path(from, "test?.txt\0");
+ set_curr_dir_path(to, "testdir2\0");
+ ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
+ ok(!SHFileOperationA(&shfo), "Files and directories are copied to directory\n");
+ ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
+ ok(file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
+ ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is copied\n");
+ clean_after_shfo_tests();
+
+ init_shfo_tests();
+ shfo.fFlags |= FOF_FILESONLY;
+ ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not copied yet\n");
+ ok(!SHFileOperationA(&shfo), "Files are copied to other directory\n");
+ ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
+ ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is copied\n");
+ clean_after_shfo_tests();
+
+ init_shfo_tests();
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0");
+ ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
+ ok(!SHFileOperationA(&shfo), "Files are copied to other directory \n");
+ ok(file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
+ ok(file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
+ clean_after_shfo_tests();
+
+ /* Copying multiple files with one not existing as source, fails the
+ entire operation in Win98/ME/2K/XP, but not in 95/NT */
+ init_shfo_tests();
+ tmp_flags = shfo.fFlags;
+ set_curr_dir_path(from, "test1.txt\0test10.txt\0test2.txt\0");
+ ok(!file_exists(".\\testdir2\\test1.txt"), "The file is not copied yet\n");
+ ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not copied yet\n");
+ retval = SHFileOperationA(&shfo);
+ if (!retval)
+ /* Win 95/NT returns success but copies only the files up to the nonexistent source */
+ ok(file_exists(".\\testdir2\\test1.txt"), "The file is not copied\n");
+ else
+ {
+ /* Win 98/ME/2K/XP fail the entire operation with return code 1026 if one source file does not exist */
+ ok(retval == 1026, "Files are copied to other directory\n");
+ ok(!file_exists(".\\testdir2\\test1.txt"), "The file is copied\n");
+ }
+ ok(!file_exists(".\\testdir2\\test2.txt"), "The file is copied\n");
+ shfo.fFlags = tmp_flags;
+}
+
+/* tests the FO_MOVE action */
+static void test_move(void)
+{
+ SHFILEOPSTRUCTA shfo, shfo2;
+ CHAR from[MAX_PATH];
+ CHAR to[MAX_PATH];
+
+ shfo.hwnd = NULL;
+ shfo.wFunc = FO_MOVE;
+ shfo.pFrom = from;
+ shfo.pTo = to;
+ shfo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
+ shfo.hNameMappings = NULL;
+ shfo.lpszProgressTitle = NULL;
+
+ set_curr_dir_path(from, "test1.txt\0");
+ set_curr_dir_path(to, "test4.txt\0");
+ ok(!SHFileOperationA(&shfo), "Prepare test to check how directories are moved recursively\n");
+ ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
+
+ set_curr_dir_path(from, "test?.txt\0");
+ set_curr_dir_path(to, "testdir2\0");
+ ok(!file_exists(".\\testdir2\\test2.txt"), "The file is not moved yet\n");
+ ok(!file_exists(".\\testdir2\\test4.txt"), "The directory is not moved yet\n");
+ ok(!SHFileOperationA(&shfo), "Files and directories are moved to directory\n");
+ ok(file_exists(".\\testdir2\\test2.txt"), "The file is moved\n");
+ ok(file_exists(".\\testdir2\\test4.txt"), "The directory is moved\n");
+ ok(file_exists(".\\testdir2\\test4.txt\\test1.txt"), "The file in subdirectory is moved\n");
+
+ clean_after_shfo_tests();
+ init_shfo_tests();
+
+ memcpy(&shfo2, &shfo, sizeof(SHFILEOPSTRUCTA));
+ shfo2.fFlags |= FOF_MULTIDESTFILES;
+
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
+ ok(!SHFileOperationA(&shfo2), "Move many files\n");
+ ok(file_exists(".\\test6.txt"), "The file is moved - many files are "
+ "specified as a target\n");
+ DeleteFileA(".\\test6.txt");
+ DeleteFileA(".\\test7.txt");
+ RemoveDirectoryA(".\\test8.txt");
+
+ init_shfo_tests();
+
+ /* number of sources do not correspond to number of targets */
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0");
+ ok(SHFileOperationA(&shfo2), "Can't move many files\n");
+ ok(!file_exists(".\\test6.txt"), "The file is not moved - many files are "
+ "specified as a target\n");
+
+ init_shfo_tests();
+
+ set_curr_dir_path(from, "test3.txt\0");
+ set_curr_dir_path(to, "test4.txt\\test1.txt\0");
+ ok(!SHFileOperationA(&shfo), "File is moved moving to other directory\n");
+ ok(file_exists(".\\test4.txt\\test1.txt"), "The file is moved\n");
+
+ set_curr_dir_path(from, "test1.txt\0test2.txt\0test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0test7.txt\0test8.txt\0");
+ ok(SHFileOperationA(&shfo), "Cannot move many files\n");
+ ok(file_exists(".\\test1.txt"), "The file is not moved. Many files are specified\n");
+ ok(file_exists(".\\test4.txt"), "The directory is not moved. Many files are specified\n");
+
+ set_curr_dir_path(from, "test1.txt\0");
+ set_curr_dir_path(to, "test6.txt\0");
+ ok(!SHFileOperationA(&shfo), "Move file\n");
+ ok(!file_exists(".\\test1.txt"), "The file is moved\n");
+ ok(file_exists(".\\test6.txt"), "The file is moved\n");
+ set_curr_dir_path(from, "test6.txt\0");
+ set_curr_dir_path(to, "test1.txt\0");
+ ok(!SHFileOperationA(&shfo), "Move file back\n");
+
+ set_curr_dir_path(from, "test4.txt\0");
+ set_curr_dir_path(to, "test6.txt\0");
+ ok(!SHFileOperationA(&shfo), "Move dir\n");
+ ok(!file_exists(".\\test4.txt"), "The dir is moved\n");
+ ok(file_exists(".\\test6.txt"), "The dir is moved\n");
+ set_curr_dir_path(from, "test6.txt\0");
+ set_curr_dir_path(to, "test4.txt\0");
+ ok(!SHFileOperationA(&shfo), "Move dir back\n");
+}
+
+static void test_sh_create_dir(void)
+{
+ CHAR path[MAX_PATH];
+ int ret;
+
+ if(!pSHCreateDirectoryExA)
+ {
+ trace("skipping SHCreateDirectoryExA tests\n");
+ return;
+ }
+
+ set_curr_dir_path(path, "testdir2\\test4.txt\0");
+ ret = pSHCreateDirectoryExA(NULL, path, NULL);
+ ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory recursively, ret = %d\n", ret);
+ ok(file_exists(".\\testdir2"), "The first directory is not created\n");
+ ok(file_exists(".\\testdir2\\test4.txt"), "The second directory is not created\n");
+
+ ret = pSHCreateDirectoryExA(NULL, path, NULL);
+ ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
+}
+
+START_TEST(shlfileop)
+{
+ InitFunctionPointers();
+
+ clean_after_shfo_tests();
+
+ init_shfo_tests();
+ test_delete();
+ clean_after_shfo_tests();
+
+ init_shfo_tests();
+ test_rename();
+ clean_after_shfo_tests();
+
+ init_shfo_tests();
+ test_copy();
+ clean_after_shfo_tests();
+
+ init_shfo_tests();
+ test_move();
+ clean_after_shfo_tests();
+
+ test_sh_create_dir();
+ clean_after_shfo_tests();
+}
--- /dev/null
+/*
+ * Unit test of the IShellFolder functions.
+ *
+ * Copyright 2004 Vitaliy Margolen
+ *
+ * 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
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "wtypes.h"
+#include "shellapi.h"
+
+
+#include "shlguid.h"
+#include "shlobj.h"
+//#include "shobjidl.h"
+#include "shlwapi.h"
+
+
+#include "wine/unicode.h"
+#include "wine/test.h"
+
+
+static IMalloc *ppM;
+
+static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
+static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
+
+static void init_function_pointers(void)
+{
+ HMODULE hmod = GetModuleHandleA("shell32.dll");
+ HRESULT hr;
+
+ if(hmod)
+ {
+ pSHBindToParent = (void*)GetProcAddress(hmod, "SHBindToParent");
+ pSHGetSpecialFolderPathW = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathW");
+ }
+
+ hr = SHGetMalloc(&ppM);
+ ok(hr == S_OK, "SHGetMalloc failed %08lx\n", hr);
+}
+
+static void test_ParseDisplayName(void)
+{
+ HRESULT hr;
+ IShellFolder *IDesktopFolder;
+ static const char *cNonExistDir1A = "c:\\nonexist_subdir";
+ static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
+ DWORD res;
+ WCHAR cTestDirW [MAX_PATH] = {0};
+ ITEMIDLIST *newPIDL;
+
+ hr = SHGetDesktopFolder(&IDesktopFolder);
+ if(hr != S_OK) return;
+
+ res = GetFileAttributesA(cNonExistDir1A);
+ if(res != INVALID_FILE_ATTRIBUTES) return;
+
+ MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
+ hr = IShellFolder_ParseDisplayName(IDesktopFolder,
+ NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
+ ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
+ "ParseDisplayName returned %08lx, expected 80070002 or E_FAIL\n", hr);
+
+ res = GetFileAttributesA(cNonExistDir2A);
+ if(res != INVALID_FILE_ATTRIBUTES) return;
+
+ MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
+ hr = IShellFolder_ParseDisplayName(IDesktopFolder,
+ NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
+ ok((hr == E_FAIL), "ParseDisplayName returned %08lx, expected E_FAIL\n", hr);
+}
+
+/* creates a file with the specified name for tests */
+static void CreateTestFile(const CHAR *name)
+{
+ HANDLE file;
+ DWORD written;
+
+ file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ if (file != INVALID_HANDLE_VALUE)
+ {
+ WriteFile(file, name, strlen(name), &written, NULL);
+ WriteFile(file, "\n", strlen("\n"), &written, NULL);
+ CloseHandle(file);
+ }
+}
+
+
+/* initializes the tests */
+static void CreateFilesFolders(void)
+{
+ CreateDirectoryA(".\\testdir", NULL);
+ CreateDirectoryA(".\\testdir\\test.txt", NULL);
+ CreateTestFile (".\\testdir\\test1.txt ");
+ CreateTestFile (".\\testdir\\test2.txt ");
+ CreateTestFile (".\\testdir\\test3.txt ");
+ CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
+ CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
+}
+
+/* cleans after tests */
+static void Cleanup(void)
+{
+ DeleteFileA(".\\testdir\\test1.txt");
+ DeleteFileA(".\\testdir\\test2.txt");
+ DeleteFileA(".\\testdir\\test3.txt");
+ RemoveDirectoryA(".\\testdir\\test.txt");
+ RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
+ RemoveDirectoryA(".\\testdir\\testdir2");
+ RemoveDirectoryA(".\\testdir");
+}
+
+
+/* perform test */
+static void test_EnumObjects(IShellFolder *iFolder)
+{
+ IEnumIDList *iEnumList;
+ LPITEMIDLIST newPIDL, idlArr[10];
+ ULONG NumPIDLs;
+ int i=0, j;
+ HRESULT hr;
+
+ static const WORD iResults [5][5] =
+ {
+ { 0,-1,-1,-1,-1},
+ { 1, 0,-1,-1,-1},
+ { 1, 1, 0,-1,-1},
+ { 1, 1, 1, 0,-1},
+ { 1, 1, 1, 1, 0}
+ };
+
+ /* Just test SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR for now */
+ static const ULONG attrs[5] =
+ {
+ SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
+ SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
+ SFGAO_FILESYSTEM,
+ SFGAO_FILESYSTEM,
+ SFGAO_FILESYSTEM,
+ };
+
+ hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
+ ok(hr == S_OK, "EnumObjects failed %08lx\n", hr);
+
+ /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
+ * the filesystem shellfolders return S_OK even if less than 'celt' items are
+ * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
+ * only ever returns a single entry per call. */
+ while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
+ i += NumPIDLs;
+ ok (i == 5, "i: %d\n", i);
+
+ hr = IEnumIDList_Release(iEnumList);
+ ok(hr == S_OK, "IEnumIDList_Release failed %08lx\n", hr);
+
+ /* Sort them first in case of wrong order from system */
+ for (i=0;i<5;i++) for (j=0;j<5;j++)
+ if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
+ {
+ newPIDL = idlArr[i];
+ idlArr[i] = idlArr[j];
+ idlArr[j] = newPIDL;
+ }
+
+ for (i=0;i<5;i++) for (j=0;j<5;j++)
+ {
+ hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
+ ok(hr == iResults[i][j], "Got %lx expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
+ }
+
+
+ for (i = 0; i < 5; i++)
+ {
+ SFGAOF flags;
+ flags = SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR;
+ hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
+ flags &= SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR;
+ ok(hr == S_OK, "GetAttributesOf returns %08lx\n", hr);
+ ok(flags == attrs[i], "GetAttributesOf gets attrs %08lx, expects %08lx\n", flags, attrs[i]);
+ }
+
+ for (i=0;i<5;i++)
+ IMalloc_Free(ppM, idlArr[i]);
+}
+
+static void test_BindToObject(void)
+{
+ HRESULT hr;
+ UINT cChars;
+ IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
+ SHITEMID emptyitem = { 0, { 0 } };
+ LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
+ WCHAR wszSystemDir[MAX_PATH];
+ WCHAR wszMyComputer[] = {
+ ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
+ 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
+
+ /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
+ * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
+ */
+ hr = SHGetDesktopFolder(&psfDesktop);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
+ ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08lx\n", hr);
+
+ hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
+ ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08lx\n", hr);
+
+ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
+ ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08lx\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
+ ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08lx\n", hr);
+ IShellFolder_Release(psfDesktop);
+ IMalloc_Free(ppM, pidlMyComputer);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
+ ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08lx\n", hr);
+
+ hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
+ ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08lx\n", hr);
+
+ cChars = GetSystemDirectoryW(wszSystemDir, MAX_PATH);
+ ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryW failed! LastError: %08lx\n", GetLastError());
+ if (cChars == 0 || cChars >= MAX_PATH) {
+ IShellFolder_Release(psfMyComputer);
+ return;
+ }
+
+ hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
+ ok (SUCCEEDED(hr), "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08lx\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfMyComputer);
+ return;
+ }
+
+ hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
+ ok (SUCCEEDED(hr), "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08lx\n", hr);
+ IShellFolder_Release(psfMyComputer);
+ IMalloc_Free(ppM, pidlSystemDir);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
+ ok (hr == E_INVALIDARG,
+ "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08lx\n", hr);
+
+ hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
+ ok (hr == E_INVALIDARG,
+ "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08lx\n", hr);
+
+ IShellFolder_Release(psfSystemDir);
+}
+
+static void test_GetDisplayName(void)
+{
+ BOOL result;
+ HRESULT hr;
+ HANDLE hTestFile;
+ WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH], wszTestDir[MAX_PATH];
+ STRRET strret;
+ LPSHELLFOLDER psfDesktop, psfPersonal;
+ IUnknown *psfFile;
+ LPITEMIDLIST pidlTestFile;
+ LPCITEMIDLIST pidlLast;
+ static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
+ static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
+
+ /* I'm trying to figure if there is a functional difference between calling
+ * SHGetPathFromIDList and calling GetDisplayNameOf(SHGDN_FORPARSING) after
+ * binding to the shellfolder. One thing I thought of was that perhaps
+ * SHGetPathFromIDList would be able to get the path to a file, which does
+ * not exist anymore, while the other method would'nt. It turns out there's
+ * no functional difference in this respect.
+ */
+
+ if(!pSHGetSpecialFolderPathW) return;
+
+ /* First creating a directory in MyDocuments and a file in this directory. */
+ result = pSHGetSpecialFolderPathW(NULL, wszTestDir, CSIDL_PERSONAL, FALSE);
+ ok(result, "SHGetSpecialFolderPathW failed! Last error: %08lx\n", GetLastError());
+ if (!result) return;
+
+ PathAddBackslashW(wszTestDir);
+ lstrcatW(wszTestDir, wszDirName);
+ result = CreateDirectoryW(wszTestDir, NULL);
+ ok(result, "CreateDirectoryW failed! Last error: %08lx\n", GetLastError());
+ if (!result) return;
+
+ lstrcpyW(wszTestFile, wszTestDir);
+ PathAddBackslashW(wszTestFile);
+ lstrcatW(wszTestFile, wszFileName);
+
+ hTestFile = CreateFileW(wszTestFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
+ ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %08lx\n", GetLastError());
+ if (hTestFile == INVALID_HANDLE_VALUE) return;
+ CloseHandle(hTestFile);
+
+ /* Getting an itemidlist for the file. */
+ hr = SHGetDesktopFolder(&psfDesktop);
+ ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
+ ok(SUCCEEDED(hr), "Desktop->ParseDisplayName failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ /* It seems as if we cannot bind to regular files on windows, but only directories.
+ */
+ hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
+ todo_wine { ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hr = %08lx\n", hr); }
+ if (SUCCEEDED(hr)) {
+ IShellFolder_Release(psfFile);
+ }
+
+ /* Deleting the file and the directory */
+ DeleteFileW(wszTestFile);
+ RemoveDirectoryW(wszTestDir);
+
+ /* SHGetPathFromIDListW still works, although the file is not present anymore. */
+ result = SHGetPathFromIDListW(pidlTestFile, wszTestFile2);
+ ok (result, "SHGetPathFromIDListW failed! Last error: %08lx\n", GetLastError());
+ ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
+
+ if(!pSHBindToParent) return;
+
+ /* Binding to the folder and querying the display name of the file also works. */
+ hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
+ ok (SUCCEEDED(hr), "SHBindToParent failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
+ ok (SUCCEEDED(hr), "Personal->GetDisplayNameOf failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ IShellFolder_Release(psfPersonal);
+ return;
+ }
+
+ hr = StrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
+ ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08lx\n", hr);
+ ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
+
+ IShellFolder_Release(psfDesktop);
+ IShellFolder_Release(psfPersonal);
+}
+
+static void test_CallForAttributes(void)
+{
+ HKEY hKey;
+ LONG lResult;
+ HRESULT hr;
+ DWORD dwSize;
+ LPSHELLFOLDER psfDesktop;
+ LPITEMIDLIST pidlMyDocuments;
+ DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
+ static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
+ static const WCHAR wszCallForAttributes[] = {
+ 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
+ static const WCHAR wszMyDocumentsKey[] = {
+ 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
+ '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
+ '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
+ WCHAR wszMyDocuments[] = {
+ ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
+ '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
+
+ /* For the root of a namespace extension, the attributes are not queried by binding
+ * to the object and calling GetAttributesOf. Instead, the attributes are read from
+ * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
+ *
+ * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
+ * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
+ * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
+ * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
+ */
+ hr = SHGetDesktopFolder(&psfDesktop);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
+ &pidlMyDocuments, NULL);
+ ok (SUCCEEDED(hr),
+ "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08lx\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ dwAttributes = 0xffffffff;
+ hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
+ (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08lx\n", hr);
+
+ /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
+ todo_wine{ ok (dwAttributes & SFGAO_FILESYSTEM,
+ "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n"); }
+ ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
+ ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
+
+ /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
+ * key. So the test will return at this point, if run on wine.
+ */
+ lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
+ todo_wine { ok (lResult == ERROR_SUCCESS, "RegOpenKeyEx failed! result: %08lx\n", lResult); }
+ if (lResult != ERROR_SUCCESS) {
+ IMalloc_Free(ppM, pidlMyDocuments);
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ /* Query MyDocuments' Attributes value, to be able to restore it later. */
+ dwSize = sizeof(DWORD);
+ lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
+ ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08lx\n", lResult);
+ if (lResult != ERROR_SUCCESS) {
+ RegCloseKey(hKey);
+ IMalloc_Free(ppM, pidlMyDocuments);
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
+ dwSize = sizeof(DWORD);
+ lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
+ (LPBYTE)&dwOrigCallForAttributes, &dwSize);
+ ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08lx\n", lResult);
+ if (lResult != ERROR_SUCCESS) {
+ RegCloseKey(hKey);
+ IMalloc_Free(ppM, pidlMyDocuments);
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
+ * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
+ * SFGAO_FILESYSTEM attributes. */
+ dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
+ RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
+ dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
+ RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
+ (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
+
+ /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
+ * GetAttributesOf. It seems that once there is a single attribute queried, for which
+ * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
+ * the flags in Attributes are ignored.
+ */
+ dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
+ hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
+ (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08lx\n", hr);
+ if (SUCCEEDED(hr))
+ ok (dwAttributes == SFGAO_FILESYSTEM,
+ "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08lx\n",
+ dwAttributes);
+
+ /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
+ RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
+ RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
+ (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
+ RegCloseKey(hKey);
+ IMalloc_Free(ppM, pidlMyDocuments);
+ IShellFolder_Release(psfDesktop);
+}
+
+static void test_GetAttributesOf(void)
+{
+ HRESULT hr;
+ LPSHELLFOLDER psfDesktop, psfMyComputer;
+ SHITEMID emptyitem = { 0, { 0 } };
+ LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
+ LPITEMIDLIST pidlMyComputer;
+ DWORD dwFlags;
+ const static DWORD dwDesktopFlags = /* As observed on WinXP SP2 */
+ SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
+ const static DWORD dwMyComputerFlags = /* As observed on WinXP SP2 */
+ SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
+ SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
+ WCHAR wszMyComputer[] = {
+ ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
+ 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
+
+ hr = SHGetDesktopFolder(&psfDesktop);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) return;
+
+ /* The Desktop attributes can be queried with a single empty itemidlist, .. */
+ dwFlags = 0xffffffff;
+ hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(empty pidl) failed! hr = %08lx\n", hr);
+ ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08lx, expected: %08lx\n",
+ dwFlags, dwDesktopFlags);
+
+ /* .. or with no itemidlist at all. */
+ dwFlags = 0xffffffff;
+ hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(NULL) failed! hr = %08lx\n", hr);
+ ok (dwFlags == dwDesktopFlags, "Wrong Desktop attributes: %08lx, expected: %08lx\n",
+ dwFlags, dwDesktopFlags);
+
+ /* Testing the attributes of the MyComputer shellfolder */
+ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
+ ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08lx\n", hr);
+ if (FAILED(hr)) {
+ IShellFolder_Release(psfDesktop);
+ return;
+ }
+
+ /* WinXP SP2 sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
+ * folder object. It doesn't do this, if MyComputer is queried directly (see below).
+ * SFGAO_CANLINK is the same as DROPEFFECT_LINK, which MSDN says means: "Drag source
+ * should create a link to the original data". You can't create links on MyComputer on
+ * Windows, so this flag shouldn't be set. Seems like a bug in Windows. As long as nobody
+ * depends on this bug, we probably shouldn't imitate it.
+ */
+ dwFlags = 0xffffffff;
+ hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
+ ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyComputer) failed! hr = %08lx\n", hr);
+ todo_wine { ok ((dwFlags & ~(DWORD)SFGAO_CANLINK) == dwMyComputerFlags,
+ "Wrong MyComputer attributes: %08lx, expected: %08lx\n", dwFlags, dwMyComputerFlags); }
+
+ hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
+ ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08lx\n", hr);
+ IShellFolder_Release(psfDesktop);
+ IMalloc_Free(ppM, pidlMyComputer);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
+ todo_wine {ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08lx\n", hr); }
+
+ dwFlags = 0xffffffff;
+ hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
+ ok (SUCCEEDED(hr), "MyComputer->GetAttributesOf(NULL) failed! hr = %08lx\n", hr);
+ todo_wine { ok (dwFlags == dwMyComputerFlags,
+ "Wrong MyComputer attributes: %08lx, expected: %08lx\n", dwFlags, dwMyComputerFlags); }
+
+ IShellFolder_Release(psfMyComputer);
+}
+
+static void test_SHGetPathFromIDList(void)
+{
+ SHITEMID emptyitem = { 0, { 0 } };
+ LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
+ LPITEMIDLIST pidlMyComputer;
+ WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
+ BOOL result;
+ HRESULT hr;
+ LPSHELLFOLDER psfDesktop;
+ WCHAR wszMyComputer[] = {
+ ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
+ 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
+
+ if(!pSHGetSpecialFolderPathW) return;
+
+ /* Calling SHGetPathFromIDList with an empty pidl should return the desktop folder's path. */
+ result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
+ ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %08lx\n", GetLastError());
+ if (!result) return;
+
+ result = SHGetPathFromIDListW(pidlEmpty, wszPath);
+ ok(result, "SHGetPathFromIDListW failed! Last error: %08lx\n", GetLastError());
+ if (!result) return;
+ ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDList didn't return desktop path for empty pidl!\n");
+
+ /* MyComputer does not map to a filesystem path. SHGetPathFromIDList should fail. */
+ hr = SHGetDesktopFolder(&psfDesktop);
+ ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08lx\n", hr);
+ if (FAILED(hr)) return;
+
+ hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
+ ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08lx\n", hr);
+ IShellFolder_Release(psfDesktop);
+ if (FAILED(hr)) return;
+
+ SetLastError(0xdeadbeef);
+ result = SHGetPathFromIDListW(pidlMyComputer, wszPath);
+ ok (!result, "SHGetPathFromIDList succeeded where it shouldn't!\n");
+ ok (GetLastError()==0xdeadbeef, "SHGetPathFromIDList shouldn't set last error! Last error: %08lx\n", GetLastError());
+
+ IMalloc_Free(ppM, pidlMyComputer);
+}
+
+static void test_EnumObjects_and_CompareIDs(void)
+{
+ ITEMIDLIST *newPIDL;
+ IShellFolder *IDesktopFolder, *testIShellFolder;
+ char cCurrDirA [MAX_PATH] = {0};
+ WCHAR cCurrDirW [MAX_PATH];
+ static const WCHAR cTestDirW[] = {'\\','t','e','s','t','d','i','r',0};
+ int len;
+ HRESULT hr;
+
+ GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
+ len = lstrlenA(cCurrDirA);
+
+ if(len == 0) {
+ trace("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
+ return;
+ }
+ if(cCurrDirA[len-1] == '\\')
+ cCurrDirA[len-1] = 0;
+
+ MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
+ strcatW(cCurrDirW, cTestDirW);
+
+ hr = SHGetDesktopFolder(&IDesktopFolder);
+ ok(hr == S_OK, "SHGetDesktopfolder failed %08lx\n", hr);
+
+ CreateFilesFolders();
+
+ hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
+ ok(hr == S_OK, "ParseDisplayName failed %08lx\n", hr);
+
+ hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
+ ok(hr == S_OK, "BindToObject failed %08lx\n", hr);
+
+ test_EnumObjects(testIShellFolder);
+
+ hr = IShellFolder_Release(testIShellFolder);
+ ok(hr == S_OK, "IShellFolder_Release failed %08lx\n", hr);
+
+ Cleanup();
+
+ IMalloc_Free(ppM, newPIDL);
+}
+
+START_TEST(shlfolder)
+{
+ init_function_pointers();
+ /* if OleInitialize doesn't get called, ParseDisplayName returns
+ CO_E_NOTINITIALIZED for malformed directory names on win2k. */
+ OleInitialize(NULL);
+
+ test_ParseDisplayName();
+ test_BindToObject();
+ test_EnumObjects_and_CompareIDs();
+ test_GetDisplayName();
+ test_GetAttributesOf();
+ test_SHGetPathFromIDList();
+ test_CallForAttributes();
+
+ OleUninitialize();
+}
--- /dev/null
+/*
+ * Unit tests for shell32 string operations
+ *
+ * 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
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#define WINE_NOWINSOCK
+#include "windef.h"
+#include "winbase.h"
+#include "wtypes.h"
+#include "shellapi.h"
+#include "shtypes.h"
+#include "objbase.h"
+
+#include "wine/test.h"
+
+static HMODULE hShell32;
+static HRESULT (WINAPI *pStrRetToStrNAW)(LPVOID,DWORD,LPSTRRET,const ITEMIDLIST *);
+
+static WCHAR *CoDupStrW(const char* src)
+{
+ INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
+ WCHAR* szTemp = (WCHAR*)CoTaskMemAlloc(len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len);
+ return szTemp;
+}
+
+static inline int strcmpW(const WCHAR *str1, const WCHAR *str2)
+{
+ while (*str1 && (*str1 == *str2)) { str1++; str2++; }
+ return *str1 - *str2;
+}
+
+static void test_StrRetToStringNA(void)
+{
+ trace("StrRetToStringNAW is Ascii\n");
+ /* FIXME */
+}
+
+static void test_StrRetToStringNW(void)
+{
+ static const WCHAR szTestW[] = { 'T','e','s','t','\0' };
+ ITEMIDLIST iidl[10];
+ WCHAR buff[128];
+ STRRET strret;
+ BOOL ret;
+
+ trace("StrRetToStringNAW is Unicode\n");
+
+ strret.uType = STRRET_WSTR;
+ strret.u.pOleStr = CoDupStrW("Test");
+ memset(buff, 0xff, sizeof(buff));
+ ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
+ ok(ret == TRUE && !strcmpW(buff, szTestW),
+ "STRRET_WSTR: dup failed, ret=%d\n", ret);
+
+ strret.uType = STRRET_CSTR;
+ lstrcpyA(strret.u.cStr, "Test");
+ memset(buff, 0xff, sizeof(buff));
+ ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
+ ok(ret == TRUE && !strcmpW(buff, szTestW),
+ "STRRET_CSTR: dup failed, ret=%d\n", ret);
+
+ strret.uType = STRRET_OFFSET;
+ strret.u.uOffset = 1;
+ strcpy((char*)&iidl, " Test");
+ memset(buff, 0xff, sizeof(buff));
+ ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, iidl);
+ ok(ret == TRUE && !strcmpW(buff, szTestW),
+ "STRRET_OFFSET: dup failed, ret=%d\n", ret);
+
+ /* The next test crashes on W2K, WinXP and W2K3, so we don't test. */
+#if 0
+ /* Invalid dest - should return FALSE, except NT4 does not, so we don't check. */
+ strret.uType = STRRET_WSTR;
+ strret.u.pOleStr = CoDupStrW("Test");
+ pStrRetToStrNAW(NULL, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
+ trace("NULL dest: ret=%d\n", ret);
+#endif
+}
+
+START_TEST(string)
+{
+ CoInitialize(0);
+
+ hShell32 = LoadLibraryA("shell32.dll");
+ if (!hShell32)
+ return;
+
+ pStrRetToStrNAW = (void*)GetProcAddress(hShell32, (LPSTR)96);
+ if (pStrRetToStrNAW)
+ {
+ if (!(GetVersion() & 0x80000000))
+ test_StrRetToStringNW();
+ else
+ test_StrRetToStringNA();
+ }
+}
--- /dev/null
+/* Automatically generated file; DO NOT EDIT!! */
+
+/* stdarg.h is needed for Winelib */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "windef.h"
+#include "winbase.h"
+
+extern void func_shelllink(void);
+extern void func_shellpath(void);
+extern void func_shlexec(void);
+extern void func_shlfileop(void);
+extern void func_shlfolder(void);
+extern void func_string(void);
+
+struct test
+{
+ const char *name;
+ void (*func)(void);
+};
+
+
+const struct test winetest_testlist[] =
+{
+ { "shelllink", func_shelllink },
+ { "shellpath", func_shellpath },
+ { "shlexec", func_shlexec },
+ { "shlfileop", func_shlfileop },
+ { "shlfolder", func_shlfolder },
+ { "string", func_string },
+ { 0, 0 }
+};
+
+#define WINETEST_WANT_MAIN
+#include "wine/test.h"