From: Amine Khaldi Date: Sat, 29 Sep 2012 13:14:50 +0000 (+0000) Subject: [SHLWAPI_WINETEST]: Sync to Wine 1.5.13. X-Git-Tag: backups/ros-csrss@57560~129 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=d28c6f3c654bb24aefb566785a18f7099690a4f7 [SHLWAPI_WINETEST]: Sync to Wine 1.5.13. CORE-6415 svn path=/trunk/; revision=57428 --- diff --git a/rostests/winetests/shlwapi/CMakeLists.txt b/rostests/winetests/shlwapi/CMakeLists.txt index 807f11a2eb8..1676f6cccf8 100644 --- a/rostests/winetests/shlwapi/CMakeLists.txt +++ b/rostests/winetests/shlwapi/CMakeLists.txt @@ -1,7 +1,5 @@ -add_definitions( - -D__ROS_LONG64__ - -D_DLL -D__USE_CRTIMP) +add_definitions(-D__ROS_LONG64__) remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502) @@ -15,9 +13,9 @@ list(APPEND SOURCE path.c shreg.c string.c + thread.c url.c - testlist.c - thread.c) + testlist.c) add_executable(shlwapi_winetest ${SOURCE}) target_link_libraries(shlwapi_winetest wine uuid) diff --git a/rostests/winetests/shlwapi/clist.c b/rostests/winetests/shlwapi/clist.c index 3b979fdec8a..65d3178bd19 100755 --- a/rostests/winetests/shlwapi/clist.c +++ b/rostests/winetests/shlwapi/clist.c @@ -212,10 +212,16 @@ static HRESULT (WINAPI *pSHLWAPI_213)(_IDummyStream*); static HRESULT (WINAPI *pSHLWAPI_214)(_IDummyStream*,ULARGE_INTEGER*); -static void InitFunctionPtrs(void) +static BOOL InitFunctionPtrs(void) { SHLWAPI_hshlwapi = GetModuleHandleA("shlwapi.dll"); + /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */ + if(!GetProcAddress(SHLWAPI_hshlwapi, "SHCreateStreamOnFileEx")){ + win_skip("Too old shlwapi version\n"); + return FALSE; + } + pSHLWAPI_17 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)17); ok(pSHLWAPI_17 != 0, "No Ordinal 17\n"); pSHLWAPI_18 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)18); @@ -238,6 +244,8 @@ static void InitFunctionPtrs(void) ok(pSHLWAPI_213 != 0, "No Ordinal 213\n"); pSHLWAPI_214 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)214); ok(pSHLWAPI_214 != 0, "No Ordinal 214\n"); + + return TRUE; } static void InitDummyStream(_IDummyStream* iface) @@ -363,26 +371,22 @@ static void test_CList(void) inserted = (LPSHLWAPI_CLIST)buff; inserted->ulSize = sizeof(SHLWAPI_CLIST) -1; inserted->ulId = 33; - hRet = pSHLWAPI_20(&list, inserted); + /* The call succeeds but the item is not inserted, except on some early * versions which return failure. Wine behaves like later versions. */ - if (0) - { - ok(hRet == S_OK, "failed bad element size\n"); - } + pSHLWAPI_20(&list, inserted); + inserted = pSHLWAPI_22(list, 33); ok(inserted == NULL, "inserted bad element size\n"); inserted = (LPSHLWAPI_CLIST)buff; inserted->ulSize = 44; inserted->ulId = ~0U; - hRet = pSHLWAPI_20(&list, inserted); + /* See comment above, some early versions fail this call */ - if (0) - { - ok(hRet == S_OK, "failed adding a container\n"); - } + pSHLWAPI_20(&list, inserted); + item = SHLWAPI_CLIST_items; /* Look for nonexistent item in populated list */ @@ -623,7 +627,8 @@ static void test_SHLWAPI_214(void) START_TEST(clist) { - InitFunctionPtrs(); + if(!InitFunctionPtrs()) + return; test_CList(); diff --git a/rostests/winetests/shlwapi/clsid.c b/rostests/winetests/shlwapi/clsid.c index 98a8c6d4c01..cf9be96372d 100755 --- a/rostests/winetests/shlwapi/clsid.c +++ b/rostests/winetests/shlwapi/clsid.c @@ -40,7 +40,7 @@ static BOOL (WINAPI *pSHLWAPI_269)(LPCSTR, CLSID *) = 0; static DWORD (WINAPI *pSHLWAPI_23)(REFGUID, LPSTR, INT) = 0; /* GUIDs to test */ -const GUID * TEST_guids[] = { +static const GUID * TEST_guids[] = { &CLSID_ShellDesktop, &CLSID_ShellLink, &CATID_BrowsableShellExt, @@ -96,7 +96,7 @@ const GUID * TEST_guids[] = { NULL }; -DEFINE_GUID(IID_Endianess, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B, +DEFINE_GUID(IID_Endianness, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x0A); static void test_ClassIDs(void) @@ -128,26 +128,26 @@ static void test_ClassIDs(void) i++; } - /* Test endianess */ - dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 256); - ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for IID_Endianess\n", dwLen); + /* Test endianness */ + dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 256); + ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for IID_Endianness\n", dwLen); ok(!strcmp(szBuff, "{01020304-0506-0708-090A-0B0C0D0E0F0A}"), - "Endianess Broken, got '%s'\n", szBuff); + "Endianness Broken, got '%s'\n", szBuff); /* test lengths */ szBuff[0] = ':'; - dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 0); + dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 0); ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n"); ok(szBuff[0] == ':', "wrote to buffer with no length\n"); szBuff[0] = ':'; - dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 38); + dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 38); ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n"); ok(szBuff[0] == ':', "wrote to buffer with no length\n"); szBuff[0] = ':'; - dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39); + dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 39); ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n"); ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n"); @@ -156,7 +156,7 @@ static void test_ClassIDs(void) bRet = pSHLWAPI_269(szBuff, &guid); ok(bRet == FALSE, "accepted invalid string\n"); - dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39); + dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 39); ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n"); ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n"); } @@ -185,6 +185,13 @@ static void test_CLSIDFromProgIDWrap(void) START_TEST(clsid) { hShlwapi = GetModuleHandleA("shlwapi.dll"); + + /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */ + if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){ + win_skip("Too old shlwapi version\n"); + return; + } + pSHLWAPI_269 = (void*)GetProcAddress(hShlwapi, (LPSTR)269); pSHLWAPI_23 = (void*)GetProcAddress(hShlwapi, (LPSTR)23); diff --git a/rostests/winetests/shlwapi/istream.c b/rostests/winetests/shlwapi/istream.c index 4a36b3ab0ba..f525d7c3316 100644 --- a/rostests/winetests/shlwapi/istream.c +++ b/rostests/winetests/shlwapi/istream.c @@ -281,12 +281,15 @@ static void test_SHCreateStreamOnFileA(DWORD mode, DWORD stgm) ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n"); if (stream) { + BOOL delret; test_IStream_invalid_operations(stream, mode); refcount = IStream_Release(stream); ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount); - ok(DeleteFileA(test_file), "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n", test_file, GetLastError()); + delret = DeleteFileA(test_file); + ok(delret, "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n", + test_file, GetLastError()); } } @@ -388,14 +391,15 @@ static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm) ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n"); if (stream) { + BOOL delret; test_IStream_invalid_operations(stream, mode); refcount = IStream_Release(stream); ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount); - ok(DeleteFileA(test_fileA), - "SHCreateStreamOnFileW: could not delete the test file, got error %d\n", - GetLastError()); + delret = DeleteFileA(test_fileA); + ok(delret, "SHCreateStreamOnFileW: could not delete the test file, got error %d\n", + GetLastError()); } } @@ -409,6 +413,7 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) WCHAR test_file[MAX_PATH]; CHAR test_fileA[MAX_PATH]; static const CHAR testEx_txt[] = "\\testEx.txt"; + BOOL delret; trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm); @@ -489,9 +494,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) refcount = IStream_Release(stream); ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); - ok(DeleteFileA(test_fileA), - "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", - GetLastError()); + delret = DeleteFileA(test_fileA); + ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", + GetLastError()); } stream = NULL; @@ -510,9 +515,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) refcount = IStream_Release(stream); ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); - ok(DeleteFileA(test_fileA), - "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", - GetLastError()); + delret = DeleteFileA(test_fileA); + ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", + GetLastError()); } stream = NULL; @@ -577,9 +582,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm) ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount); } - ok(DeleteFileA(test_fileA), - "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", - GetLastError()); + delret = DeleteFileA(test_fileA); + ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n", + GetLastError()); } diff --git a/rostests/winetests/shlwapi/ordinal.c b/rostests/winetests/shlwapi/ordinal.c index bf614182771..1229ae2a75f 100755 --- a/rostests/winetests/shlwapi/ordinal.c +++ b/rostests/winetests/shlwapi/ordinal.c @@ -20,6 +20,7 @@ #include #define COBJMACROS +#define CONST_VTABLE #include "wine/test.h" #include "winbase.h" #include "winerror.h" @@ -31,10 +32,12 @@ #include "shlwapi.h" #include "docobj.h" #include "shobjidl.h" +#include "shlobj.h" /* Function ptrs for ordinal calls */ static HMODULE hShlwapi; static BOOL is_win2k_and_lower; +static BOOL is_win9x; static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int); static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD); @@ -56,10 +59,22 @@ static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *); static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*); static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*); static HWND (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR); +static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**); +static DWORD (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR); +static BOOL (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR); +static HKEY (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL); +static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*); +static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD); +static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR); +static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*); +static HWND (WINAPI *pSHSetParentHwnd)(HWND, HWND); static HMODULE hmlang; static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT); +static HMODULE hshell32; +static HRESULT (WINAPI *pSHGetDesktopFolder)(IShellFolder**); + static const CHAR ie_international[] = { 'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', @@ -68,6 +83,13 @@ static const CHAR ie_international[] = { static const CHAR acceptlanguage[] = { 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0}; +static int strcmp_wa(LPCWSTR strw, const char *stra) +{ + CHAR buf[512]; + WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); + return lstrcmpA(stra, buf); +} + typedef struct { int id; const void *args[5]; @@ -335,7 +357,7 @@ static void test_GetAcceptLanguagesA(void) buffer[maxlen] = 0; hr = pGetAcceptLanguagesA( buffer, &len); /* When the buffer is too small, win7_32 and w2k8_64 and above fail with - HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed + HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions succeed and return a partial 0 terminated result while other versions fail with E_INVALIDARG and return a partial unterminated result */ ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) || @@ -576,6 +598,7 @@ static void test_GetShellSecurityDescriptor(void) }; SECURITY_DESCRIPTOR* psd; SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int); + void *pChrCmpIW = GetProcAddress(hShlwapi, "ChrCmpIW"); pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475); @@ -585,12 +608,18 @@ static void test_GetShellSecurityDescriptor(void) return; } + if(pChrCmpIW && pChrCmpIW == pGetShellSecurityDescriptor) /* win2k */ + { + win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n"); + return; + } + psd = pGetShellSecurityDescriptor(NULL, 2); ok(psd==NULL || broken(psd==INVALID_HANDLE_VALUE), /* IE5 */ "GetShellSecurityDescriptor should fail\n"); psd = pGetShellSecurityDescriptor(rgsup, 0); - ok(psd==NULL, "GetShellSecurityDescriptor should fail\n"); + ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd); SetLastError(0xdeadbeef); psd = pGetShellSecurityDescriptor(rgsup, 2); @@ -600,7 +629,7 @@ static void test_GetShellSecurityDescriptor(void) win_skip("GetShellSecurityDescriptor is not implemented\n"); return; } - if (psd==INVALID_HANDLE_VALUE) + if (psd == INVALID_HANDLE_VALUE) { win_skip("GetShellSecurityDescriptor is broken on IE5\n"); return; @@ -608,19 +637,19 @@ static void test_GetShellSecurityDescriptor(void) ok(psd!=NULL, "GetShellSecurityDescriptor failed\n"); if (psd!=NULL) { - BOOL bHasDacl = FALSE, bDefaulted; + BOOL bHasDacl = FALSE, bDefaulted, ret; PACL pAcl; DWORD dwRev; SECURITY_DESCRIPTOR_CONTROL control; ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n"); - ok(GetSecurityDescriptorControl(psd, &control, &dwRev), - "GetSecurityDescriptorControl failed with error %u\n", GetLastError()); + ret = GetSecurityDescriptorControl(psd, &control, &dwRev); + ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError()); ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n"); - ok(GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted), - "GetSecurityDescriptorDacl failed with error %u\n", GetLastError()); + ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted); + ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError()); ok(bHasDacl, "SD has no DACL\n"); if (bHasDacl) @@ -634,28 +663,31 @@ static void test_GetShellSecurityDescriptor(void) ok(IsValidAcl(pAcl), "DACL is not valid\n"); - ok(GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation), - "GetAclInformation failed with error %u\n", GetLastError()); + ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation); + ok(ret, "GetAclInformation failed with error %u\n", GetLastError()); ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount); if (asiSize.AceCount == 3) { ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */ - ok(GetAce(pAcl, 0, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError()); + ret = GetAce(pAcl, 0, (LPVOID*)&paaa); + ok(ret, "GetAce failed with error %u\n", GetLastError()); ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, "Invalid ACE type %d\n", paaa->Header.AceType); ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags); ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask); - ok(GetAce(pAcl, 1, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError()); + ret = GetAce(pAcl, 1, (LPVOID*)&paaa); + ok(ret, "GetAce failed with error %u\n", GetLastError()); ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, "Invalid ACE type %d\n", paaa->Header.AceType); /* first one of two ACEs generated from inheritable entry - without inheritance */ ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags); ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask); - ok(GetAce(pAcl, 2, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError()); + ret = GetAce(pAcl, 2, (LPVOID*)&paaa); + ok(ret, "GetAce failed with error %u\n", GetLastError()); ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, "Invalid ACE type %d\n", paaa->Header.AceType); /* second ACE - with inheritance */ @@ -719,22 +751,32 @@ static void test_SHPackDispParams(void) typedef struct _disp { - const IDispatchVtbl *vtbl; + IDispatch IDispatch_iface; LONG refCount; } Disp; +static inline Disp *impl_from_IDispatch(IDispatch *iface) +{ + return CONTAINING_RECORD(iface, Disp, IDispatch_iface); +} + typedef struct _contain { - const IConnectionPointContainerVtbl *vtbl; + IConnectionPointContainer IConnectionPointContainer_iface; LONG refCount; UINT ptCount; IConnectionPoint **pt; } Contain; +static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface) +{ + return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface); +} + typedef struct _cntptn { - const IConnectionPointVtbl *vtbl; + IConnectionPoint IConnectionPoint_iface; LONG refCount; Contain *container; @@ -743,24 +785,39 @@ typedef struct _cntptn IUnknown **sink; } ConPt; +static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface) +{ + return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface); +} + typedef struct _enum { - const IEnumConnectionsVtbl *vtbl; + IEnumConnections IEnumConnections_iface; LONG refCount; UINT idx; ConPt *pt; } EnumCon; +static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface) +{ + return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface); +} + typedef struct _enumpt { - const IEnumConnectionPointsVtbl *vtbl; + IEnumConnectionPoints IEnumConnectionPoints_iface; LONG refCount; int idx; Contain *container; } EnumPt; +static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface) +{ + return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface); +} + static HRESULT WINAPI Disp_QueryInterface( IDispatch* This, @@ -776,7 +833,7 @@ static HRESULT WINAPI Disp_QueryInterface( if (*ppvObject) { - IUnknown_AddRef(This); + IDispatch_AddRef(This); return S_OK; } @@ -786,13 +843,13 @@ static HRESULT WINAPI Disp_QueryInterface( static ULONG WINAPI Disp_AddRef(IDispatch* This) { - Disp *iface = (Disp*)This; + Disp *iface = impl_from_IDispatch(This); return InterlockedIncrement(&iface->refCount); } static ULONG WINAPI Disp_Release(IDispatch* This) { - Disp *iface = (Disp*)This; + Disp *iface = impl_from_IDispatch(This); ULONG ret; ret = InterlockedDecrement(&iface->refCount); @@ -891,7 +948,7 @@ static HRESULT WINAPI Enum_QueryInterface( if (*ppvObject) { - IUnknown_AddRef(This); + IEnumConnections_AddRef(This); return S_OK; } @@ -901,13 +958,13 @@ static HRESULT WINAPI Enum_QueryInterface( static ULONG WINAPI Enum_AddRef(IEnumConnections* This) { - EnumCon *iface = (EnumCon*)This; + EnumCon *iface = impl_from_IEnumConnections(This); return InterlockedIncrement(&iface->refCount); } static ULONG WINAPI Enum_Release(IEnumConnections* This) { - EnumCon *iface = (EnumCon*)This; + EnumCon *iface = impl_from_IEnumConnections(This); ULONG ret; ret = InterlockedDecrement(&iface->refCount); @@ -922,7 +979,7 @@ static HRESULT WINAPI Enum_Next( LPCONNECTDATA rgcd, ULONG *pcFetched) { - EnumCon *iface = (EnumCon*)This; + EnumCon *iface = impl_from_IEnumConnections(This); if (cConnections > 0 && iface->idx < iface->pt->sinkCount) { @@ -983,7 +1040,7 @@ static HRESULT WINAPI ConPt_QueryInterface( if (*ppvObject) { - IUnknown_AddRef(This); + IConnectionPoint_AddRef(This); return S_OK; } @@ -994,14 +1051,14 @@ static HRESULT WINAPI ConPt_QueryInterface( static ULONG WINAPI ConPt_AddRef( IConnectionPoint* This) { - ConPt *iface = (ConPt*)This; + ConPt *iface = impl_from_IConnectionPoint(This); return InterlockedIncrement(&iface->refCount); } static ULONG WINAPI ConPt_Release( IConnectionPoint* This) { - ConPt *iface = (ConPt*)This; + ConPt *iface = impl_from_IConnectionPoint(This); ULONG ret; ret = InterlockedDecrement(&iface->refCount); @@ -1027,7 +1084,7 @@ static HRESULT WINAPI ConPt_GetConnectionInterface( IID *pIID) { static int i = 0; - ConPt *iface = (ConPt*)This; + ConPt *iface = impl_from_IConnectionPoint(This); if (i==0) { i++; @@ -1042,9 +1099,9 @@ static HRESULT WINAPI ConPt_GetConnectionPointContainer( IConnectionPoint* This, IConnectionPointContainer **ppCPC) { - ConPt *iface = (ConPt*)This; + ConPt *iface = impl_from_IConnectionPoint(This); - *ppCPC = (IConnectionPointContainer*)iface->container; + *ppCPC = &iface->container->IConnectionPointContainer_iface; return S_OK; } @@ -1053,7 +1110,7 @@ static HRESULT WINAPI ConPt_Advise( IUnknown *pUnkSink, DWORD *pdwCookie) { - ConPt *iface = (ConPt*)This; + ConPt *iface = impl_from_IConnectionPoint(This); if (iface->sinkCount == 0) iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*)); @@ -1070,7 +1127,7 @@ static HRESULT WINAPI ConPt_Unadvise( IConnectionPoint* This, DWORD dwCookie) { - ConPt *iface = (ConPt*)This; + ConPt *iface = impl_from_IConnectionPoint(This); if (dwCookie > iface->sinkCount) return E_FAIL; @@ -1089,11 +1146,11 @@ static HRESULT WINAPI ConPt_EnumConnections( EnumCon *ec; ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon)); - ec->vtbl = &enum_vtbl; + ec->IEnumConnections_iface.lpVtbl = &enum_vtbl; ec->refCount = 1; - ec->pt = (ConPt*)This; + ec->pt = impl_from_IConnectionPoint(This); ec->idx = 0; - *ppEnum = (IEnumConnections*)ec; + *ppEnum = &ec->IEnumConnections_iface; return S_OK; } @@ -1124,7 +1181,7 @@ static HRESULT WINAPI EnumPt_QueryInterface( if (*ppvObject) { - IUnknown_AddRef(This); + IEnumConnectionPoints_AddRef(This); return S_OK; } @@ -1134,13 +1191,13 @@ static HRESULT WINAPI EnumPt_QueryInterface( static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This) { - EnumPt *iface = (EnumPt*)This; + EnumPt *iface = impl_from_IEnumConnectionPoints(This); return InterlockedIncrement(&iface->refCount); } static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This) { - EnumPt *iface = (EnumPt*)This; + EnumPt *iface = impl_from_IEnumConnectionPoints(This); ULONG ret; ret = InterlockedDecrement(&iface->refCount); @@ -1155,12 +1212,12 @@ static HRESULT WINAPI EnumPt_Next( IConnectionPoint **rgcd, ULONG *pcFetched) { - EnumPt *iface = (EnumPt*)This; + EnumPt *iface = impl_from_IEnumConnectionPoints(This); if (cConnections > 0 && iface->idx < iface->container->ptCount) { *rgcd = iface->container->pt[iface->idx]; - IUnknown_AddRef(iface->container->pt[iface->idx]); + IConnectionPoint_AddRef(iface->container->pt[iface->idx]); if (pcFetched) *pcFetched = 1; iface->idx++; @@ -1215,7 +1272,7 @@ static HRESULT WINAPI Contain_QueryInterface( if (*ppvObject) { - IUnknown_AddRef(This); + IConnectionPointContainer_AddRef(This); return S_OK; } @@ -1226,14 +1283,14 @@ static HRESULT WINAPI Contain_QueryInterface( static ULONG WINAPI Contain_AddRef( IConnectionPointContainer* This) { - Contain *iface = (Contain*)This; + Contain *iface = impl_from_IConnectionPointContainer(This); return InterlockedIncrement(&iface->refCount); } static ULONG WINAPI Contain_Release( IConnectionPointContainer* This) { - Contain *iface = (Contain*)This; + Contain *iface = impl_from_IConnectionPointContainer(This); ULONG ret; ret = InterlockedDecrement(&iface->refCount); @@ -1243,7 +1300,7 @@ static ULONG WINAPI Contain_Release( { int i; for (i = 0; i < iface->ptCount; i++) - IUnknown_Release(iface->pt[i]); + IConnectionPoint_Release(iface->pt[i]); HeapFree(GetProcessHeap(),0,iface->pt); } HeapFree(GetProcessHeap(),0,This); @@ -1258,11 +1315,11 @@ static HRESULT WINAPI Contain_EnumConnectionPoints( EnumPt *ec; ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt)); - ec->vtbl = &enumpt_vtbl; + ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl; ec->refCount = 1; ec->idx= 0; - ec->container = (Contain*)This; - *ppEnum = (IEnumConnectionPoints*)ec; + ec->container = impl_from_IConnectionPointContainer(This); + *ppEnum = &ec->IEnumConnectionPoints_iface; return S_OK; } @@ -1272,13 +1329,13 @@ static HRESULT WINAPI Contain_FindConnectionPoint( REFIID riid, IConnectionPoint **ppCP) { - Contain *iface = (Contain*)This; + Contain *iface = impl_from_IConnectionPointContainer(This); ConPt *pt; if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0) { pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt)); - pt->vtbl = &point_vtbl; + pt->IConnectionPoint_iface.lpVtbl = &point_vtbl; pt->refCount = 1; pt->sinkCount = 0; pt->sink = NULL; @@ -1289,10 +1346,10 @@ static HRESULT WINAPI Contain_FindConnectionPoint( iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*)); else iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1)); - iface->pt[iface->ptCount] = (IConnectionPoint*)pt; + iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface; iface->ptCount++; - *ppCP = (IConnectionPoint*)pt; + *ppCP = &pt->IConnectionPoint_iface; } else { @@ -1330,13 +1387,13 @@ static void test_IConnectionPoint(void) } container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain)); - container->vtbl = &contain_vtbl; + container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl; container->refCount = 1; container->ptCount = 0; container->pt = NULL; dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp)); - dispatch->vtbl = &disp_vtbl; + dispatch->IDispatch_iface.lpVtbl = &disp_vtbl; dispatch->refCount = 1; rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point); @@ -1374,11 +1431,16 @@ static void test_IConnectionPoint(void) typedef struct _propbag { - const IPropertyBagVtbl *vtbl; + IPropertyBag IPropertyBag_iface; LONG refCount; } PropBag; +static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface) +{ + return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface); +} + static HRESULT WINAPI Prop_QueryInterface( IPropertyBag* This, @@ -1394,7 +1456,7 @@ static HRESULT WINAPI Prop_QueryInterface( if (*ppvObject) { - IUnknown_AddRef(This); + IPropertyBag_AddRef(This); return S_OK; } @@ -1405,14 +1467,14 @@ static HRESULT WINAPI Prop_QueryInterface( static ULONG WINAPI Prop_AddRef( IPropertyBag* This) { - PropBag *iface = (PropBag*)This; + PropBag *iface = impl_from_IPropertyBag(This); return InterlockedIncrement(&iface->refCount); } static ULONG WINAPI Prop_Release( IPropertyBag* This) { - PropBag *iface = (PropBag*)This; + PropBag *iface = impl_from_IPropertyBag(This); ULONG ret; ret = InterlockedDecrement(&iface->refCount); @@ -1465,19 +1527,18 @@ static void test_SHPropertyBag_ReadLONG(void) pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag)); pb->refCount = 1; - pb->vtbl = &prop_vtbl; + pb->IPropertyBag_iface.lpVtbl = &prop_vtbl; out = 0xfeedface; rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out); ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc); ok(out == 0xfeedface, "value should not have changed\n"); - rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, NULL, &out); + rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out); ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc); ok(out == 0xfeedface, "value should not have changed\n"); - rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, NULL); + rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL); ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc); - ok(out == 0xfeedface, "value should not have changed\n"); - rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, &out); + rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out); ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc); ok(out == 0xfeedface || broken(out == 0xfeedfa00), "value should not have changed %x\n",out); IUnknown_Release((IUnknown*)pb); @@ -1577,7 +1638,7 @@ static void test_SHFormatDateTimeA(void) if (0) { /* crashes on native */ - ret = pSHFormatDateTimeA(NULL, NULL, NULL, 0); + pSHFormatDateTimeA(NULL, NULL, NULL, 0); } GetLocalTime(&st); @@ -1589,7 +1650,8 @@ if (0) SetLastError(0xdeadbeef); ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0); ok(ret == 0, "got %d\n", ret); - ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); + ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */), + "expected 0xdeadbeef, got %d\n", GetLastError()); SetLastError(0xdeadbeef); buff[0] = 'a'; buff[1] = 0; @@ -1670,24 +1732,30 @@ if (0) flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME; ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1); - ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); - ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); - strcat(buff2, ", "); ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)); ok(ret == lstrlenA(buff3)+1, "got %d\n", ret); - strcat(buff2, buff3); - ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); + ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0, + "expected (%s), got (%s) for time part\n", + buff3, buff + lstrlenA(buff) - lstrlenA(buff3)); + ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); + ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); + buff[lstrlenA(buff2)] = '\0'; + ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", + buff2, buff); flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME; ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); ok(ret == lstrlenA(buff)+1, "got %d\n", ret); - ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); - ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); - strcat(buff2, ", "); ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)); ok(ret == lstrlenA(buff3)+1, "got %d\n", ret); - strcat(buff2, buff3); - ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff); + ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0, + "expected (%s), got (%s) for time part\n", + buff3, buff + lstrlenA(buff) - lstrlenA(buff3)); + ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)); + ok(ret == lstrlenA(buff2)+1, "got %d\n", ret); + buff[lstrlenA(buff2)] = '\0'; + ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", + buff2, buff); flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME; ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff)); @@ -1715,12 +1783,12 @@ if (0) static void test_SHFormatDateTimeW(void) { FILETIME UNALIGNED filetime; - WCHAR buff[100], buff2[100], buff3[100]; + WCHAR buff[100], buff2[100], buff3[100], *p1, *p2; SYSTEMTIME st; DWORD flags; INT ret; static const WCHAR spaceW[] = {' ',0}; - static const WCHAR commaW[] = {',',' ',0}; +#define UNICODE_LTR_MARK 0x200e if(!pSHFormatDateTimeW) { @@ -1731,7 +1799,7 @@ static void test_SHFormatDateTimeW(void) if (0) { /* crashes on native */ - ret = pSHFormatDateTimeW(NULL, NULL, NULL, 0); + pSHFormatDateTimeW(NULL, NULL, NULL, 0); } GetLocalTime(&st); @@ -1742,13 +1810,13 @@ if (0) /* no way to get required buffer length here */ SetLastError(0xdeadbeef); ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0); - ok(ret == 0, "got %d\n", ret); + ok(ret == 0, "expected 0, got %d\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); SetLastError(0xdeadbeef); buff[0] = 'a'; buff[1] = 0; ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0); - ok(ret == 0, "got %d\n", ret); + ok(ret == 0, "expected 0, got %d\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); ok(buff[0] == 'a', "expected same string\n"); @@ -1756,20 +1824,23 @@ if (0) flags = FDTF_SHORTTIME | FDTF_LONGTIME; SetLastError(0xdeadbeef); ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); flags = FDTF_SHORTDATE | FDTF_LONGDATE; SetLastError(0xdeadbeef); ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError()); flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE; SetLastError(0xdeadbeef); buff[0] = 0; /* NT4 doesn't clear the buffer on failure */ ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */ "expected 0xdeadbeef, got %d\n", GetLastError()); @@ -1777,7 +1848,8 @@ if (0) /* now check returned strings */ flags = FDTF_SHORTTIME; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); SetLastError(0xdeadbeef); ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) @@ -1785,88 +1857,125 @@ if (0) win_skip("Needed W-functions are not implemented\n"); return; } - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); flags = FDTF_LONGTIME; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); /* both time flags */ flags = FDTF_LONGTIME | FDTF_SHORTTIME; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n"); flags = FDTF_SHORTDATE; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); flags = FDTF_LONGDATE; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); /* both date flags */ flags = FDTF_LONGDATE | FDTF_SHORTDATE; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); /* various combinations of date/time flags */ flags = FDTF_LONGDATE | FDTF_SHORTTIME; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d, length %d\n", ret, lstrlenW(buff)+1); - ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); - lstrcatW(buff2, commaW); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff3)+1, "got %d\n", ret); - lstrcatW(buff2, buff3); - ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); + ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); + ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0, + "expected (%s), got (%s) for time part\n", + wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3))); + ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); + p1 = buff; + p2 = buff2; + while (*p2 != '\0') + { + while (*p1 == UNICODE_LTR_MARK) + p1++; + while (*p2 == UNICODE_LTR_MARK) + p2++; + p1++; + p2++; + } + *p1 = '\0'; + ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", + wine_dbgstr_w(buff2), wine_dbgstr_w(buff)); flags = FDTF_LONGDATE | FDTF_LONGTIME; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); - ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); - lstrcatW(buff2, commaW); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff3)+1, "got %d\n", ret); - lstrcatW(buff2, buff3); - ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); + ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); + ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0, + "expected (%s), got (%s) for time part\n", + wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3))); + ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); + p1 = buff; + p2 = buff2; + while (*p2 != '\0') + { + while (*p1 == UNICODE_LTR_MARK) + p1++; + while (*p2 == UNICODE_LTR_MARK) + p2++; + p1++; + p2++; + } + *p1 = '\0'; + ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n", + wine_dbgstr_w(buff2), wine_dbgstr_w(buff)); flags = FDTF_SHORTDATE | FDTF_SHORTTIME; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); lstrcatW(buff2, spaceW); ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff3)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); lstrcatW(buff2, buff3); ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); flags = FDTF_SHORTDATE | FDTF_LONGTIME; ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff), + "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret); ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff2)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret); lstrcatW(buff2, spaceW); ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR)); - ok(ret == lstrlenW(buff3)+1, "got %d\n", ret); + ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret); lstrcatW(buff2, buff3); ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); } @@ -1895,6 +2004,7 @@ static void test_SHGetObjectCompatFlags(void) }; static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects"; + void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma"); CHAR keyA[39]; /* {CLSID} */ HKEY root; DWORD ret; @@ -1906,6 +2016,12 @@ static void test_SHGetObjectCompatFlags(void) return; } + if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */ + { + win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n"); + return; + } + /* null args */ ret = pSHGetObjectCompatFlags(NULL, NULL); ok(ret == 0, "got %d\n", ret); @@ -1954,10 +2070,15 @@ static void test_SHGetObjectCompatFlags(void) } typedef struct { - const IOleCommandTargetVtbl *lpVtbl; + IOleCommandTarget IOleCommandTarget_iface; LONG ref; } IOleCommandTargetImpl; +static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface) +{ + return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface); +} + static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl; static IOleCommandTarget* IOleCommandTargetImpl_Construct(void) @@ -1965,15 +2086,15 @@ static IOleCommandTarget* IOleCommandTargetImpl_Construct(void) IOleCommandTargetImpl *obj; obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); - obj->lpVtbl = &IOleCommandTargetImpl_Vtbl; + obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl; obj->ref = 1; - return (IOleCommandTarget*)obj; + return &obj->IOleCommandTarget_iface; } static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj) { - IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface; + IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface); if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IOleCommandTarget)) @@ -1983,7 +2104,7 @@ static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *if if(*ppvObj) { - IUnknown_AddRef(iface); + IOleCommandTarget_AddRef(iface); return S_OK; } @@ -1992,13 +2113,13 @@ static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *if static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface) { - IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface; + IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface); return InterlockedIncrement(&This->ref); } static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface) { - IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface; + IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface); ULONG ref = InterlockedDecrement(&This->ref); if (!ref) @@ -2037,15 +2158,25 @@ static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl = }; typedef struct { - const IServiceProviderVtbl *lpVtbl; + IServiceProvider IServiceProvider_iface; LONG ref; } IServiceProviderImpl; +static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface) +{ + return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface); +} + typedef struct { - const IProfferServiceVtbl *lpVtbl; + IProfferService IProfferService_iface; LONG ref; } IProfferServiceImpl; +static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface) +{ + return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface); +} + static const IServiceProviderVtbl IServiceProviderImpl_Vtbl; static const IProfferServiceVtbl IProfferServiceImpl_Vtbl; @@ -2055,10 +2186,10 @@ static IServiceProvider* IServiceProviderImpl_Construct(void) IServiceProviderImpl *obj; obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); - obj->lpVtbl = &IServiceProviderImpl_Vtbl; + obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl; obj->ref = 1; - return (IServiceProvider*)obj; + return &obj->IServiceProvider_iface; } static IProfferService* IProfferServiceImpl_Construct(void) @@ -2066,15 +2197,15 @@ static IProfferService* IProfferServiceImpl_Construct(void) IProfferServiceImpl *obj; obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); - obj->lpVtbl = &IProfferServiceImpl_Vtbl; + obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl; obj->ref = 1; - return (IProfferService*)obj; + return &obj->IProfferService_iface; } static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj) { - IServiceProviderImpl *This = (IServiceProviderImpl *)iface; + IServiceProviderImpl *This = impl_from_IServiceProvider(iface); if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IServiceProvider)) @@ -2084,7 +2215,7 @@ static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *ifac if(*ppvObj) { - IUnknown_AddRef(iface); + IServiceProvider_AddRef(iface); /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */ if (IsEqualIID(riid, &IID_IServiceProvider)) add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0); @@ -2096,13 +2227,13 @@ static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *ifac static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface) { - IServiceProviderImpl *This = (IServiceProviderImpl *)iface; + IServiceProviderImpl *This = impl_from_IServiceProvider(iface); return InterlockedIncrement(&This->ref); } static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface) { - IServiceProviderImpl *This = (IServiceProviderImpl *)iface; + IServiceProviderImpl *This = impl_from_IServiceProvider(iface); ULONG ref = InterlockedDecrement(&This->ref); if (!ref) @@ -2186,7 +2317,7 @@ static void test_IUnknown_QueryServiceExec(void) static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj) { - IProfferServiceImpl *This = (IProfferServiceImpl *)iface; + IProfferServiceImpl *This = impl_from_IProfferService(iface); if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IProfferService)) @@ -2202,7 +2333,7 @@ static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, if(*ppvObj) { - IUnknown_AddRef(iface); + IProfferService_AddRef(iface); return S_OK; } @@ -2211,13 +2342,13 @@ static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface) { - IProfferServiceImpl *This = (IProfferServiceImpl *)iface; + IProfferServiceImpl *This = impl_from_IProfferService(iface); return InterlockedIncrement(&This->ref); } static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface) { - IProfferServiceImpl *This = (IProfferServiceImpl *)iface; + IProfferServiceImpl *This = impl_from_IProfferService(iface); ULONG ref = InterlockedDecrement(&This->ref); if (!ref) @@ -2231,6 +2362,7 @@ static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface) static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface, REFGUID service, IServiceProvider *pService, DWORD *pCookie) { + *pCookie = 0xdeadbeef; add_call(&trace_got, 3, service, pService, pCookie, 0, 0); return S_OK; } @@ -2288,8 +2420,10 @@ static void test_IUnknown_ProfferService(void) add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0); init_call_trace(&trace_got); + cookie = 0; hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie); ok(hr == S_OK, "got 0x%08x\n", hr); + ok(cookie == 0xdeadbeef, "got %x\n", cookie); ok_trace(&trace_expected, &trace_got); free_call_trace(&trace_got); @@ -2303,8 +2437,10 @@ static void test_IUnknown_ProfferService(void) add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0); init_call_trace(&trace_got); + ok(cookie != 0, "got %x\n", cookie); hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie); ok(hr == S_OK, "got 0x%08x\n", hr); + ok(cookie == 0, "got %x\n", cookie); ok_trace(&trace_expected, &trace_got); free_call_trace(&trace_got); free_call_trace(&trace_expected); @@ -2359,16 +2495,427 @@ static void test_SHCreateWorkerWindowA(void) /* test exstyle */ ret = GetWindowLongA(hwnd, GWL_EXSTYLE); - ok(ret == WS_EX_WINDOWEDGE, "0x%08lx\n", ret); + ok(ret == WS_EX_WINDOWEDGE || + ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret); DestroyWindow(hwnd); hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0); ret = GetWindowLongA(hwnd, GWL_EXSTYLE); - ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW), "0x%08lx\n", ret); + ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) || + ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret); DestroyWindow(hwnd); } +static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface, + REFIID riid, void **ppv) +{ + /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */ + ok(!IsEqualGUID(&IID_IShellFolder, riid), + "Unexpected QI for IShellFolder\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI SF_AddRef(IShellFolder *iface) +{ + return 2; +} + +static ULONG WINAPI SF_Release(IShellFolder *iface) +{ + return 1; +} + +static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface, + HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten, + LPITEMIDLIST *idl, ULONG *attr) +{ + ok(0, "Didn't expect ParseDisplayName\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface, + HWND owner, SHCONTF flags, IEnumIDList **enm) +{ + *enm = (IEnumIDList*)0xcafebabe; + return S_OK; +} + +static HRESULT WINAPI SF_BindToObject(IShellFolder *iface, + LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj) +{ + ok(0, "Didn't expect BindToObject\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface, + LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj) +{ + ok(0, "Didn't expect BindToStorage\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface, + LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2) +{ + ok(0, "Didn't expect CompareIDs\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface, + HWND owner, REFIID riid, void **out) +{ + ok(0, "Didn't expect CreateViewObject\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface, + UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut) +{ + ok(0, "Didn't expect GetAttributesOf\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface, + HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut, + void **out) +{ + ok(0, "Didn't expect GetUIObjectOf\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface, + LPCITEMIDLIST idl, SHGDNF flags, STRRET *name) +{ + ok(0, "Didn't expect GetDisplayNameOf\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface, + HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags, + LPITEMIDLIST *idlOut) +{ + ok(0, "Didn't expect SetNameOf\n"); + return E_NOTIMPL; +} + +static IShellFolderVtbl ShellFolderVtbl = { + SF_QueryInterface, + SF_AddRef, + SF_Release, + SF_ParseDisplayName, + SF_EnumObjects, + SF_BindToObject, + SF_BindToStorage, + SF_CompareIDs, + SF_CreateViewObject, + SF_GetAttributesOf, + SF_GetUIObjectOf, + SF_GetDisplayNameOf, + SF_SetNameOf +}; + +static IShellFolder ShellFolder = { &ShellFolderVtbl }; + +static void test_SHIShellFolder_EnumObjects(void) +{ + IEnumIDList *enm; + HRESULT hres; + IShellFolder *folder; + + if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){ + win_skip("SHIShellFolder_EnumObjects not available\n"); + return; + } + + if(0){ + /* NULL object crashes on Windows */ + pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL); + } + + /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */ + enm = (IEnumIDList*)0xdeadbeef; + hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm); + ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres); + ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm); + + /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */ + hres = pSHGetDesktopFolder(&folder); + ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres); + + enm = NULL; + hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm); + ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres); + ok(enm != NULL, "Didn't get an enumerator\n"); + if(enm) + IEnumIDList_Release(enm); + + IShellFolder_Release(folder); +} + +static void write_inifile(LPCWSTR filename) +{ + DWORD written; + HANDLE file; + + static const char data[] = + "[TestApp]\r\n" + "AKey=1\r\n" + "AnotherKey=asdf\r\n"; + + file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if(file == INVALID_HANDLE_VALUE) + return; + + WriteFile(file, data, sizeof(data), &written, NULL); + + CloseHandle(file); +} + +#define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e) +static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp) +{ + HANDLE file; + CHAR buf[1024]; + DWORD read; + + file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if(file == INVALID_HANDLE_VALUE) + return; + + ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL); + buf[read] = '\0'; + + CloseHandle(file); + + ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp, + buf); +} + +static void test_SHGetIniString(void) +{ + DWORD ret; + WCHAR out[64] = {0}; + + static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0}; + static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0}; + static const WCHAR AKeyW[] = {'A','K','e','y',0}; + static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0}; + static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0}; + + if(!pSHGetIniStringW || is_win2k_and_lower){ + win_skip("SHGetIniStringW is not available\n"); + return; + } + + write_inifile(TestIniW); + + if(0){ + /* these crash on Windows */ + pSHGetIniStringW(NULL, NULL, NULL, 0, NULL); + pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW); + pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW); + } + + ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW); + ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret); + + /* valid arguments */ + ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW); + ok(broken(ret == 0) || /* win 98 */ + ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret); + ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n", + wine_dbgstr_w(AKeyW), wine_dbgstr_w(out)); + + ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW); + ok(broken(ret == 0) || /* win 98 */ + ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret); + ok(broken(*out == 0) || /*win 98 */ + !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out)); + + ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW); + ok(broken(ret == 0) || /* win 98 */ + ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret); + ok(broken(*out == 0) || /* win 98 */ + !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out)); + + ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW); + ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret); + ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out)); + + DeleteFileW(TestIniW); +} + +static void test_SHSetIniString(void) +{ + BOOL ret; + + static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0}; + static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0}; + static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0}; + static const WCHAR AKeyW[] = {'A','K','e','y',0}; + static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0}; + static const WCHAR AValueW[] = {'A','V','a','l','u','e',0}; + + if(!pSHSetIniStringW || is_win2k_and_lower){ + win_skip("SHSetIniStringW is not available\n"); + return; + } + + write_inifile(TestIniW); + + ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW); + ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); + todo_wine /* wine sticks an extra \r\n at the end of the file */ + verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n"); + + ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW); + ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); + verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n"); + + ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW); + ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); + verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n"); + + ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW); + ok(ret == TRUE, "SHSetIniStringW should not have failed\n"); + verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n"); + + DeleteFileW(TestIniW); +} + +enum _shellkey_flags { + SHKEY_Root_HKCU = 0x1, + SHKEY_Root_HKLM = 0x2, + SHKEY_Key_Explorer = 0x00, + SHKEY_Key_Shell = 0x10, + SHKEY_Key_ShellNoRoam = 0x20, + SHKEY_Key_Classes = 0x30, + SHKEY_Subkey_Default = 0x0000, + SHKEY_Subkey_ResourceName = 0x1000, + SHKEY_Subkey_Handlers = 0x2000, + SHKEY_Subkey_Associations = 0x3000, + SHKEY_Subkey_Volatile = 0x4000, + SHKEY_Subkey_MUICache = 0x5000, + SHKEY_Subkey_FileExts = 0x6000 +}; + +static void test_SHGetShellKey(void) +{ + static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 }; + static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 }; + + void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW"); + DWORD *alloc_data, data, size; + HKEY hkey; + HRESULT hres; + + if (!pSHGetShellKey) + { + win_skip("SHGetShellKey(ordinal 491) isn't available\n"); + return; + } + + /* some win2k */ + if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey) + { + win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n"); + return; + } + + if (is_win9x || is_win2k_and_lower) + { + win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n"); + return; + } + + /* Vista+ limits SHKEY enumeration values */ + SetLastError(0xdeadbeef); + hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE); + if (hkey) + { + /* Tests not working on Vista+ */ + RegCloseKey(hkey); + + hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE); + ok(hkey != NULL, "hkey = NULL\n"); + RegCloseKey(hkey); + } + + hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE); + ok(hkey != NULL, "hkey = NULL\n"); + RegCloseKey(hkey); + + hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE); + ok(hkey != NULL, "hkey = NULL\n"); + RegCloseKey(hkey); + + hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE); + ok(hkey == NULL, "hkey != NULL\n"); + + hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE); + ok(hkey != NULL, "Can't open key\n"); + ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n"); + RegCloseKey(hkey); + + hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE); + if (!hkey && GetLastError() == ERROR_ACCESS_DENIED) + { + skip("Not authorized to create keys\n"); + return; + } + ok(hkey != NULL, "Can't create key\n"); + RegCloseKey(hkey); + + if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW) + { + win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n"); + return; + } + + size = sizeof(data); + hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size); + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres); + + data = 1234; + hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD)); + ok(hres == S_OK, "hres = %x\n", hres); + + size = 1; + hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size); + ok(hres == S_OK, "hres = %x\n", hres); + ok(size == sizeof(DWORD), "size = %d\n", size); + + data = 0xdeadbeef; + hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size); + ok(hres == S_OK, "hres = %x\n", hres); + ok(size == sizeof(DWORD), "size = %d\n", size); + ok(data == 1234, "data = %d\n", data); + + hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size); + ok(hres == S_OK, "hres= %x\n", hres); + ok(size == sizeof(DWORD), "size = %d\n", size); + if (SUCCEEDED(hres)) + { + ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data); + LocalFree(alloc_data); + } + + hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL); + ok(hres == S_OK, "hres = %x\n", hres); + + hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL); + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres); + + hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size); + ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres); + + hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE); + ok(hkey != NULL, "Can't create key\n"); + ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n"); + RegCloseKey(hkey); +} + static void init_pointers(void) { #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord))) @@ -2378,6 +2925,7 @@ static void init_pointers(void) MAKEFUNC(SHFreeShared, 10); MAKEFUNC(GetAcceptLanguagesA, 14); MAKEFUNC(SHSetWindowBits, 165); + MAKEFUNC(SHSetParentHwnd, 167); MAKEFUNC(ConnectToConnectionPoint, 168); MAKEFUNC(SHSearchMapInt, 198); MAKEFUNC(SHCreateWorkerWindowA, 257); @@ -2385,25 +2933,125 @@ static void init_pointers(void) MAKEFUNC(SHPackDispParams, 282); MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283); MAKEFUNC(IConnectionPoint_SimpleInvoke, 284); + MAKEFUNC(SHGetIniStringW, 294); + MAKEFUNC(SHSetIniStringW, 295); MAKEFUNC(SHFormatDateTimeA, 353); MAKEFUNC(SHFormatDateTimeW, 354); + MAKEFUNC(SHIShellFolder_EnumObjects, 404); MAKEFUNC(SHGetObjectCompatFlags, 476); MAKEFUNC(IUnknown_QueryServiceExec, 484); + MAKEFUNC(SHGetShellKey, 491); MAKEFUNC(SHPropertyBag_ReadLONG, 496); MAKEFUNC(IUnknown_ProfferService, 514); + MAKEFUNC(SKGetValueW, 516); + MAKEFUNC(SKSetValueW, 517); + MAKEFUNC(SKDeleteValueW, 518); + MAKEFUNC(SKAllocValueW, 519); #undef MAKEFUNC } +static void test_SHSetParentHwnd(void) +{ + HWND hwnd, hwnd2, ret; + DWORD style; + + if (!pSHSetParentHwnd) + { + win_skip("SHSetParentHwnd not available\n"); + return; + } + + hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "got %p\n", hwnd); + + hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL); + ok(hwnd2 != NULL, "got %p\n", hwnd2); + + /* null params */ + ret = pSHSetParentHwnd(NULL, NULL); + ok(ret == NULL, "got %p\n", ret); + + /* set to no parent while already no parent present */ + ret = GetParent(hwnd); + ok(ret == NULL, "got %p\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style); + ret = pSHSetParentHwnd(hwnd, NULL); + ok(ret == NULL, "got %p\n", ret); + style = GetWindowLongA(hwnd, GWL_STYLE); + ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style); + + /* reset to null parent from not null */ + ret = GetParent(hwnd2); + ok(ret == hwnd, "got %p\n", ret); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style); + ret = pSHSetParentHwnd(hwnd2, NULL); + ok(ret == NULL, "got %p\n", ret); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style); + ret = GetParent(hwnd2); + ok(ret == NULL, "got %p\n", ret); + + /* set parent back */ + style = GetWindowLongA(hwnd2, GWL_STYLE); + SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP)); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style); + + ret = pSHSetParentHwnd(hwnd2, hwnd); + todo_wine ok(ret == NULL, "got %p\n", ret); + + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style); + ret = GetParent(hwnd2); + ok(ret == hwnd, "got %p\n", ret); + + /* try to set same parent again */ + /* with WS_POPUP */ + style = GetWindowLongA(hwnd2, GWL_STYLE); + SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP); + ret = pSHSetParentHwnd(hwnd2, hwnd); + todo_wine ok(ret == NULL, "got %p\n", ret); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style); + ret = GetParent(hwnd2); + ok(ret == hwnd, "got %p\n", ret); + + /* without WS_POPUP */ + style = GetWindowLongA(hwnd2, GWL_STYLE); + SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP); + ret = pSHSetParentHwnd(hwnd2, hwnd); + todo_wine ok(ret == hwnd, "got %p\n", ret); + style = GetWindowLongA(hwnd2, GWL_STYLE); + ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style); + ret = GetParent(hwnd2); + ok(ret == hwnd, "got %p\n", ret); + + DestroyWindow(hwnd); + DestroyWindow(hwnd2); +} + START_TEST(ordinal) { hShlwapi = GetModuleHandleA("shlwapi.dll"); is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0; + is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */ + + /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */ + if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){ + win_skip("Too old shlwapi version\n"); + return; + } init_pointers(); hmlang = LoadLibraryA("mlang.dll"); pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A"); + hshell32 = LoadLibraryA("shell32.dll"); + pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder"); + test_GetAcceptLanguagesA(); test_SHSearchMapInt(); test_alloc_shared(); @@ -2419,4 +3067,12 @@ START_TEST(ordinal) test_IUnknown_QueryServiceExec(); test_IUnknown_ProfferService(); test_SHCreateWorkerWindowA(); + test_SHIShellFolder_EnumObjects(); + test_SHGetIniString(); + test_SHSetIniString(); + test_SHGetShellKey(); + test_SHSetParentHwnd(); + + FreeLibrary(hshell32); + FreeLibrary(hmlang); } diff --git a/rostests/winetests/shlwapi/path.c b/rostests/winetests/shlwapi/path.c index 3e83a4556c6..d459570a982 100755 --- a/rostests/winetests/shlwapi/path.c +++ b/rostests/winetests/shlwapi/path.c @@ -17,7 +17,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include #include #include @@ -37,7 +36,7 @@ static BOOL (WINAPI *pPathAppendA)(LPSTR, LPCSTR); /* ################ */ -struct { +static const struct { const char *url; const char *path; DWORD ret; @@ -106,7 +105,7 @@ static struct { {NULL, FALSE} }; -struct { +static const struct { const char *path; const char *result; } TEST_PATH_UNQUOTE_SPACES[] = { @@ -1362,6 +1361,12 @@ START_TEST(path) { HMODULE hShlwapi = GetModuleHandleA("shlwapi.dll"); + /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */ + if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){ + win_skip("Too old shlwapi version\n"); + return; + } + pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA"); pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW"); pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW"); diff --git a/rostests/winetests/shlwapi/shreg.c b/rostests/winetests/shlwapi/shreg.c index 5fb3dacf14f..3634041c01e 100755 --- a/rostests/winetests/shlwapi/shreg.c +++ b/rostests/winetests/shlwapi/shreg.c @@ -17,7 +17,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include #include #include @@ -34,12 +33,11 @@ #define REG_CURRENT_VERSION "Software\\Microsoft\\Windows\\CurrentVersion\\explorer" static HMODULE hshlwapi; -typedef DWORD (WINAPI *SHCopyKeyA_func)(HKEY,LPCSTR,HKEY,DWORD); -static SHCopyKeyA_func pSHCopyKeyA; -typedef DWORD (WINAPI *SHRegGetPathA_func)(HKEY,LPCSTR,LPCSTR,LPSTR,DWORD); -static SHRegGetPathA_func pSHRegGetPathA; -typedef LSTATUS (WINAPI *SHRegGetValueA_func)(HKEY,LPCSTR,LPCSTR,SRRF,LPDWORD,LPVOID,LPDWORD); -static SHRegGetValueA_func pSHRegGetValueA; + +static DWORD (WINAPI *pSHCopyKeyA)(HKEY,LPCSTR,HKEY,DWORD); +static DWORD (WINAPI *pSHRegGetPathA)(HKEY,LPCSTR,LPCSTR,LPSTR,DWORD); +static LSTATUS (WINAPI *pSHRegGetValueA)(HKEY,LPCSTR,LPCSTR,SRRF,LPDWORD,LPVOID,LPDWORD); +static LSTATUS (WINAPI *pSHRegCreateUSKeyW)(LPCWSTR,REGSAM,HUSKEY,PHUSKEY,DWORD); static char sTestpath1[] = "%LONGSYSTEMVAR%\\subdir1"; static char sTestpath2[] = "%FOO%\\subdir1"; @@ -192,7 +190,7 @@ static void test_SHGetRegPath(void) ok( 0 == strcmp(sExpTestpath1, buf) , "Comparing (%s) with (%s) failed\n", buf, sExpTestpath1); } -static void test_SHQUeryValueEx(void) +static void test_SHQueryValueEx(void) { HKEY hKey; DWORD dwSize; @@ -445,21 +443,47 @@ static void test_SHDeleteKey(void) ok( 0, "Could not set up SHDeleteKey test\n"); } +static void test_SHRegCreateUSKeyW(void) +{ + static const WCHAR subkeyW[] = {'s','u','b','k','e','y',0}; + LONG ret; + + if (!pSHRegCreateUSKeyW) + { + win_skip("SHRegCreateUSKeyW not available\n"); + return; + } + + ret = pSHRegCreateUSKeyW(subkeyW, KEY_ALL_ACCESS, NULL, NULL, SHREGSET_FORCE_HKCU); + ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret); +} + START_TEST(shreg) { - HKEY hkey = create_test_entries(); - - if (!hkey) return; - - hshlwapi = GetModuleHandleA("shlwapi.dll"); - pSHCopyKeyA=(SHCopyKeyA_func)GetProcAddress(hshlwapi,"SHCopyKeyA"); - pSHRegGetPathA=(SHRegGetPathA_func)GetProcAddress(hshlwapi,"SHRegGetPathA"); - pSHRegGetValueA=(SHRegGetValueA_func)GetProcAddress(hshlwapi,"SHRegGetValueA"); - test_SHGetValue(); - test_SHRegGetValue(); - test_SHQUeryValueEx(); - test_SHGetRegPath(); - test_SHCopyKey(); - test_SHDeleteKey(); - delete_key( hkey, "Software\\Wine", "Test" ); + HKEY hkey = create_test_entries(); + + if (!hkey) return; + + hshlwapi = GetModuleHandleA("shlwapi.dll"); + + /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */ + if(!GetProcAddress(hshlwapi, "SHCreateStreamOnFileEx")){ + win_skip("Too old shlwapi version\n"); + return; + } + + pSHCopyKeyA = (void*)GetProcAddress(hshlwapi,"SHCopyKeyA"); + pSHRegGetPathA = (void*)GetProcAddress(hshlwapi,"SHRegGetPathA"); + pSHRegGetValueA = (void*)GetProcAddress(hshlwapi,"SHRegGetValueA"); + pSHRegCreateUSKeyW = (void*)GetProcAddress(hshlwapi, "SHRegCreateUSKeyW"); + + test_SHGetValue(); + test_SHRegGetValue(); + test_SHQueryValueEx(); + test_SHGetRegPath(); + test_SHCopyKey(); + test_SHDeleteKey(); + test_SHRegCreateUSKeyW(); + + delete_key( hkey, "Software\\Wine", "Test" ); } diff --git a/rostests/winetests/shlwapi/string.c b/rostests/winetests/shlwapi/string.c index 17c652de411..aac79f83bd1 100755 --- a/rostests/winetests/shlwapi/string.c +++ b/rostests/winetests/shlwapi/string.c @@ -55,12 +55,18 @@ static LPSTR (WINAPI *pStrFormatKBSizeA)(LONGLONG,LPSTR,UINT); static LPWSTR (WINAPI *pStrFormatKBSizeW)(LONGLONG,LPWSTR,UINT); static BOOL (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int); static BOOL (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int); -static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,void*,BSTR*); +static LPWSTR (WINAPI *pStrPBrkW)(LPCWSTR,LPCWSTR); +static LPSTR (WINAPI *pStrRChrA)(LPCSTR,LPCSTR,WORD); +static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,LPCITEMIDLIST,BSTR*); static HRESULT (WINAPI *pStrRetToBufA)(STRRET*,LPCITEMIDLIST,LPSTR,UINT); static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT); +static LPWSTR (WINAPI *pStrStrNW)(LPCWSTR,LPCWSTR,UINT); +static LPWSTR (WINAPI *pStrStrNIW)(LPCWSTR,LPCWSTR,UINT); static INT (WINAPIV *pwnsprintfA)(LPSTR,INT,LPCSTR, ...); static INT (WINAPIV *pwnsprintfW)(LPWSTR,INT,LPCWSTR, ...); static LPWSTR (WINAPI *pStrChrNW)(LPWSTR,WCHAR,UINT); +static BOOL (WINAPI *pStrToInt64ExA)(LPCSTR,DWORD,LONGLONG*); +static BOOL (WINAPI *pStrToInt64ExW)(LPCWSTR,DWORD,LONGLONG*); static int strcmpW(const WCHAR *str1, const WCHAR *str2) { @@ -73,17 +79,19 @@ typedef struct tagStrToIntResult { const char* string; int str_to_int; - int str_to_int_ex; - int str_to_int_hex; + LONGLONG str_to_int64_ex; + LONGLONG str_to_int64_hex; } StrToIntResult; static const StrToIntResult StrToInt_results[] = { { "1099", 1099, 1099, 1099 }, + { "4294967319", 23, ((LONGLONG)1 << 32) | 23, ((LONGLONG)1 << 32) | 23 }, { "+88987", 0, 88987, 88987 }, { "012", 12, 12, 12 }, { "-55", -55, -55, -55 }, { "-0", 0, 0, 0 }, { "0x44ff", 0, 0, 0x44ff }, + { "0x2bdc546291f4b1", 0, 0, ((LONGLONG)0x2bdc54 << 32) | 0x6291f4b1 }, { "+0x44f4", 0, 0, 0x44f4 }, { "-0x44fd", 0, 0, 0x44fd }, { "+ 88987", 0, 0, 0 }, @@ -107,6 +115,8 @@ typedef struct tagStrFormatSizeResult LONGLONG value; const char* byte_size_64; const char* kb_size; + int kb_size_broken; + const char* kb_size2; } StrFormatSizeResult; @@ -117,19 +127,19 @@ static const StrFormatSizeResult StrFormatSize_results[] = { { 10191, "9.95 KB", "10 KB"}, { 100353, "98.0 KB", "99 KB"}, { 1022286, "998 KB", "999 KB"}, - { 1046862, "0.99 MB", "1,023 KB"}, - { 1048574619, "999 MB", "1,023,999 KB"}, - { 1073741775, "0.99 GB", "1,048,576 KB"}, - { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB"}, - { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB"}, - { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB"}, - { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB"}, - { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB"}, - { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB"}, + { 1046862, "0.99 MB", "1,023 KB", 1, "1023 KB"}, + { 1048574619, "999 MB", "1,023,999 KB", 1, "1023999 KB"}, + { 1073741775, "0.99 GB", "1,048,576 KB", 1, "1048576 KB"}, + { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB", 1, "1048575999 KB"}, + { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB", 1, "1073741823 KB"}, + { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB", 1, "4294967295 KB"}, + { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB", 1, "4294967295 KB"}, + { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB", 1, "0 KB"}, + { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB", 1, "4294967295 KB"}, { 0, NULL, NULL } }; -/* StrFormatByteSize64/StrFormatKBSize results */ +/* StrFromTimeIntervalA/StrFromTimeIntervalW results */ typedef struct tagStrFromTimeIntervalResult { DWORD ms; @@ -191,6 +201,39 @@ static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = { { 0, 0, NULL } }; + +/* Returns true if the user interface is in English. Note that this does not + * presume of the formatting of dates, numbers, etc. + */ +static BOOL is_lang_english(void) +{ + static HMODULE hkernel32 = NULL; + static LANGID (WINAPI *pGetThreadUILanguage)(void) = NULL; + static LANGID (WINAPI *pGetUserDefaultUILanguage)(void) = NULL; + + if (!hkernel32) + { + hkernel32 = GetModuleHandleA("kernel32.dll"); + pGetThreadUILanguage = (void*)GetProcAddress(hkernel32, "GetThreadUILanguage"); + pGetUserDefaultUILanguage = (void*)GetProcAddress(hkernel32, "GetUserDefaultUILanguage"); + } + if (pGetThreadUILanguage) + return PRIMARYLANGID(pGetThreadUILanguage()) == LANG_ENGLISH; + if (pGetUserDefaultUILanguage) + return PRIMARYLANGID(pGetUserDefaultUILanguage()) == LANG_ENGLISH; + + return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH; +} + +/* Returns true if the dates, numbers, etc. are formatted using English + * conventions. + */ +static BOOL is_locale_english(void) +{ + /* Surprisingly GetThreadLocale() is irrelevant here */ + return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH; +} + static void test_StrChrA(void) { char string[129]; @@ -364,16 +407,28 @@ static void test_StrCpyW(void) WCHAR szSrc[256]; WCHAR szBuff[256]; const StrFormatSizeResult* result = StrFormatSize_results; - + LPWSTR lpRes; while(result->value) { MultiByteToWideChar(0,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR)); - StrCpyW(szBuff, szSrc); - ok(!StrCmpW(szSrc, szBuff), "Copied string %s wrong\n", result->byte_size_64); + lpRes = StrCpyW(szBuff, szSrc); + ok(!StrCmpW(szSrc, szBuff) && lpRes == szBuff, "Copied string %s wrong\n", result->byte_size_64); result++; } + + /* this test crashes on win2k SP4 */ + /*lpRes = StrCpyW(szBuff, NULL);*/ + /*ok(lpRes == szBuff, "Wrong return value: got %p expected %p\n", lpRes, szBuff);*/ + + /* this test crashes on win2k SP4 */ + /*lpRes = StrCpyW(NULL, szSrc);*/ + /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/ + + /* this test crashes on win2k SP4 */ + /*lpRes = StrCpyW(NULL, NULL);*/ + /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/ } static void test_StrChrNW(void) @@ -441,7 +496,7 @@ static void test_StrToIntExA(void) ok(!bRet || return_val != -1, "No result returned from '%s'\n", result->string); if (bRet) - ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n", + ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n", result->string, return_val); result++; } @@ -454,7 +509,7 @@ static void test_StrToIntExA(void) ok(!bRet || return_val != -1, "No result returned from '%s'\n", result->string); if (bRet) - ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n", + ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n", result->string, return_val); result++; } @@ -475,7 +530,7 @@ static void test_StrToIntExW(void) ok(!bRet || return_val != -1, "No result returned from '%s'\n", result->string); if (bRet) - ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n", + ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n", result->string, return_val); result++; } @@ -489,12 +544,91 @@ static void test_StrToIntExW(void) ok(!bRet || return_val != -1, "No result returned from '%s'\n", result->string); if (bRet) - ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n", + ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n", result->string, return_val); result++; } } +static void test_StrToInt64ExA(void) +{ + const StrToIntResult *result = StrToInt_results; + LONGLONG return_val; + BOOL bRet; + + if (!pStrToInt64ExA) + { + win_skip("StrToInt64ExA() is not available\n"); + return; + } + + while (result->string) + { + return_val = -1; + bRet = pStrToInt64ExA(result->string,0,&return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int64_ex, "converted '%s' wrong (%08x%08x)\n", + result->string, (DWORD)(return_val >> 32), (DWORD)return_val); + result++; + } + + result = StrToInt_results; + while (result->string) + { + return_val = -1; + bRet = pStrToInt64ExA(result->string,STIF_SUPPORT_HEX,&return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int64_hex, "converted '%s' wrong (%08x%08x)\n", + result->string, (DWORD)(return_val >> 32), (DWORD)return_val); + result++; + } +} + +static void test_StrToInt64ExW(void) +{ + WCHAR szBuff[256]; + const StrToIntResult *result = StrToInt_results; + LONGLONG return_val; + BOOL bRet; + + if (!pStrToInt64ExW) + { + win_skip("StrToInt64ExW() is not available\n"); + return; + } + + while (result->string) + { + return_val = -1; + MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR)); + bRet = pStrToInt64ExW(szBuff, 0, &return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int64_ex, "converted '%s' wrong (%08x%08x)\n", + result->string, (DWORD)(return_val >> 32), (DWORD)return_val); + result++; + } + + result = StrToInt_results; + while (result->string) + { + return_val = -1; + MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR)); + bRet = pStrToInt64ExW(szBuff, STIF_SUPPORT_HEX, &return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int64_hex, "converted '%s' wrong (%08x%08x)\n", + result->string, (DWORD)(return_val >> 32), (DWORD)return_val); + result++; + } +} + static void test_StrDupA(void) { LPSTR lpszStr; @@ -560,8 +694,8 @@ static void test_StrFormatKBSizeW(void) { pStrFormatKBSizeW(result->value, szBuffW, 256); WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0); - ok(!strcmp(result->kb_size, szBuff), - "Formatted %x%08x wrong: got %s, expected %s\n", + + ok(!strcmp(result->kb_size, szBuff), "Formatted %x%08x wrong: got %s, expected %s\n", (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size); result++; } @@ -582,7 +716,10 @@ static void test_StrFormatKBSizeA(void) { pStrFormatKBSizeA(result->value, szBuff, 256); - ok(!strcmp(result->kb_size, szBuff), + /* shlwapi on Win98 SE does not appear to apply delimiters to the output + * and does not correctly handle extremely large values. */ + ok(!strcmp(result->kb_size, szBuff) || + (result->kb_size_broken && !strcmp(result->kb_size2, szBuff)), "Formatted %x%08x wrong: got %s, expected %s\n", (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size); result++; @@ -598,8 +735,8 @@ static void test_StrFromTimeIntervalA(void) { StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits); - ok(!strcmp(result->time_interval, szBuff), "Formatted %d %d wrong\n", - result->ms, result->digits); + ok(!strcmp(result->time_interval, szBuff), "Formatted %d %d wrong: %s\n", + result->ms, result->digits, szBuff); result++; } } @@ -772,7 +909,7 @@ static void test_StrRStrI(void) static const WCHAR wszPattern4[] = {'a','b',0}; LPWSTR retW; LPSTR retA; - + check_strrstri(A, szTest, 4, "A", szTest+1); check_strrstri(A, szTest, 4, "aX", szTest+1); check_strrstri(A, szTest, 4, "Ay", NULL); @@ -804,6 +941,12 @@ static void test_SHAnsiToAnsi(void) return; } + if (pSHAnsiToAnsi == (void *)pStrPBrkW) + { + win_skip("Ordinal 345 corresponds to StrPBrkW, skipping SHAnsiToAnsi tests\n"); + return; + } + memset(dest, '\n', sizeof(dest)); dwRet = pSHAnsiToAnsi("hello", dest, sizeof(dest)/sizeof(dest[0])); ok(dwRet == 6 && !memcmp(dest, "hello\0\n\n", sizeof(dest)), @@ -825,6 +968,12 @@ static void test_SHUnicodeToUnicode(void) return; } + if (pSHUnicodeToUnicode == (void *)pStrRChrA) + { + win_skip("Ordinal 346 corresponds to StrRChrA, skipping SHUnicodeToUnicode tests\n"); + return; + } + memcpy(dest, lpInit, sizeof(lpInit)); dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0])); ok(dwRet == 6 && !memcmp(dest, lpRes, sizeof(dest)), @@ -932,7 +1081,7 @@ if (0) { memset(buf, 0xbf, sizeof(buf)); ret = pwnsprintfA(buf, 10, "%s", str1); - ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wsnprintfA return %d, expected 9 or -1\n", ret); + ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfA return %d, expected 9 or -1\n", ret); expect_eq(buf[9], 0, CHAR, "%x"); expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x"); } @@ -943,7 +1092,7 @@ if (0) { memset(wbuf, 0xbf, sizeof(wbuf)); ret = pwnsprintfW(wbuf, 10, fmt, wstr1); - ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wsnprintfW return %d, expected 9 or -1\n", ret); + ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfW return %d, expected 9 or -1\n", ret); expect_eq(wbuf[9], 0, WCHAR, "%x"); expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x"); } @@ -951,6 +1100,387 @@ if (0) win_skip("wnsprintfW() is not available\n"); } +static void test_StrStrA(void) +{ + static const char *deadbeefA = "DeAdBeEf"; + + const struct + { + const char *search; + const char *expect; + } StrStrA_cases[] = + { + {"", NULL}, + {"DeAd", deadbeefA}, + {"dead", NULL}, + {"AdBe", deadbeefA + 2}, + {"adbe", NULL}, + {"BeEf", deadbeefA + 4}, + {"beef", NULL}, + }; + + LPSTR ret; + int i; + + /* Tests crash on Win2k */ + if (0) + { + ret = StrStrA(NULL, NULL); + ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret); + + ret = StrStrA(NULL, ""); + ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret); + + ret = StrStrA("", NULL); + ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret); + } + + ret = StrStrA("", ""); + ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret); + + for (i = 0; i < sizeof(StrStrA_cases)/sizeof(StrStrA_cases[0]); i++) + { + ret = StrStrA(deadbeefA, StrStrA_cases[i].search); + ok(ret == StrStrA_cases[i].expect, + "[%d] Expected StrStrA to return %p, got %p\n", + i, StrStrA_cases[i].expect, ret); + } +} + +static void test_StrStrW(void) +{ + static const WCHAR emptyW[] = {0}; + static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0}; + static const WCHAR deadW[] = {'D','e','A','d',0}; + static const WCHAR dead_lowerW[] = {'d','e','a','d',0}; + static const WCHAR adbeW[] = {'A','d','B','e',0}; + static const WCHAR adbe_lowerW[] = {'a','d','b','e',0}; + static const WCHAR beefW[] = {'B','e','E','f',0}; + static const WCHAR beef_lowerW[] = {'b','e','e','f',0}; + + const struct + { + const WCHAR *search; + const WCHAR *expect; + } StrStrW_cases[] = + { + {emptyW, NULL}, + {deadW, deadbeefW}, + {dead_lowerW, NULL}, + {adbeW, deadbeefW + 2}, + {adbe_lowerW, NULL}, + {beefW, deadbeefW + 4}, + {beef_lowerW, NULL}, + }; + + LPWSTR ret; + int i; + + /* Tests crash on Win2k */ + if (0) + { + ret = StrStrW(NULL, NULL); + ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret); + + ret = StrStrW(NULL, emptyW); + ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret); + + ret = StrStrW(emptyW, NULL); + ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret); + } + + ret = StrStrW(emptyW, emptyW); + ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret); + + for (i = 0; i < sizeof(StrStrW_cases)/sizeof(StrStrW_cases[0]); i++) + { + ret = StrStrW(deadbeefW, StrStrW_cases[i].search); + ok(ret == StrStrW_cases[i].expect, + "[%d] Expected StrStrW to return %p, got %p\n", + i, StrStrW_cases[i].expect, ret); + } +} + +static void test_StrStrIA(void) +{ + static const char *deadbeefA = "DeAdBeEf"; + + const struct + { + const char *search; + const char *expect; + } StrStrIA_cases[] = + { + {"", NULL}, + {"DeAd", deadbeefA}, + {"dead", deadbeefA}, + {"AdBe", deadbeefA + 2}, + {"adbe", deadbeefA + 2}, + {"BeEf", deadbeefA + 4}, + {"beef", deadbeefA + 4}, + {"cafe", NULL}, + }; + + LPSTR ret; + int i; + + /* Tests crash on Win2k */ + if (0) + { + ret = StrStrIA(NULL, NULL); + ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret); + + ret = StrStrIA(NULL, ""); + ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret); + + ret = StrStrIA("", NULL); + ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret); + } + + ret = StrStrIA("", ""); + ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret); + + for (i = 0; i < sizeof(StrStrIA_cases)/sizeof(StrStrIA_cases[0]); i++) + { + ret = StrStrIA(deadbeefA, StrStrIA_cases[i].search); + ok(ret == StrStrIA_cases[i].expect, + "[%d] Expected StrStrIA to return %p, got %p\n", + i, StrStrIA_cases[i].expect, ret); + } +} + +static void test_StrStrIW(void) +{ + static const WCHAR emptyW[] = {0}; + static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0}; + static const WCHAR deadW[] = {'D','e','A','d',0}; + static const WCHAR dead_lowerW[] = {'d','e','a','d',0}; + static const WCHAR adbeW[] = {'A','d','B','e',0}; + static const WCHAR adbe_lowerW[] = {'a','d','b','e',0}; + static const WCHAR beefW[] = {'B','e','E','f',0}; + static const WCHAR beef_lowerW[] = {'b','e','e','f',0}; + static const WCHAR cafeW[] = {'c','a','f','e',0}; + + const struct + { + const WCHAR *search; + const WCHAR *expect; + } StrStrIW_cases[] = + { + {emptyW, NULL}, + {deadW, deadbeefW}, + {dead_lowerW, deadbeefW}, + {adbeW, deadbeefW + 2}, + {adbe_lowerW, deadbeefW + 2}, + {beefW, deadbeefW + 4}, + {beef_lowerW, deadbeefW + 4}, + {cafeW, NULL}, + }; + + LPWSTR ret; + int i; + + /* Tests crash on Win2k */ + if (0) + { + ret = StrStrIW(NULL, NULL); + ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret); + + ret = StrStrIW(NULL, emptyW); + ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret); + + ret = StrStrIW(emptyW, NULL); + ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret); + } + + ret = StrStrIW(emptyW, emptyW); + ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret); + + for (i = 0; i < sizeof(StrStrIW_cases)/sizeof(StrStrIW_cases[0]); i++) + { + ret = StrStrIW(deadbeefW, StrStrIW_cases[i].search); + ok(ret == StrStrIW_cases[i].expect, + "[%d] Expected StrStrIW to return %p, got %p\n", + i, StrStrIW_cases[i].expect, ret); + } +} + +static void test_StrStrNW(void) +{ + static const WCHAR emptyW[] = {0}; + static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0}; + static const WCHAR deadW[] = {'D','e','A','d',0}; + static const WCHAR dead_lowerW[] = {'d','e','a','d',0}; + static const WCHAR adbeW[] = {'A','d','B','e',0}; + static const WCHAR adbe_lowerW[] = {'a','d','b','e',0}; + static const WCHAR beefW[] = {'B','e','E','f',0}; + static const WCHAR beef_lowerW[] = {'b','e','e','f',0}; + + const struct + { + const WCHAR *search; + const UINT count; + const WCHAR *expect; + } StrStrNW_cases[] = + { + {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL}, + {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW}, + {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL}, + {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2}, + {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL}, + {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4}, + {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL}, + {beefW, 0, NULL}, + {beefW, 1, NULL}, + {beefW, 2, NULL}, + {beefW, 3, NULL}, + {beefW, 4, NULL}, + {beefW, 5, deadbeefW + 4}, + {beefW, 6, deadbeefW + 4}, + {beefW, 7, deadbeefW + 4}, + {beefW, 8, deadbeefW + 4}, + {beefW, 9, deadbeefW + 4}, + }; + + LPWSTR ret; + UINT i; + + if (!pStrStrNW) + { + win_skip("StrStrNW() is not available\n"); + return; + } + + ret = pStrStrNW(NULL, NULL, 0); + ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret); + + ret = pStrStrNW(NULL, NULL, 10); + ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret); + + ret = pStrStrNW(NULL, emptyW, 10); + ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret); + + ret = pStrStrNW(emptyW, NULL, 10); + ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret); + + ret = pStrStrNW(emptyW, emptyW, 10); + ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret); + + for (i = 0; i < sizeof(StrStrNW_cases)/sizeof(StrStrNW_cases[0]); i++) + { + ret = pStrStrNW(deadbeefW, StrStrNW_cases[i].search, StrStrNW_cases[i].count); + ok(ret == StrStrNW_cases[i].expect, + "[%d] Expected StrStrNW to return %p, got %p\n", + i, StrStrNW_cases[i].expect, ret); + } + + /* StrStrNW accepts counts larger than the search string length but rejects + * counts larger than around 2G. The limit seems to change based on the + * caller executable itself. */ + ret = pStrStrNW(deadbeefW, beefW, 100); + ok(ret == deadbeefW + 4, "Expected StrStrNW to return deadbeefW + 4, got %p\n", ret); + + if (0) + { + ret = pStrStrNW(deadbeefW, beefW, ~0U); + ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret); + } +} + +static void test_StrStrNIW(void) +{ + static const WCHAR emptyW[] = {0}; + static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0}; + static const WCHAR deadW[] = {'D','e','A','d',0}; + static const WCHAR dead_lowerW[] = {'d','e','a','d',0}; + static const WCHAR adbeW[] = {'A','d','B','e',0}; + static const WCHAR adbe_lowerW[] = {'a','d','b','e',0}; + static const WCHAR beefW[] = {'B','e','E','f',0}; + static const WCHAR beef_lowerW[] = {'b','e','e','f',0}; + static const WCHAR cafeW[] = {'c','a','f','e',0}; + + const struct + { + const WCHAR *search; + const UINT count; + const WCHAR *expect; + } StrStrNIW_cases[] = + { + {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL}, + {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW}, + {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW}, + {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2}, + {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2}, + {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4}, + {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4}, + {cafeW, sizeof(deadbeefW)/sizeof(WCHAR), NULL}, + {beefW, 0, NULL}, + {beefW, 1, NULL}, + {beefW, 2, NULL}, + {beefW, 3, NULL}, + {beefW, 4, NULL}, + {beefW, 5, deadbeefW + 4}, + {beefW, 6, deadbeefW + 4}, + {beefW, 7, deadbeefW + 4}, + {beefW, 8, deadbeefW + 4}, + {beefW, 9, deadbeefW + 4}, + {beef_lowerW, 0, NULL}, + {beef_lowerW, 1, NULL}, + {beef_lowerW, 2, NULL}, + {beef_lowerW, 3, NULL}, + {beef_lowerW, 4, NULL}, + {beef_lowerW, 5, deadbeefW + 4}, + {beef_lowerW, 6, deadbeefW + 4}, + {beef_lowerW, 7, deadbeefW + 4}, + {beef_lowerW, 8, deadbeefW + 4}, + {beef_lowerW, 9, deadbeefW + 4}, + }; + + LPWSTR ret; + UINT i; + + if (!pStrStrNIW) + { + win_skip("StrStrNIW() is not available\n"); + return; + } + + ret = pStrStrNIW(NULL, NULL, 0); + ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret); + + ret = pStrStrNIW(NULL, NULL, 10); + ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret); + + ret = pStrStrNIW(NULL, emptyW, 10); + ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret); + + ret = pStrStrNIW(emptyW, NULL, 10); + ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret); + + ret = pStrStrNIW(emptyW, emptyW, 10); + ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret); + + for (i = 0; i < sizeof(StrStrNIW_cases)/sizeof(StrStrNIW_cases[0]); i++) + { + ret = pStrStrNIW(deadbeefW, StrStrNIW_cases[i].search, StrStrNIW_cases[i].count); + ok(ret == StrStrNIW_cases[i].expect, + "[%d] Expected StrStrNIW to return %p, got %p\n", + i, StrStrNIW_cases[i].expect, ret); + } + + /* StrStrNIW accepts counts larger than the search string length but rejects + * counts larger than around 2G. The limit seems to change based on the + * caller executable itself. */ + ret = pStrStrNIW(deadbeefW, beefW, 100); + ok(ret == deadbeefW + 4, "Expected StrStrNIW to return deadbeefW + 4, got %p\n", ret); + + if (0) + { + ret = pStrStrNIW(deadbeefW, beefW, ~0U); + ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret); + } +} + START_TEST(string) { HMODULE hShlwapi; @@ -978,11 +1508,17 @@ START_TEST(string) pStrFormatKBSizeW = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeW"); pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA"); pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW"); + pStrPBrkW = (void *)GetProcAddress(hShlwapi, "StrPBrkW"); + pStrRChrA = (void *)GetProcAddress(hShlwapi, "StrRChrA"); pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR"); pStrRetToBufA = (void *)GetProcAddress(hShlwapi, "StrRetToBufA"); pStrRetToBufW = (void *)GetProcAddress(hShlwapi, "StrRetToBufW"); + pStrStrNW = (void *)GetProcAddress(hShlwapi, "StrStrNW"); + pStrStrNIW = (void *)GetProcAddress(hShlwapi, "StrStrNIW"); pwnsprintfA = (void *)GetProcAddress(hShlwapi, "wnsprintfA"); pwnsprintfW = (void *)GetProcAddress(hShlwapi, "wnsprintfW"); + pStrToInt64ExA = (void *)GetProcAddress(hShlwapi, "StrToInt64ExA"); + pStrToInt64ExW = (void *)GetProcAddress(hShlwapi, "StrToInt64ExW"); test_StrChrA(); test_StrChrW(); @@ -996,20 +1532,23 @@ START_TEST(string) test_StrToIntW(); test_StrToIntExA(); test_StrToIntExW(); + test_StrToInt64ExA(); + test_StrToInt64ExW(); test_StrDupA(); - if (lstrcmp(thousandDelim, ",")==0 && lstrcmp(decimalDelim, ".")==0) + + /* language-dependent test */ + if (is_lang_english() && is_locale_english()) { - /* these tests are locale-dependent */ test_StrFormatByteSize64A(); test_StrFormatKBSizeA(); test_StrFormatKBSizeW(); } - - /* language-dependent test */ - if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH) - trace("Skipping StrFromTimeInterval test for non English language\n"); else + skip("An English UI and locale is required for the StrFormat*Size tests\n"); + if (is_lang_english()) test_StrFromTimeIntervalA(); + else + skip("An English UI is required for the StrFromTimeInterval tests\n"); test_StrCmpA(); test_StrCmpW(); @@ -1020,6 +1559,12 @@ START_TEST(string) test_SHAnsiToAnsi(); test_SHUnicodeToUnicode(); test_StrXXX_overflows(); + test_StrStrA(); + test_StrStrW(); + test_StrStrIA(); + test_StrStrIW(); + test_StrStrNW(); + test_StrStrNIW(); CoUninitialize(); } diff --git a/rostests/winetests/shlwapi/thread.c b/rostests/winetests/shlwapi/thread.c index 24d5be15802..d4a17872361 100644 --- a/rostests/winetests/shlwapi/thread.c +++ b/rostests/winetests/shlwapi/thread.c @@ -21,6 +21,8 @@ #include #define COBJMACROS +#define CONST_VTABLE + #include "windef.h" #include "winbase.h" #include "winerror.h" @@ -37,13 +39,18 @@ static DWORD AddRef_called; typedef struct { - const IUnknownVtbl* lpVtbl; + IUnknown IUnknown_iface; LONG *ref; } threadref; +static inline threadref *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, threadref, IUnknown_iface); +} + static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj) { - threadref * This = (threadref *)iface; + threadref * This = impl_from_IUnknown(iface); trace("unexpected QueryInterface(%p, %p, %p) called\n", This, riid, ppvObj); *ppvObj = NULL; @@ -52,7 +59,7 @@ static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPV static ULONG WINAPI threadref_AddRef(IUnknown *iface) { - threadref * This = (threadref *)iface; + threadref * This = impl_from_IUnknown(iface); AddRef_called++; return InterlockedIncrement(This->ref); @@ -60,7 +67,7 @@ static ULONG WINAPI threadref_AddRef(IUnknown *iface) static ULONG WINAPI threadref_Release(IUnknown *iface) { - threadref * This = (threadref *)iface; + threadref * This = impl_from_IUnknown(iface); trace("unexpected Release(%p) called\n", This); return InterlockedDecrement(This->ref); @@ -76,7 +83,7 @@ static const IUnknownVtbl threadref_vt = static void init_threadref(threadref* iface, LONG *refcount) { - iface->lpVtbl = &threadref_vt; + iface->IUnknown_iface.lpVtbl = &threadref_vt; iface->ref = refcount; } @@ -184,7 +191,7 @@ static void test_SHGetThreadRef(void) if (0) { /* this crash on Windows */ - hr = pSHGetThreadRef(NULL); + pSHGetThreadRef(NULL); } } @@ -209,7 +216,7 @@ static void test_SHSetThreadRef(void) init_threadref(&ref, &refcount); AddRef_called = 0; refcount = 1; - hr = pSHSetThreadRef( (IUnknown *)&ref); + hr = pSHSetThreadRef(&ref.IUnknown_iface); ok( (hr == S_OK) && (refcount == 1) && (!AddRef_called), "got 0x%x with %d, %d (expected S_OK with 1, 0)\n", hr, refcount, AddRef_called); @@ -219,7 +226,7 @@ static void test_SHSetThreadRef(void) refcount = 1; punk = NULL; hr = pSHGetThreadRef(&punk); - ok( (hr == S_OK) && (punk == (IUnknown *)&ref) && (refcount == 2) && (AddRef_called == 1), + ok( (hr == S_OK) && (punk == &ref.IUnknown_iface) && (refcount == 2) && (AddRef_called == 1), "got 0x%x and %p with %d, %d (expected S_OK and %p with 2, 1)\n", hr, punk, refcount, AddRef_called, &ref); diff --git a/rostests/winetests/shlwapi/url.c b/rostests/winetests/shlwapi/url.c index 8a8f68a8f9e..fbc3601e77f 100644 --- a/rostests/winetests/shlwapi/url.c +++ b/rostests/winetests/shlwapi/url.c @@ -56,6 +56,8 @@ static HRESULT (WINAPI *pHashData)(LPBYTE, DWORD, LPBYTE, DWORD); static const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923"; static const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923"; static const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y"; +static const char* TEST_URL_4 = "http://foo:bar@google.*.com:21/internal.php?query=x&return=y"; + static const WCHAR winehqW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/',0}; static const CHAR winehqA[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/',0}; @@ -83,9 +85,18 @@ static const TEST_URL_APPLY TEST_APPLY[] = { {"winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"}, {"winehq.org", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, {"winehq.org", URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"}, + {"http://www.winehq.org", URL_APPLY_GUESSSCHEME , S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, + {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_FORCEAPPLY, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, + {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_FORCEAPPLY | URL_APPLY_DEFAULT, S_OK, 28, "http://http://www.winehq.org"}, + {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, {"", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 7, "http://"}, {"", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, - {"", URL_APPLY_DEFAULT, S_OK, 7, "http://"} + {"", URL_APPLY_DEFAULT, S_OK, 7, "http://"}, + {"u:\\windows", URL_APPLY_GUESSFILE | URL_APPLY_DEFAULT, S_OK, 18, "file:///u:/windows"}, + {"u:\\windows", URL_APPLY_GUESSFILE, S_OK, 18, "file:///u:/windows"}, + {"u:\\windows", URL_APPLY_DEFAULT, S_OK, 17, "http://u:\\windows"}, + {"file:///c:/windows", URL_APPLY_GUESSFILE , S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, + {"aa:\\windows", URL_APPLY_GUESSFILE , S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA}, }; /* ################ */ @@ -100,6 +111,8 @@ typedef struct _TEST_URL_CANONICALIZE { static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/", TRUE}, + {"http://www.winehq.org/..", 0, S_OK, "http://www.winehq.org/..", FALSE}, + {"http://www.winehq.org/tests/tests2/../../tests", 0, S_OK, "http://www.winehq.org/tests", FALSE}, {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests", FALSE}, {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE}, {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE}, @@ -112,6 +125,7 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/", FALSE}, {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE}, {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE}, + {"\tht\ttp\t://www\t.w\tineh\t\tq.or\tg\t/\ttests/..\t?\tquer\ty=x\t\t&re\tturn=y\t\t", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE}, {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, {"http://www.winehq.org/tests\\../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE}, @@ -120,6 +134,9 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example", FALSE}, {"http://www.winehq.org/tests/foo bar", URL_ESCAPE_SPACES_ONLY| URL_DONT_ESCAPE_EXTRA_INFO , S_OK, "http://www.winehq.org/tests/foo%20bar", FALSE}, {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar", FALSE}, + {"http://www.winehq.org", 0, S_OK, "http://www.winehq.org/", FALSE}, + {"http:///www.winehq.org", 0, S_OK, "http:///www.winehq.org", FALSE}, + {"http:////www.winehq.org", 0, S_OK, "http:////www.winehq.org", FALSE}, {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE}, {"file:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE}, {"file:///c:/tests/foo%20bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE}, @@ -134,6 +151,24 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar", FALSE}, {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar", FALSE}, {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar", FALSE}, + {"file:///c:\\tests\\foobar", 0, S_OK, "file:///c:/tests/foobar", FALSE}, + {"file:///c:\\tests\\foobar", URL_WININET_COMPATIBILITY, S_OK, "file://c:\\tests\\foobar", FALSE}, + {"file://home/user/file", 0, S_OK, "file://home/user/file", FALSE}, + {"file:///home/user/file", 0, S_OK, "file:///home/user/file", FALSE}, + {"file:////home/user/file", 0, S_OK, "file://home/user/file", FALSE}, + {"file://home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\\\home\\user\\file", FALSE}, + {"file:///home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\home\\user\\file", FALSE}, + {"file:////home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\\\home\\user\\file", FALSE}, + {"file://///home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\\\home\\user\\file", FALSE}, + {"file://C:/user/file", 0, S_OK, "file:///C:/user/file", FALSE}, + {"file://C:/user/file/../asdf", 0, S_OK, "file:///C:/user/asdf", FALSE}, + {"file:///C:/user/file", 0, S_OK, "file:///C:/user/file", FALSE}, + {"file:////C:/user/file", 0, S_OK, "file:///C:/user/file", FALSE}, + {"file://C:/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://C:\\user\\file", FALSE}, + {"file:///C:/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://C:\\user\\file", FALSE}, + {"file:////C:/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://C:\\user\\file", FALSE}, + {"http:///www.winehq.org", 0, S_OK, "http:///www.winehq.org", FALSE}, + {"http:///www.winehq.org", URL_WININET_COMPATIBILITY, S_OK, "http:///www.winehq.org", FALSE}, {"http://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/site/about", FALSE}, {"file_://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "file_://www.winehq.org/site/about", FALSE}, {"c:\\dir\\file", 0, S_OK, "file:///c:/dir/file", FALSE}, @@ -141,6 +176,7 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { {"c:dir\\file", 0, S_OK, "file:///c:dir/file", FALSE}, {"c:\\tests\\foo bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE}, {"c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE}, + {"c\t:\t\\te\tsts\\fo\to \tbar\t", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE}, {"res://file", 0, S_OK, "res://file/", FALSE}, {"res://file", URL_FILE_USE_PATHURL, S_OK, "res://file/", FALSE}, {"res:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "res:///c:/tests/foo bar", FALSE}, @@ -158,11 +194,19 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { {"res://c:\\tests/res\\foo%20bar/strange\\sth", URL_FILE_USE_PATHURL, S_OK, "res://c:\\tests/res\\foo%20bar/strange\\sth", FALSE}, {"res://c:\\tests/res\\foo%20bar/strange\\sth", URL_UNESCAPE, S_OK, "res://c:\\tests/res\\foo bar/strange\\sth", FALSE}, {"A", 0, S_OK, "A", FALSE}, + {"../A", 0, S_OK, "../A", FALSE}, + {"A/../B", 0, S_OK, "B", TRUE}, {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/, S_OK, "/uri-res/N2R?urn:sha1:B3K", FALSE} /*LimeWire online installer calls this*/, {"http:www.winehq.org/dir/../index.html", 0, S_OK, "http:www.winehq.org/index.html"}, {"http://localhost/test.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/test.html"}, {"http://localhost/te%20st.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/te%20st.html"}, - {"http://www.winehq.org/%E6%A1%9C.html", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/%E6%A1%9C.html"} + {"http://www.winehq.org/%E6%A1%9C.html", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/%E6%A1%9C.html"}, + {"mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"}, + {"ftp:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "ftp:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"}, + {"file:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "file:@MSITStore:C:/Program Files/AutoCAD 2008/Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"}, + {"http:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "http:@MSITStore:C:/Program Files/AutoCAD 2008/Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"}, + {"http:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", URL_FILE_USE_PATHURL, S_OK, "http:@MSITStore:C:/Program Files/AutoCAD 2008/Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"}, + {"mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", URL_FILE_USE_PATHURL, S_OK, "mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"}, }; /* ################ */ @@ -280,6 +324,9 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = { {"http://www.winehq.org/tests/#example", "tests9", 0, S_OK, "http://www.winehq.org/tests/tests9"}, {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests10/.."}, {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../tests11"}, + {"http://www.winehq.org/test12", "#", 0, S_OK, "http://www.winehq.org/test12#"}, + {"http://www.winehq.org/test13#aaa", "#bbb", 0, S_OK, "http://www.winehq.org/test13#bbb"}, + {"http://www.winehq.org/test14#aaa/bbb#ccc", "#", 0, S_OK, "http://www.winehq.org/test14#"}, {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"}, {"file:///C:\\dir\\file.txt#hash\\hash", "test.txt", 0, S_OK, "file:///C:/dir/file.txt#hash/test.txt"}, {"file:///C:\\dir\\file.html#hash\\hash", "test.html", 0, S_OK, "file:///C:/dir/test.html"}, @@ -296,7 +343,7 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = { {"foo:today", "foo:calendar", 0, S_OK, "foo:calendar"}, {"foo:today", "bar:calendar", 0, S_OK, "bar:calendar"}, {"foo:/today", "foo:calendar", 0, S_OK, "foo:/calendar"}, - {"foo:/today/", "foo:calendar", 0, S_OK, "foo:/today/calendar"}, + {"Foo:/today/", "fOo:calendar", 0, S_OK, "foo:/today/calendar"}, {"mk:@MSITStore:dir/test.chm::dir/index.html", "image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"}, {"mk:@MSITStore:dir/test.chm::dir/dir2/index.html", "../image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"}, /* UrlCombine case 2 tests. Schemes do not match */ @@ -318,7 +365,7 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = { {"outbind://xxxxxxxxx/","http:wine16/dir",0, S_OK,"http:wine16/dir"}, {"http://xxxxxxxxx","outbind:wine17/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"outbind:wine17/dir"}, {"xxx://xxxxxxxxx","ftp:wine18/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"ftp:wine18/dir"}, - {"ftp://xxxxxxxxx/","xxx:wine19/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"xxx:wine19/dir"}, + {"ftp://xxxxxxxxx/","xXx:wine19/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"xxx:wine19/dir"}, {"outbind://xxxxxxxxx/","http:wine20/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"http:wine20/dir"}, {"file:///c:/dir/file.txt","index.html?test=c:/abc",URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,S_OK,"file:///c:/dir/index.html?test=c:/abc"} }; @@ -337,6 +384,7 @@ static const struct { {"c:foo\\bar", "file:///c:foo/bar", S_OK}, {"c:\\foo/b a%r", "file:///c:/foo/b%20a%25r", S_OK}, {"c:\\foo\\foo bar", "file:///c:/foo/foo%20bar", S_OK}, + {"file:///c:/foo/bar", "file:///c:/foo/bar", S_FALSE}, #if 0 /* The following test fails on native shlwapi as distributed with Win95/98. * Wine matches the behaviour of later versions. @@ -587,6 +635,9 @@ static void test_UrlGetPart(void) const char* http_url = "http://user:pass 123@www.wine hq.org"; const char* res_url = "res://some.dll/find.dlg"; const char* about_url = "about:blank"; + const char* excid_url = "x-excid://36C00000/guid:{048B4E89-2E92-496F-A837-33BA02FF6D32}/Message.htm"; + const char* foo_url = "foo://bar-url/test"; + const char* short_url = "ascheme:"; CHAR szPart[INTERNET_MAX_URL_LENGTH]; DWORD dwSize; @@ -623,6 +674,20 @@ static void test_UrlGetPart(void) ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart); ok(dwSize == 0, "dwSize = %d\n", dwSize); + if(pUrlGetPartW) + { + const WCHAR hiW[] = {'h','i',0}; + WCHAR bufW[5]; + + /* UrlGetPartW returns S_OK instead of S_FALSE */ + dwSize = sizeof szPart; + bufW[0]='x'; bufW[1]=0; + res = pUrlGetPartW(hiW, bufW, &dwSize, URL_PART_SCHEME, 0); + todo_wine ok(res==S_OK, "UrlGetPartW(\"hi\") returned %08X\n", res); + ok(bufW[0] == 0, "UrlGetPartW(\"hi\") return \"%c\"\n", bufW[0]); + ok(dwSize == 0, "dwSize = %d\n", dwSize); + } + dwSize = sizeof szPart; szPart[0]='x'; szPart[1]=0; res = pUrlGetPartA("hi", szPart, &dwSize, URL_PART_QUERY, 0); @@ -637,6 +702,8 @@ static void test_UrlGetPart(void) test_url_part(TEST_URL_3, URL_PART_SCHEME, 0, "http"); test_url_part(TEST_URL_3, URL_PART_QUERY, 0, "?query=x&return=y"); + test_url_part(TEST_URL_4, URL_PART_HOSTNAME, 0, "google.*.com"); + test_url_part(file_url, URL_PART_HOSTNAME, 0, "h o s t"); test_url_part(http_url, URL_PART_HOSTNAME, 0, "www.wine hq.org"); @@ -644,6 +711,10 @@ static void test_UrlGetPart(void) test_url_part(about_url, URL_PART_SCHEME, 0, "about"); + test_url_part(excid_url, URL_PART_SCHEME, 0, "x-excid"); + test_url_part(foo_url, URL_PART_SCHEME, 0, "foo"); + test_url_part(short_url, URL_PART_SCHEME, 0, "ascheme"); + dwSize = sizeof(szPart); res = pUrlGetPartA(about_url, szPart, &dwSize, URL_PART_HOSTNAME, 0); ok(res==E_FAIL, "returned %08x\n", res); @@ -674,6 +745,34 @@ static void test_UrlGetPart(void) szPart[0] = 'x'; szPart[1] = '\0'; res = pUrlGetPartA("index.htm", szPart, &dwSize, URL_PART_HOSTNAME, 0); ok(res==E_FAIL, "returned %08x\n", res); + + dwSize = sizeof(szPart); + szPart[0] = 'x'; szPart[1] = '\0'; + res = pUrlGetPartA(excid_url, szPart, &dwSize, URL_PART_HOSTNAME, 0); + ok(res==E_FAIL, "returned %08x\n", res); + ok(szPart[0] == 'x', "szPart[0] = %c\n", szPart[0]); + ok(dwSize == sizeof(szPart), "dwSize = %d\n", dwSize); + + dwSize = sizeof(szPart); + szPart[0] = 'x'; szPart[1] = '\0'; + res = pUrlGetPartA(excid_url, szPart, &dwSize, URL_PART_QUERY, 0); + ok(res==S_FALSE, "returned %08x\n", res); + ok(szPart[0] == 0, "szPart[0] = %c\n", szPart[0]); + ok(dwSize == 0, "dwSize = %d\n", dwSize); + + dwSize = sizeof(szPart); + szPart[0] = 'x'; szPart[1] = '\0'; + res = pUrlGetPartA(foo_url, szPart, &dwSize, URL_PART_HOSTNAME, 0); + ok(res==E_FAIL, "returned %08x\n", res); + ok(szPart[0] == 'x', "szPart[0] = %c\n", szPart[0]); + ok(dwSize == sizeof(szPart), "dwSize = %d\n", dwSize); + + dwSize = sizeof(szPart); + szPart[0] = 'x'; szPart[1] = '\0'; + res = pUrlGetPartA(foo_url, szPart, &dwSize, URL_PART_QUERY, 0); + ok(res==S_FALSE, "returned %08x\n", res); + ok(szPart[0] == 0, "szPart[0] = %c\n", szPart[0]); + ok(dwSize == 0, "dwSize = %d\n", dwSize); } /* ########################### */ @@ -750,10 +849,13 @@ static void test_url_canonicalize(int index, const char *szUrl, DWORD dwFlags, H static void test_UrlEscape(void) { + static const WCHAR out[] = { 'f','o','o','%','2','0','b','a','r',0 }; + DWORD size = 0; HRESULT ret; unsigned int i; char empty_string[] = ""; + WCHAR overwrite[] = { 'f','o','o',' ','b','a','r',0,0,0 }; if (!pUrlEscapeA) { win_skip("UrlEscapeA noz found\n"); @@ -780,9 +882,28 @@ static void test_UrlEscape(void) ok(size == 1, "got %d, expected %d\n", size, 1); size = 1; + empty_string[0] = 127; ret = pUrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_SPACES_ONLY); ok(ret == E_POINTER, "got %x, expected %x\n", ret, E_POINTER); ok(size == 34, "got %d, expected %d\n", size, 34); + ok(empty_string[0] == 127, "String has changed, empty_string[0] = %d\n", empty_string[0]); + + if(pUrlEscapeW) { + WCHAR wc; + + size = sizeof(overwrite)/sizeof(WCHAR); + ret = pUrlEscapeW(overwrite, overwrite, &size, URL_ESCAPE_SPACES_ONLY); + ok(ret == S_OK, "got %x, expected S_OK\n", ret); + ok(size == 9, "got %d, expected 9\n", size); + ok(!lstrcmpW(overwrite, out), "got %s, expected %s\n", wine_dbgstr_w(overwrite), wine_dbgstr_w(out)); + + size = 1; + wc = 127; + ret = pUrlEscapeW(overwrite, &wc, &size, URL_ESCAPE_SPACES_ONLY); + ok(ret == E_POINTER, "got %x, expected %x\n", ret, E_POINTER); + ok(size == 10, "got %d, expected 10\n", size); + ok(wc == 127, "String has changed, wc = %d\n", wc); + } for(i=0; i