[SHELL32_APITEST]
[reactos.git] / rostests / apitests / shell32 / CShellDesktop.cpp
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 #include <atlbase.h>
11 #include <atlcom.h>
12 #include <strsafe.h>
13 #include <ndk/rtlfuncs.h>
14
15 #define NDEBUG
16 #include <debug.h>
17 #include <shellutils.h>
18
19
20 // We would normally use S_LESSTHAN and S_GREATERTHAN, but w2k3 returns numbers like 3 and -3...
21 // So instead we check on the sign bit (compare result is the low word of the hresult).
22 #define SHORT_SIGN_BIT 0x8000
23
24 static
25 VOID
26 compare_imp(IShellFolder* psf, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, HRESULT expected)
27 {
28 HRESULT hr;
29 _SEH2_TRY
30 {
31 hr = psf->CompareIDs(0, pidl1, pidl2);
32 }
33 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
34 {
35 winetest_ok(0, "Exception %lx!\n", _SEH2_GetExceptionCode());
36 hr = HRESULT_FROM_WIN32(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
37 }
38 _SEH2_END;
39 if (expected == S_LESSTHAN)
40 winetest_ok(SUCCEEDED(hr) && (hr & SHORT_SIGN_BIT), "hr = %lx\n", hr);
41 else if (expected == S_EQUAL)
42 winetest_ok(hr == S_EQUAL, "hr = %lx\n", hr);
43 else if (expected == S_GREATERTHAN)
44 winetest_ok(SUCCEEDED(hr) && !(hr & SHORT_SIGN_BIT), "hr = %lx\n", hr);
45 else
46 winetest_ok(hr == expected, "hr = %lx\n", hr);
47 }
48
49 // 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 :)
50 #define compare (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : compare_imp
51
52 static
53 VOID
54 TestCompareIDList(IShellFolder* psf)
55 {
56 compare(psf, NULL, NULL, E_INVALIDARG);
57
58 CComHeapPtr<ITEMIDLIST> desktop;
59 HRESULT hr = SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, NULL, &desktop);
60 ok(hr == S_OK, "hr = %lx\n", hr);
61 compare(psf, desktop, NULL, E_INVALIDARG);
62 compare(psf, NULL, desktop, E_INVALIDARG);
63 compare(psf, desktop, desktop, S_EQUAL);
64
65 // First check the ordering of some special folders against eachother
66 CComHeapPtr<ITEMIDLIST> internet;
67 hr = SHGetFolderLocation(NULL, CSIDL_INTERNET, NULL, NULL, &internet);
68 ok(hr == S_OK, "hr = %lx\n", hr);
69 compare(psf, internet, desktop, S_LESSTHAN);
70 compare(psf, desktop, internet, S_GREATERTHAN);
71
72 CComHeapPtr<ITEMIDLIST> programs;
73 hr = SHGetFolderLocation(NULL, CSIDL_PROGRAMS, NULL, NULL, &programs);
74 ok(hr == S_OK, "hr = %lx\n", hr);
75 compare(psf, programs, desktop, S_LESSTHAN);
76 compare(psf, desktop, programs, S_GREATERTHAN);
77 compare(psf, internet, programs, S_GREATERTHAN);
78 compare(psf, programs, internet, S_LESSTHAN);
79
80 // Verify that an idlist retrieved from GetCurFolder is equal to the original one.
81 CComPtr<IPersistFolder2> persist;
82 hr = psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &persist));
83 ok(hr == S_OK, "hr = %lx\n", hr);
84 if (hr == S_OK)
85 {
86 CComHeapPtr<ITEMIDLIST> cur;
87 hr = persist->GetCurFolder(&cur);
88 ok(hr == S_OK, "hr = %lx\n", hr);
89 compare(psf, cur, desktop, S_EQUAL);
90 compare(psf, desktop, cur, S_EQUAL);
91 }
92
93 // Compare special folders against full paths
94 CComHeapPtr<ITEMIDLIST> dir1, dir2;
95 PathToIDList(L"A:\\AAA.AAA", &dir1);
96 PathToIDList(L"A:\\ZZZ.ZZZ", &dir2);
97
98 compare(psf, dir1, desktop, S_LESSTHAN);
99 compare(psf, desktop, dir1, S_GREATERTHAN);
100 compare(psf, dir1, programs, S_LESSTHAN);
101 compare(psf, programs, dir1, S_GREATERTHAN);
102 compare(psf, dir1, dir1, S_EQUAL);
103
104 compare(psf, dir2, desktop, S_LESSTHAN);
105 compare(psf, desktop, dir2, S_GREATERTHAN);
106 compare(psf, dir2, programs, S_LESSTHAN);
107 compare(psf, programs, dir2, S_GREATERTHAN);
108 compare(psf, dir2, dir2, S_EQUAL);
109
110 CComHeapPtr<ITEMIDLIST> dir3, dir4;
111 PathToIDList(L"Z:\\AAA.AAA", &dir3);
112 PathToIDList(L"Z:\\ZZZ.ZZZ", &dir4);
113
114 compare(psf, dir3, desktop, S_LESSTHAN);
115 compare(psf, desktop, dir3, S_GREATERTHAN);
116 compare(psf, dir3, programs, S_GREATERTHAN);
117 compare(psf, programs, dir3, S_LESSTHAN);
118 compare(psf, dir3, dir3, S_EQUAL);
119
120 compare(psf, dir4, desktop, S_LESSTHAN);
121 compare(psf, desktop, dir4, S_GREATERTHAN);
122 compare(psf, dir4, programs, S_GREATERTHAN);
123 compare(psf, programs, dir4, S_LESSTHAN);
124 compare(psf, dir4, dir4, S_EQUAL);
125
126 // Now compare the paths against eachother.
127 compare(psf, dir1, dir2, S_LESSTHAN);
128 compare(psf, dir2, dir1, S_GREATERTHAN);
129
130 compare(psf, dir2, dir3, S_LESSTHAN);
131 compare(psf, dir3, dir2, S_GREATERTHAN);
132
133 compare(psf, dir3, dir4, S_LESSTHAN);
134 compare(psf, dir4, dir3, S_GREATERTHAN);
135
136 // Check that comparing desktop pidl with another one with another IShellFolder fails
137 CComPtr<IShellFolder> psf2;
138 hr = psf->BindToObject(programs, NULL, IID_IShellFolder, reinterpret_cast<void**>(&psf2));
139 ok(hr == S_OK, "Impossible to bind to Programs pidl");
140 if (hr == S_OK)
141 {
142 // Compare desktop pidl in programs scope should fail since it's relative pidl
143 compare(psf2, desktop, programs, E_INVALIDARG);
144 compare(psf2, programs, desktop, E_INVALIDARG);
145 // For the same reasons, filesystem paths can't be compared with special shell
146 // folders that don't have CFSFolder in children
147 compare(psf2, dir1, dir2, E_INVALIDARG);
148 compare(psf2, dir2, dir1, E_INVALIDARG);
149 }
150 }
151
152 static
153 VOID
154 TestShellFolder(
155 _In_ IShellFolder2 *psf2)
156 {
157 HRESULT hr;
158 CComPtr<IDropTarget> pdt;
159 CComPtr<IDropTarget> pdt_2;
160 CComPtr<IContextMenu> pcm;
161 CComPtr<IContextMenu> pcm_2;
162 CComPtr<IShellView> psv;
163 CComPtr<IShellView> psv_2;
164
165 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pdt));
166 ok(hr == S_OK, "hr = %lx\n", hr);
167
168 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pdt_2));
169 ok(hr == S_OK, "hr = %lx\n", hr);
170 ok(pdt != pdt_2, "Expected %p != %p\n", static_cast<PVOID>(pdt), static_cast<PVOID>(pdt_2));
171
172 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IContextMenu, &pcm));
173 ok(hr == S_OK, "hr = %lx\n", hr);
174
175 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IContextMenu, &pcm_2));
176 ok(hr == S_OK, "hr = %lx\n", hr);
177 ok(pcm != pcm_2, "Expected %p != %p\n", static_cast<PVOID>(pcm), static_cast<PVOID>(pcm_2));
178
179 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IShellView, &psv));
180 ok(hr == S_OK, "hr = %lx\n", hr);
181
182 hr = psf2->CreateViewObject(NULL, IID_PPV_ARG(IShellView, &psv_2));
183 ok(hr == S_OK, "hr = %lx\n", hr);
184 ok(psv != psv_2, "Expected %p != %p\n", static_cast<PVOID>(psv), static_cast<PVOID>(psv_2));
185 }
186
187 START_TEST(CShellDesktop)
188 {
189 HRESULT hr;
190 CComPtr<IShellFolder2> psf2;
191 CComPtr<IShellFolder2> psf2_2;
192 CComPtr<IShellFolder> psf;
193
194 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
195
196 hr = CoCreateInstance(CLSID_ShellDesktop,
197 NULL,
198 CLSCTX_INPROC_SERVER,
199 IID_PPV_ARG(IShellFolder2, &psf2));
200 ok(hr == S_OK, "hr = %lx\n", hr);
201 if (FAILED(hr))
202 {
203 skip("Could not instantiate CShellDesktop\n");
204 return;
205 }
206
207 /* second create should give us a pointer to the same object */
208 hr = CoCreateInstance(CLSID_ShellDesktop,
209 NULL,
210 CLSCTX_INPROC_SERVER,
211 IID_PPV_ARG(IShellFolder2, &psf2_2));
212 ok(hr == S_OK, "hr = %lx\n", hr);
213 ok(psf2 == psf2_2, "Expected %p == %p\n", static_cast<PVOID>(psf2), static_cast<PVOID>(psf2_2));
214
215 /* SHGetDesktopFolder should also give us the same pointer */
216 hr = SHGetDesktopFolder(&psf);
217 ok(hr == S_OK, "hr = %lx\n", hr);
218 ok(psf == static_cast<IShellFolder *>(psf2), "Expected %p == %p\n", static_cast<PVOID>(psf), static_cast<PVOID>(psf2));
219
220 TestShellFolder(psf2);
221 TestCompareIDList(psf);
222 }