1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Test for CShellDesktop 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 * Mark Jansen 7 */ 8 9 #include "shelltest.h" 10 11 #include <ndk/rtlfuncs.h> 12 #include <shellutils.h> 13 14 // We would normally use S_LESSTHAN and S_GREATERTHAN, but w2k3 returns numbers like 3 and -3... 15 // So instead we check on the sign bit (compare result is the low word of the hresult). 16 #define SHORT_SIGN_BIT 0x8000 17 18 static 19 VOID 20 compare_imp(IShellFolder* psf, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, HRESULT expected) 21 { 22 HRESULT hr; 23 _SEH2_TRY 24 { 25 hr = psf->CompareIDs(0, pidl1, pidl2); 26 } 27 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 28 { 29 winetest_ok(0, "Exception %lx!\n", _SEH2_GetExceptionCode()); 30 hr = HRESULT_FROM_WIN32(RtlNtStatusToDosError(_SEH2_GetExceptionCode())); 31 } 32 _SEH2_END; 33 if (expected == S_LESSTHAN) 34 winetest_ok(SUCCEEDED(hr) && (hr & SHORT_SIGN_BIT), "hr = %lx\n", hr); 35 else if (expected == S_EQUAL) 36 winetest_ok(hr == S_EQUAL, "hr = %lx\n", hr); 37 else if (expected == S_GREATERTHAN) 38 winetest_ok(SUCCEEDED(hr) && !(hr & SHORT_SIGN_BIT), "hr = %lx\n", hr); 39 else 40 winetest_ok(hr == expected, "hr = %lx\n", hr); 41 } 42 43 // make the winetest_ok look like it came from the line where the compare function was called, and not from inside the compare_imp function :) 44 #define compare (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : compare_imp 45 46 static 47 VOID 48 TestCompareIDList(IShellFolder* psf) 49 { 50 compare(psf, NULL, NULL, E_INVALIDARG); 51 52 CComHeapPtr<ITEMIDLIST> desktop; 53 HRESULT hr = SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, NULL, &desktop); 54 ok(hr == S_OK, "hr = %lx\n", hr); 55 compare(psf, desktop, NULL, E_INVALIDARG); 56 compare(psf, NULL, desktop, E_INVALIDARG); 57 compare(psf, desktop, desktop, S_EQUAL); 58 59 // First check the ordering of some special folders against eachother 60 CComHeapPtr<ITEMIDLIST> internet; 61 hr = SHGetFolderLocation(NULL, CSIDL_INTERNET, NULL, NULL, &internet); 62 ok(hr == S_OK, "hr = %lx\n", hr); 63 compare(psf, internet, desktop, S_LESSTHAN); 64 compare(psf, desktop, internet, S_GREATERTHAN); 65 66 CComHeapPtr<ITEMIDLIST> programs; 67 hr = SHGetFolderLocation(NULL, CSIDL_PROGRAMS, NULL, NULL, &programs); 68 ok(hr == S_OK, "hr = %lx\n", hr); 69 compare(psf, programs, desktop, S_LESSTHAN); 70 compare(psf, desktop, programs, S_GREATERTHAN); 71 compare(psf, internet, programs, S_GREATERTHAN); 72 compare(psf, programs, internet, S_LESSTHAN); 73 74 // Verify that an idlist retrieved from GetCurFolder is equal to the original one. 75 CComPtr<IPersistFolder2> persist; 76 hr = psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &persist)); 77 ok(hr == S_OK, "hr = %lx\n", hr); 78 if (hr == S_OK) 79 { 80 CComHeapPtr<ITEMIDLIST> cur; 81 hr = persist->GetCurFolder(&cur); 82 ok(hr == S_OK, "hr = %lx\n", hr); 83 compare(psf, cur, desktop, S_EQUAL); 84 compare(psf, desktop, cur, S_EQUAL); 85 } 86 87 // Compare special folders against full paths 88 CComHeapPtr<ITEMIDLIST> dir1, dir2; 89 PathToIDList(L"A:\\AAA.AAA", &dir1); 90 PathToIDList(L"A:\\ZZZ.ZZZ", &dir2); 91 92 compare(psf, dir1, desktop, S_LESSTHAN); 93 compare(psf, desktop, dir1, S_GREATERTHAN); 94 compare(psf, dir1, programs, S_LESSTHAN); 95 compare(psf, programs, dir1, S_GREATERTHAN); 96 compare(psf, dir1, dir1, S_EQUAL); 97 98 compare(psf, dir2, desktop, S_LESSTHAN); 99 compare(psf, desktop, dir2, S_GREATERTHAN); 100 compare(psf, dir2, programs, S_LESSTHAN); 101 compare(psf, programs, dir2, S_GREATERTHAN); 102 compare(psf, dir2, dir2, S_EQUAL); 103 104 CComHeapPtr<ITEMIDLIST> dir3, dir4; 105 PathToIDList(L"Z:\\AAA.AAA", &dir3); 106 PathToIDList(L"Z:\\ZZZ.ZZZ", &dir4); 107 108 compare(psf, dir3, desktop, S_LESSTHAN); 109 compare(psf, desktop, dir3, S_GREATERTHAN); 110 compare(psf, dir3, programs, S_GREATERTHAN); 111 compare(psf, programs, dir3, S_LESSTHAN); 112 compare(psf, dir3, dir3, S_EQUAL); 113 114 compare(psf, dir4, desktop, S_LESSTHAN); 115 compare(psf, desktop, dir4, S_GREATERTHAN); 116 compare(psf, dir4, programs, S_GREATERTHAN); 117 compare(psf, programs, dir4, S_LESSTHAN); 118 compare(psf, dir4, dir4, S_EQUAL); 119 120 // Now compare the paths against eachother. 121 compare(psf, dir1, dir2, S_LESSTHAN); 122 compare(psf, dir2, dir1, S_GREATERTHAN); 123 124 compare(psf, dir2, dir3, S_LESSTHAN); 125 compare(psf, dir3, dir2, S_GREATERTHAN); 126 127 compare(psf, dir3, dir4, S_LESSTHAN); 128 compare(psf, dir4, dir3, S_GREATERTHAN); 129 130 // Check that comparing desktop pidl with another one with another IShellFolder fails 131 CComPtr<IShellFolder> psf2; 132 hr = psf->BindToObject(programs, NULL, IID_IShellFolder, reinterpret_cast<void**>(&psf2)); 133 ok(hr == S_OK, "Impossible to bind to Programs pidl"); 134 if (hr == S_OK) 135 { 136 // Compare desktop pidl in programs scope should fail since it's relative pidl 137 compare(psf2, desktop, programs, E_INVALIDARG); 138 compare(psf2, programs, desktop, E_INVALIDARG); 139 // For the same reasons, filesystem paths can't be compared with special shell 140 // folders that don't have CFSFolder in children 141 compare(psf2, dir1, dir2, E_INVALIDARG); 142 compare(psf2, dir2, dir1, E_INVALIDARG); 143 } 144 } 145 146 static 147 VOID 148 TestDesktopFolder( 149 _In_ IShellFolder2 *psf2) 150 { 151 HRESULT hr; 152 CComPtr<IDropTarget> pdt; 153 CComPtr<IDropTarget> pdt_2; 154 CComPtr<IContextMenu> pcm; 155 CComPtr<IContextMenu> pcm_2; 156 CComPtr<IShellView> psv; 157 CComPtr<IShellView> psv_2; 158 159 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pdt)); 160 ok(hr == S_OK, "hr = %lx\n", hr); 161 162 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pdt_2)); 163 ok(hr == S_OK, "hr = %lx\n", hr); 164 ok(pdt != pdt_2, "Expected %p != %p\n", static_cast<PVOID>(pdt), static_cast<PVOID>(pdt_2)); 165 166 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IContextMenu, &pcm)); 167 ok(hr == S_OK, "hr = %lx\n", hr); 168 169 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IContextMenu, &pcm_2)); 170 ok(hr == S_OK, "hr = %lx\n", hr); 171 ok(pcm != pcm_2, "Expected %p != %p\n", static_cast<PVOID>(pcm), static_cast<PVOID>(pcm_2)); 172 173 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IShellView, &psv)); 174 ok(hr == S_OK, "hr = %lx\n", hr); 175 176 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IShellView, &psv_2)); 177 ok(hr == S_OK, "hr = %lx\n", hr); 178 ok(psv != psv_2, "Expected %p != %p\n", static_cast<PVOID>(psv), static_cast<PVOID>(psv_2)); 179 180 STRRET strret; 181 hr = psf2->GetDisplayNameOf(NULL, 0, &strret); 182 ok(hr == S_OK, "hr = %lx\n", hr); 183 } 184 185 VOID TestInitialize(_In_ IShellFolder *psf) 186 { 187 CComPtr<IPersistFolder2> ppf2; 188 HRESULT hr = psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2)); 189 ok(hr == S_OK, "hr = %lx\n", hr); 190 191 /* Create a tiny pidl with no contents */ 192 LPITEMIDLIST testpidl = (LPITEMIDLIST)SHAlloc(3 * sizeof(WORD)); 193 testpidl->mkid.cb = 2 * sizeof(WORD); 194 *(WORD*)((char*)testpidl + (int)(2 * sizeof(WORD))) = 0; 195 196 hr = ppf2->Initialize(testpidl); 197 ok(hr == E_INVALIDARG, "hr = %lx\n", hr); 198 199 //crashes in xp, works on win10 200 //hr = ppf2->Initialize(NULL); 201 //ok(hr == S_OK, "hr = %lx\n", hr); 202 //hr = ppf2->Initialize((LPCITEMIDLIST)0xdeaddead); 203 //ok(hr == S_OK, "hr = %lx\n", hr); 204 //hr = ppf2->GetCurFolder(NULL); 205 //ok(hr == E_INVALIDARG, "hr = %lx\n", hr); 206 207 LPITEMIDLIST pidl; 208 hr = ppf2->GetCurFolder(&pidl); 209 ok(hr == S_OK, "hr = %lx\n", hr); 210 ok(pidl->mkid.cb == 0, "expected empty pidl got cb = %x\n", pidl->mkid.cb); 211 } 212 213 START_TEST(CShellDesktop) 214 { 215 HRESULT hr; 216 CComPtr<IShellFolder2> psf2; 217 CComPtr<IShellFolder2> psf2_2; 218 CComPtr<IShellFolder> psf; 219 220 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 221 222 hr = CoCreateInstance(CLSID_ShellDesktop, 223 NULL, 224 CLSCTX_INPROC_SERVER, 225 IID_PPV_ARG(IShellFolder2, &psf2)); 226 ok(hr == S_OK, "hr = %lx\n", hr); 227 if (FAILED(hr)) 228 { 229 skip("Could not instantiate CShellDesktop\n"); 230 return; 231 } 232 233 /* second create should give us a pointer to the same object */ 234 hr = CoCreateInstance(CLSID_ShellDesktop, 235 NULL, 236 CLSCTX_INPROC_SERVER, 237 IID_PPV_ARG(IShellFolder2, &psf2_2)); 238 ok(hr == S_OK, "hr = %lx\n", hr); 239 ok(psf2 == psf2_2, "Expected %p == %p\n", static_cast<PVOID>(psf2), static_cast<PVOID>(psf2_2)); 240 241 /* SHGetDesktopFolder should also give us the same pointer */ 242 hr = SHGetDesktopFolder(&psf); 243 ok(hr == S_OK, "hr = %lx\n", hr); 244 ok(psf == static_cast<IShellFolder *>(psf2), "Expected %p == %p\n", static_cast<PVOID>(psf), static_cast<PVOID>(psf2)); 245 246 TestDesktopFolder(psf2); 247 TestCompareIDList(psf); 248 TestInitialize(psf); 249 } 250