1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Test for IACLCustomMRU objects
5  * COPYRIGHT:   Copyright 2017-2020 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #define _UNICODE
9 #define UNICODE
10 #include <apitest.h>
11 #include <shlobj.h>
12 #include <atlbase.h>
13 #include <atlstr.h>
14 #include <atlcom.h>
15 #include <atlwin.h>
16 
17 // Yes, gcc at it again, let's validate everything found inside unused templates!
18 ULONG DbgPrint(PCH Format,...);
19 
20 #include <shellutils.h>
21 #include <shlwapi.h>
22 #include <strsafe.h>
23 #include <initguid.h>
24 
25 #define ok_hex2(file, line, key, expression, result) \
26     do { \
27         int _value = (expression); \
28         ok_(file, line)(_value == (result), "Wrong value for '%s', expected: " #result " (0x%x), got: 0x%x for %c\n", \
29            #expression, (int)(result), _value, (char)key); \
30     } while (0)
31 
32 #define ok_wstri(x, y) \
33     ok(lstrcmpiW(x, y) == 0, "Wrong string. Expected '%S', got '%S'\n", y, x)
34 
35 struct CCoInit
36 {
37     CCoInit() { hres = CoInitialize(NULL); }
38     ~CCoInit() { if (SUCCEEDED(hres)) { CoUninitialize(); } }
39     HRESULT hres;
40 };
41 
42 
43 DEFINE_GUID(IID_IACLCustomMRU,             0xf729fc5e, 0x8769, 0x4f3e, 0xbd, 0xb2, 0xd7, 0xb5, 0x0f, 0xd2, 0x27, 0x5b);
44 static const WCHAR szTestPath[] = L"TESTPATH_BROWSEUI_APITEST";
45 
46 #undef INTERFACE
47 #define INTERFACE IACLCustomMRU
48 
49 /* based on https://msdn.microsoft.com/en-gb/library/windows/desktop/bb776380(v=vs.85).aspx */
50 DECLARE_INTERFACE_IID_(IACLCustomMRU, IUnknown, "F729FC5E-8769-4F3E-BDB2-D7B50FD2275B")
51 {
52     // *** IUnknown methods ***
53     STDMETHOD(QueryInterface) (THIS_ REFIID riid, void **ppv) PURE;
54     STDMETHOD_(ULONG, AddRef) (THIS)PURE;
55     STDMETHOD_(ULONG, Release) (THIS)PURE;
56 
57     // *** IACLCustomMRU methods ***
58     STDMETHOD(Initialize) (THIS_ LPCWSTR pwszMRURegKey, DWORD dwMax) PURE;
59     STDMETHOD(AddMRUString) (THIS_ LPCWSTR pwszEntry) PURE;
60 };
61 
62 
63 static void Cleanup_Testdata()
64 {
65     CRegKey tmp;
66     if (!tmp.Open(HKEY_CURRENT_USER, NULL, KEY_READ | KEY_WRITE))
67         tmp.DeleteSubKey(szTestPath);
68 }
69 
70 #define verify_mru(mru, ...)     verify_mru_(__FILE__, __LINE__, mru, __VA_ARGS__, NULL)
71 static void verify_mru_(const char* file, int line, IACLCustomMRU* mru, PCWSTR MRUString, ...)
72 {
73 
74     CRegKey key;
75     key.Open(HKEY_CURRENT_USER, szTestPath);
76 
77     va_list args;
78     va_start(args, MRUString);
79     PCWSTR Entry;
80     WCHAR Key = L'a';
81     while ((Entry = va_arg(args, PCWSTR)))
82     {
83         WCHAR Value[MAX_PATH];
84         ULONG nChars = _countof(Value);
85         CStringW tmp;
86         tmp += Key;
87         LSTATUS Status = key.QueryStringValue(tmp, Value, &nChars);
88         ok_hex2(file, line, Key, Status, ERROR_SUCCESS);
89         if (Status == ERROR_SUCCESS)
90         {
91             ok_(file, line)(!wcscmp(Value, Entry), "Expected value %c to be %S, was %S\n", (char)Key, Entry, Value);
92         }
93         Key++;
94     }
95     va_end(args);
96 
97     if (Key != L'a')
98     {
99         WCHAR Value[MAX_PATH];
100         ULONG nChars = _countof(Value);
101         LSTATUS Status = key.QueryStringValue(L"MRUList", Value, &nChars);
102         ok_hex2(file, line, Key, Status, ERROR_SUCCESS);
103         if (Status == ERROR_SUCCESS)
104         {
105             ok_(file, line)(!wcscmp(Value, MRUString), "Expected MRUList to be %S, was %S\n", MRUString, Value);
106         }
107     }
108 }
109 
110 
111 static void
112 test_IACLCustomMRU_Basics()
113 {
114     CComPtr<IACLCustomMRU> CustomMRU;
115     HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
116     ok_hex(hr, S_OK);
117     if (!SUCCEEDED(hr))
118         return;
119 
120     Cleanup_Testdata();
121 
122     /* Initialize with a NULL name will cause an AV */
123     //hr = CustomMRU->Initialize(NULL, 0);
124 
125     hr = CustomMRU->Initialize(szTestPath, 0);
126     ok_hex(hr, S_OK);
127     /* Adding an entry with a dwMax of 0 will cause an AV */
128 
129     /* Calling it again will resize */
130     hr = CustomMRU->Initialize(szTestPath, 3);
131     ok_hex(hr, S_OK);
132     verify_mru(CustomMRU, L"");
133 
134     hr = CustomMRU->AddMRUString(L"FIRST_ENTRY");
135     ok_hex(hr, S_OK);
136     verify_mru(CustomMRU, L"a", L"FIRST_ENTRY");
137 
138     hr = CustomMRU->AddMRUString(L"SECOND_ENTRY");
139     ok_hex(hr, S_OK);
140     verify_mru(CustomMRU, L"ba", L"FIRST_ENTRY", L"SECOND_ENTRY");
141 
142     hr = CustomMRU->AddMRUString(L"THIRD_ENTRY");
143     ok_hex(hr, S_OK);
144     verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
145 
146     /* First entry is replaced */
147     hr = CustomMRU->AddMRUString(L"FOURTH_ENTRY");
148     ok_hex(hr, S_OK);
149     verify_mru(CustomMRU, L"acb", L"FOURTH_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
150 
151     /* Second entry is replaced */
152     hr = CustomMRU->AddMRUString(L"FIFTH_ENTRY");
153     ok_hex(hr, S_OK);
154     verify_mru(CustomMRU, L"bac", L"FOURTH_ENTRY", L"FIFTH_ENTRY", L"THIRD_ENTRY");
155 }
156 
157 
158 static void FillDefault(IACLCustomMRU* CustomMRU)
159 {
160     Cleanup_Testdata();
161     HRESULT hr = CustomMRU->Initialize(szTestPath, 3);
162     ok_hex(hr, S_OK);
163     hr = CustomMRU->AddMRUString(L"FIRST_ENTRY");
164     ok_hex(hr, S_OK);
165     hr = CustomMRU->AddMRUString(L"SECOND_ENTRY");
166     ok_hex(hr, S_OK);
167     hr = CustomMRU->AddMRUString(L"THIRD_ENTRY");
168     ok_hex(hr, S_OK);
169 }
170 
171 static void
172 test_IACLCustomMRU_UpdateOrder()
173 {
174     CComPtr<IACLCustomMRU> CustomMRU;
175     HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
176     ok_hex(hr, S_OK);
177     if (!SUCCEEDED(hr))
178         return;
179 
180     Cleanup_Testdata();
181     FillDefault(CustomMRU);
182     verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
183 
184     /* Add the first entry again */
185     hr = CustomMRU->AddMRUString(L"FIRST_ENTRY");
186     ok_hex(hr, S_OK);
187     /* No change */
188     verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
189 
190     CustomMRU.Release();
191     /* Now the order is updated */
192     verify_mru(NULL, L"acb", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
193 
194 
195     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
196     ok_hex(hr, S_OK);
197     if (!SUCCEEDED(hr))
198         return;
199 
200     Cleanup_Testdata();
201     FillDefault(CustomMRU);
202     verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
203 
204 
205     /* Add the first entry again */
206     hr = CustomMRU->AddMRUString(L"FIRST_ENTRY");
207     ok_hex(hr, S_OK);
208     /* No change */
209     verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
210 
211     hr = CustomMRU->AddMRUString(L"SOMETHING_ELSE");
212     ok_hex(hr, S_OK);
213     /* Now all changes are persisted */
214     verify_mru(CustomMRU, L"bac", L"FIRST_ENTRY", L"SOMETHING_ELSE", L"THIRD_ENTRY");
215 }
216 
217 static void
218 test_IACLCustomMRU_ExtraChars()
219 {
220     CComPtr<IACLCustomMRU> CustomMRU;
221     HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
222     ok_hex(hr, S_OK);
223     if (!SUCCEEDED(hr))
224         return;
225 
226     Cleanup_Testdata();
227 
228     /* Still returnes success */
229     hr = CustomMRU->Initialize(szTestPath, 30);
230     ok_hex(hr, S_OK);
231 
232     for (int n = 0; n < 30; ++n)
233     {
234         CStringW tmp;
235         tmp.Format(L"%d", n);
236 
237         hr = CustomMRU->AddMRUString(tmp);
238         ok_hex(hr, S_OK);
239     }
240     /* But is starting to wrap around */
241     verify_mru(CustomMRU, L"a}|{zyxwvutsrqponmlkjihgfedcb", L"29",
242                L"1", L"2", L"3", L"4", L"5", L"6", L"7", L"8", L"9",
243                L"10", L"11", L"12", L"13", L"14", L"15", L"16", L"17", L"18", L"19",
244                L"20", L"21", L"22", L"23", L"24", L"25", L"26", L"27", L"28");
245 
246     Cleanup_Testdata();
247 }
248 
249 static void
250 test_IACLCustomMRU_Continue()
251 {
252     CComPtr<IACLCustomMRU> CustomMRU;
253     HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
254     ok_hex(hr, S_OK);
255     if (!SUCCEEDED(hr))
256         return;
257 
258     Cleanup_Testdata();
259     FillDefault(CustomMRU);
260     verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
261 
262     CustomMRU.Release();
263 
264     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
265     ok_hex(hr, S_OK);
266     if (!SUCCEEDED(hr))
267         return;
268 
269     hr = CustomMRU->Initialize(szTestPath, 3);
270     ok_hex(hr, S_OK);
271 
272     /* First entry is replaced */
273     hr = CustomMRU->AddMRUString(L"FOURTH_ENTRY");
274     ok_hex(hr, S_OK);
275     verify_mru(CustomMRU, L"acb", L"FOURTH_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
276 
277     CustomMRU.Release();
278 
279     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
280     ok_hex(hr, S_OK);
281     if (!SUCCEEDED(hr))
282         return;
283 
284     hr = CustomMRU->Initialize(szTestPath, 3);
285     ok_hex(hr, S_OK);
286 
287     /* Second entry is replaced */
288     hr = CustomMRU->AddMRUString(L"FIFTH_ENTRY");
289     ok_hex(hr, S_OK);
290     verify_mru(CustomMRU, L"bac", L"FOURTH_ENTRY", L"FIFTH_ENTRY", L"THIRD_ENTRY");
291 
292     CustomMRU.Release();
293 
294     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
295     ok_hex(hr, S_OK);
296     if (!SUCCEEDED(hr))
297         return;
298 
299 
300     /* Save some garbage */
301     CRegKey key;
302     key.Open(HKEY_CURRENT_USER, szTestPath);
303     key.SetStringValue(L"MRUList", L"b**");
304     key.Close();
305 
306     hr = CustomMRU->Initialize(szTestPath, 3);
307     ok_hex(hr, S_OK);
308 
309     CustomMRU.Release();
310 
311     /* Not cleaned up */
312     verify_mru(CustomMRU, L"b**", L"FOURTH_ENTRY", L"FIFTH_ENTRY", L"THIRD_ENTRY");
313 
314     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
315     ok_hex(hr, S_OK);
316     if (!SUCCEEDED(hr))
317         return;
318 
319     hr = CustomMRU->Initialize(szTestPath, 3);
320     ok_hex(hr, S_OK);
321 
322     /* Now it's just cleaned up */
323     hr = CustomMRU->AddMRUString(L"SIXTH_ENTRY");
324     ok_hex(hr, S_OK);
325     verify_mru(CustomMRU, L"ab", L"SIXTH_ENTRY");
326 
327     CustomMRU.Release();
328 
329     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
330     ok_hex(hr, S_OK);
331     if (!SUCCEEDED(hr))
332         return;
333 
334     Cleanup_Testdata();
335     FillDefault(CustomMRU);
336     verify_mru(CustomMRU, L"cba", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
337 
338     CustomMRU.Release();
339 
340     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
341     ok_hex(hr, S_OK);
342     if (!SUCCEEDED(hr))
343         return;
344 
345     key.Open(HKEY_CURRENT_USER, szTestPath);
346     key.SetStringValue(L"MRUList", L"baccccc");
347     key.Close();
348 
349     hr = CustomMRU->Initialize(szTestPath, 3);
350     ok_hex(hr, S_OK);
351     CustomMRU.Release();
352 
353     verify_mru(CustomMRU, L"baccccc", L"FIRST_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
354 
355     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
356     ok_hex(hr, S_OK);
357     if (!SUCCEEDED(hr))
358         return;
359 
360     hr = CustomMRU->Initialize(szTestPath, 3);
361     ok_hex(hr, S_OK);
362 
363     hr = CustomMRU->AddMRUString(L"FOURTH_ENTRY");
364     ok_hex(hr, S_OK);
365     verify_mru(CustomMRU, L"a", L"FOURTH_ENTRY", L"SECOND_ENTRY", L"THIRD_ENTRY");
366 
367     CustomMRU.Release();
368     Cleanup_Testdata();
369 
370     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
371     ok_hex(hr, S_OK);
372     if (!SUCCEEDED(hr))
373         return;
374 
375     hr = CustomMRU->Initialize(szTestPath, 3);
376     ok_hex(hr, S_OK);
377     if (!SUCCEEDED(hr))
378         return;
379 
380     hr = CustomMRU->AddMRUString(L"FIRST_ENTRY");
381     ok_hex(hr, S_OK);
382     verify_mru(CustomMRU, L"a", L"FIRST_ENTRY");
383 
384     CustomMRU.Release();
385 
386     key.Open(HKEY_CURRENT_USER, szTestPath);
387     key.SetStringValue(L"MRUList", L"aaa");
388     key.Close();
389 
390     hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL, IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
391     ok_hex(hr, S_OK);
392     if (!SUCCEEDED(hr))
393         return;
394 
395     hr = CustomMRU->Initialize(szTestPath, 3);
396     ok_hex(hr, S_OK);
397     if (!SUCCEEDED(hr))
398         return;
399 
400     hr = CustomMRU->AddMRUString(L"SECOND_ENTRY");
401     ok_hex(hr, S_OK);
402     verify_mru(CustomMRU, L"ba", L"FIRST_ENTRY", L"SECOND_ENTRY");
403 }
404 
405 #define TYPED_URLS_KEY L"Software\\Microsoft\\Internet Explorer\\TypedURLs"
406 
407 static void
408 RestoreTypedURLs(const CStringW& url1, const CStringW& url2)
409 {
410     CRegKey key;
411     key.Open(HKEY_CURRENT_USER, TYPED_URLS_KEY, KEY_WRITE);
412     if (url1 != L"")
413         key.SetStringValue(L"url1", url1);
414     else
415         key.DeleteValue(L"url1");
416     if (url2 != L"")
417         key.SetStringValue(L"url2", url2);
418     else
419         key.DeleteValue(L"url2");
420 }
421 
422 static void
423 test_IACLCustomMRU_TypedURLs() // TypedURLs is special case
424 {
425     CStringW url1, url2; // Save values
426     {
427         CRegKey key;
428         key.Create(HKEY_CURRENT_USER, TYPED_URLS_KEY);
429 
430         WCHAR Value[MAX_PATH];
431         ULONG cch = _countof(Value);
432         LSTATUS Status = key.QueryStringValue(L"url1", Value, &cch);
433         if (!Status)
434             url1 = Value;
435 
436         cch = _countof(Value);
437         Status = key.QueryStringValue(L"url2", Value, &cch);
438         if (!Status)
439             url2 = Value;
440 
441         // Set values
442         key.SetStringValue(L"url1", L"aaa");
443         key.SetStringValue(L"url2", L"bbb");
444     }
445 
446     CComPtr<IACLCustomMRU> CustomMRU;
447     HRESULT hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_ALL,
448                                   IID_PPV_ARG(IACLCustomMRU, &CustomMRU));
449     ok_hex(hr, S_OK);
450     if (FAILED(hr))
451     {
452         skip("IACLCustomMRU was NULL\n");
453         RestoreTypedURLs(url1, url2);
454         return;
455     }
456 
457     CComPtr<IACList> ACList;
458     hr = CustomMRU->QueryInterface(IID_PPV_ARG(IACList, &ACList));
459     ok_hex(hr, S_OK);
460     if (SUCCEEDED(hr))
461     {
462         hr = ACList->Expand(L"C:");
463         ok_hex(hr, E_NOTIMPL);
464         hr = ACList->Expand(L"C:\\");
465         ok_hex(hr, E_NOTIMPL);
466         hr = ACList->Expand(L"C:\\Program Files");
467         ok_hex(hr, E_NOTIMPL);
468         hr = ACList->Expand(L"C:\\Program Files\\");
469         ok_hex(hr, E_NOTIMPL);
470         hr = ACList->Expand(L"http://");
471         ok_hex(hr, E_NOTIMPL);
472         hr = ACList->Expand(L"https://");
473         ok_hex(hr, E_NOTIMPL);
474         hr = ACList->Expand(L"https://google.co.jp/");
475         ok_hex(hr, E_NOTIMPL);
476     }
477 
478     hr = CustomMRU->Initialize(TYPED_URLS_KEY, 64);
479     ok_hex(hr, S_OK);
480 
481     if (ACList)
482     {
483         hr = ACList->Expand(L"C:");
484         ok_hex(hr, E_NOTIMPL);
485         hr = ACList->Expand(L"C:\\");
486         ok_hex(hr, E_NOTIMPL);
487         hr = ACList->Expand(L"C:\\Program Files");
488         ok_hex(hr, E_NOTIMPL);
489         hr = ACList->Expand(L"C:\\Program Files\\");
490         ok_hex(hr, E_NOTIMPL);
491         hr = ACList->Expand(L"http://");
492         ok_hex(hr, E_NOTIMPL);
493         hr = ACList->Expand(L"https://");
494         ok_hex(hr, E_NOTIMPL);
495         hr = ACList->Expand(L"https://google.co.jp/");
496         ok_hex(hr, E_NOTIMPL);
497     }
498 
499     CComPtr<IEnumString> pEnum;
500     hr = CustomMRU->QueryInterface(IID_PPV_ARG(IEnumString, &pEnum));
501     ok_hex(hr, S_OK);
502     if (FAILED(hr))
503     {
504         skip("IEnumString was NULL\n");
505         RestoreTypedURLs(url1, url2);
506         return;
507     }
508 
509     CComPtr<IEnumString> pEnumClone;
510     hr = pEnum->Clone(&pEnumClone);
511     ok_hex(hr, E_NOTIMPL);
512 
513     hr = pEnum->Skip(1);
514     ok_hex(hr, E_NOTIMPL);
515 
516 #define INVALID_LPOLESTR ((LPOLESTR)(LONG_PTR)0xDEADBEEF)
517     LPOLESTR apsz[2] = { NULL, INVALID_LPOLESTR };
518     ULONG c = 0;
519     hr = pEnum->Next(2, apsz, &c);
520     ok_hex(hr, S_OK);
521     ok_wstri(apsz[0], L"aaa");
522     ok_int(c, 1);
523     ok(apsz[1] == INVALID_LPOLESTR, "apsz[1] was '%S'\n", apsz[1]);
524     CoTaskMemFree(apsz[0]);
525 
526     LPOLESTR psz = INVALID_LPOLESTR;
527     c = 0;
528     hr = pEnum->Next(0, &psz, &c);
529     ok_hex(hr, S_OK);
530     ok(psz == INVALID_LPOLESTR, "psz was '%S'\n", psz);
531     ok_int(c, 0);
532 
533     psz = NULL;
534     c = 0;
535     hr = pEnum->Next(1, &psz, &c);
536     ok_hex(hr, S_OK);
537     ok_wstri(psz, L"bbb");
538     ok_int(c, 1);
539     CoTaskMemFree(psz);
540 
541     hr = CustomMRU->AddMRUString(L"https://google.co.jp");
542     ok_hex(hr, E_FAIL);
543     hr = CustomMRU->AddMRUString(L"C:");
544     ok_hex(hr, E_FAIL);
545     hr = CustomMRU->AddMRUString(L"C:\\");
546     ok_hex(hr, E_FAIL);
547 
548     RestoreTypedURLs(url1, url2);
549 }
550 
551 START_TEST(IACLCustomMRU)
552 {
553     CCoInit init;
554     ok_hex(init.hres, S_OK);
555     if (!SUCCEEDED(init.hres))
556         return;
557 
558     test_IACLCustomMRU_Basics();
559     test_IACLCustomMRU_UpdateOrder();
560     test_IACLCustomMRU_ExtraChars();
561     test_IACLCustomMRU_Continue();
562     test_IACLCustomMRU_TypedURLs();
563 
564     Cleanup_Testdata();
565 }
566