1 /*
2  * PROJECT:         ReactOS API tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Test for SHParseDisplayName
5  * PROGRAMMERS:     Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include "shelltest.h"
9 
10 /* Version masks */
11 #define T_ALL     0x0
12 #define T_WIN2K   0x1
13 #define T_WINXP   0x2
14 #define T_WIN2K3  0x4
15 #define T_VISTA   0x8
16 #define T_WIN7    0x10
17 #define T_WIN8    0x20
18 #define T_WIN10   0x40
19 
20 #define T_PRE_VISTA T_WIN2K|T_WINXP|T_WIN2K3
21 #define T_VISTA_PLUS T_VISTA|T_WIN7|T_WIN8|T_WIN10
22 
23 struct test_data
24 {
25     int testline;
26     PCWSTR wszPathToParse;
27     PCWSTR wszExpectedDisplayName;
28     INT nExpectedCSIDL;
29     HRESULT hResult;
30     UINT ValidForVersion;
31 };
32 
33 struct test_data Tests[] =
34 {
35     /* Tests for CDesktopFolder */
36     {__LINE__, NULL, NULL, 0, E_OUTOFMEMORY, T_PRE_VISTA},
37     {__LINE__, NULL, NULL, 0, E_INVALIDARG, T_VISTA_PLUS},
38     {__LINE__, L"", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0, S_OK, 0},
39     {__LINE__, L" ", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), T_PRE_VISTA},
40     {__LINE__, L" ", NULL, 0, E_INVALIDARG, T_VISTA_PLUS},
41     {__LINE__, L":", NULL, 0, E_INVALIDARG, 0},
42     {__LINE__, L": ", NULL, 0, E_INVALIDARG, 0},
43     {__LINE__, L" :", NULL, 0, E_INVALIDARG, 0},
44     {__LINE__, L"/", NULL, 0, E_INVALIDARG, 0},
45     {__LINE__, L"//", NULL, 0, E_INVALIDARG, 0},
46     /* This opens C:\ from Win+R and address bar */
47     {__LINE__, L"\\", NULL, 0, E_INVALIDARG, 0},
48     /* These two opens "C:\Program Files" from Win+R and address bar */
49     {__LINE__, L"\\Program Files", NULL, 0, E_INVALIDARG, 0},
50     {__LINE__, L"\\Program Files\\", NULL, 0, E_INVALIDARG, 0},
51     {__LINE__, L"\\\\?", NULL, 0, E_INVALIDARG, 0},
52     {__LINE__, L"\\\\?\\", NULL, 0, E_INVALIDARG, 0},
53     /* Tests for the shell: protocol */
54     {__LINE__, L"shell:", NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), 0},
55     {__LINE__, L"shell::", NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), 0},
56     {__LINE__, L"shell:::", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), 0},
57     {__LINE__, L"shell:::{", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), 0},
58     {__LINE__, L"shell:fail", NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), 0},
59     {__LINE__, L"shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0, S_OK, 0},
60     {__LINE__, L"shell:desktop", NULL, CSIDL_DESKTOPDIRECTORY, S_OK, T_PRE_VISTA},
61     {__LINE__, L"shell:windows", NULL, CSIDL_WINDOWS, S_OK, T_PRE_VISTA},
62     {__LINE__, L"shell:system", NULL, CSIDL_SYSTEM, S_OK, T_PRE_VISTA},
63     {__LINE__, L"shell:personal", NULL, CSIDL_MYDOCUMENTS, S_OK, T_PRE_VISTA},
64     {__LINE__, L"shell:programs", NULL, CSIDL_PROGRAMS, S_OK, T_PRE_VISTA},
65     {__LINE__, L"shell:programfiles", NULL, CSIDL_PROGRAM_FILES, S_OK, T_PRE_VISTA},
66     {__LINE__, L"shell:windows\\system32", NULL, CSIDL_SYSTEM, S_OK, T_PRE_VISTA},
67     {__LINE__, L"shell:windows\\fonts", NULL, CSIDL_FONTS, S_OK, T_PRE_VISTA},
68     /* The following tests are confusing. They don't work for SHParseDisplayName but work on psfDesktop->ParseDisplayName */
69     {__LINE__, L"shell:desktop", NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
70     {__LINE__, L"shell:windows",  NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
71     {__LINE__, L"shell:system",  NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
72     {__LINE__, L"shell:personal",  NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
73     {__LINE__, L"shell:programs",  NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
74     {__LINE__, L"shell:programfiles",  NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
75     {__LINE__, L"shell:windows\\system32", NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
76     {__LINE__, L"shell:windows\\fonts", NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_VISTA_PLUS},
77     /* Tests for CInternet */
78     {__LINE__, L"aa:", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
79     {__LINE__, L"garbage:", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
80     {__LINE__, L"ftp:", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
81     {__LINE__, L"ftp:/", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
82     {__LINE__, L"ftp://", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
83     {__LINE__, L"ftp://a", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
84     {__LINE__, L"ftp://ftp.gnu.org/gnu/octave/", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
85     {__LINE__, L"aa:", L"aa:", 0, S_OK, T_VISTA_PLUS},
86     {__LINE__, L"garbage:", L"garbage:", 0, S_OK, T_VISTA_PLUS},
87     {__LINE__, L"ftp:", L"ftp:", 0, S_OK, T_VISTA_PLUS},
88     {__LINE__, L"ftp:/", L"ftp:/", 0, S_OK, T_VISTA_PLUS},
89     {__LINE__, L"ftp://", L"ftp:///", 0, S_OK, T_VISTA_PLUS},
90     {__LINE__, L"ftp://a", L"ftp://a/", 0, S_OK, T_VISTA_PLUS},
91     {__LINE__, L"ftp://ftp.gnu.org/gnu/octave/", L"ftp://ftp.gnu.org/gnu/octave/", 0, S_OK, T_VISTA_PLUS},
92     /* Tests for CRegFolder */
93     {__LINE__, L"::", NULL, 0, CO_E_CLASSSTRING, 0},
94     {__LINE__, L"::{", NULL, 0, CO_E_CLASSSTRING, 0},
95     {__LINE__, L"::{ ", NULL, 0, CO_E_CLASSSTRING, 0},
96     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0, S_OK, 0},
97     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D} ", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0, S_OK, 0},
98     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}a", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0, S_OK, 0},
99     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}garbage", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0, S_OK, 0},
100     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D ", NULL, 0, CO_E_CLASSSTRING, 0},
101     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\", NULL, 0, E_INVALIDARG, 0},
102     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\ ", NULL, 0, E_INVALIDARG, 0},
103     {__LINE__, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}", 0, S_OK, 0},
104      /* Tests for CDrivesFolder */
105     {__LINE__, L"c:", NULL, 0, E_INVALIDARG, T_PRE_VISTA},
106     {__LINE__, L"c:", L"C:\\", 0, S_OK, T_VISTA_PLUS},
107     {__LINE__, L"c:\\", L"C:\\", 0, S_OK, 0},
108     {__LINE__, L"C:\\", L"C:\\", 0, S_OK, 0},
109     {__LINE__, L"y:\\", NULL, 0, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), T_PRE_VISTA},
110     {__LINE__, L"y:\\", NULL, 0, HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE), T_VISTA_PLUS},
111     {__LINE__, L"C:\\ ", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), T_PRE_VISTA},
112     {__LINE__, L"C:\\ ", NULL, 0, E_INVALIDARG, T_VISTA_PLUS},
113     /* Tests for CFSFolder */
114     {__LINE__, L"$", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), 0},
115     {__LINE__, L"c:\\Program Files", L"C:\\Program Files", 0, S_OK, 0},
116     {__LINE__, L"c:\\Program Files\\", L"C:\\Program Files", 0, S_OK, 0},
117     /* Paths with . are valid for win+r dialog or address bar but not for ParseDisplayName */
118     {__LINE__, L"c:\\Program Files\\.", NULL, 0, E_INVALIDARG, 0},
119     {__LINE__, L"c:\\Program Files\\..", NULL, 0, E_INVALIDARG, 0}, /* This gives C:\ when entered in address bar */
120     {__LINE__, L".", NULL, 0, E_INVALIDARG, 0},
121     {__LINE__, L"..", NULL, 0, E_INVALIDARG, 0},
122     {__LINE__, L"C:\\.", NULL, 0, E_INVALIDARG, 0},
123     {__LINE__, L"fonts", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), 0},  /* These three work for ShellExecute */
124     {__LINE__, L"winsxs", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), 0},
125     {__LINE__, L"system32", NULL, 0, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), 0}
126 };
127 
128 UINT get_host_os_flag()
129 {
130     switch (LOWORD(GetVersion()))
131     {
132     case 5: return T_WIN2K;
133     case (5 | (1 << 8)): return T_WINXP;
134     case (5 | (2 << 8)): return T_WIN2K3;
135     case 6: return T_VISTA;
136     case (6 | (1 << 8)): return T_WIN7;
137     case (6 | (2 << 8)): return T_WIN8;
138     case 10: return T_WIN10;
139     }
140 
141     return 0;
142 }
143 
144 START_TEST(SHParseDisplayName)
145 {
146     HRESULT hr;
147     WCHAR winDir[MAX_PATH];
148     UINT os_flag = get_host_os_flag();
149     ok (os_flag != 0, "Incompatible os version %d!", os_flag);
150     if (os_flag == 0)
151         return;
152 
153     IShellFolder *psfDesktop;
154     hr = SHGetDesktopFolder(&psfDesktop);
155     ok(hr == S_OK, "hr = %lx\n", hr);
156 
157     GetWindowsDirectoryW(winDir, _countof(winDir));
158     SetCurrentDirectoryW(winDir);
159 
160     for (UINT i = 0; i < _countof(Tests); i ++)
161     {
162         if (Tests[i].ValidForVersion && !(Tests[i].ValidForVersion & os_flag))
163            continue;
164 
165         PIDLIST_ABSOLUTE pidl;
166         HRESULT hr = SHParseDisplayName(Tests[i].wszPathToParse, NULL, &pidl, 0, NULL);
167         ok(hr == Tests[i].hResult, "%d: Expected error 0x%lx, got 0x%lx\n", Tests[i].testline, Tests[i].hResult, hr);
168 
169         if (Tests[i].wszExpectedDisplayName == NULL && Tests[i].nExpectedCSIDL == 0)
170         {
171            ok(pidl == NULL, "%d: Expected no pidl\n", Tests[i].testline);
172            continue;
173         }
174 
175         ok(pidl != NULL, "%d: Expected pidl on success\n", Tests[i].testline);
176         if(!pidl)
177             continue;
178 
179         STRRET strret;
180         hr = psfDesktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
181         ok(hr == S_OK, "%d: hr = %lx\n", Tests[i].testline, hr);
182 
183         ok(strret.uType == STRRET_WSTR, "%d: Expected STRRET_WSTR\n", Tests[i].testline);
184 
185         if (Tests[i].wszExpectedDisplayName)
186         {
187             ok(!wcscmp(strret.pOleStr, Tests[i].wszExpectedDisplayName), "%d: expected %S got %S\n", Tests[i].testline, Tests[i].wszExpectedDisplayName, strret.pOleStr);
188         }
189         else
190         {
191             PIDLIST_ABSOLUTE pidlSpecial;
192             hr = SHGetSpecialFolderLocation(NULL, Tests[i].nExpectedCSIDL, &pidlSpecial);
193             ok(hr == S_OK, "%d: hr = %lx\n", Tests[i].testline, hr);
194 
195             STRRET strretSpecial;
196             hr = psfDesktop->GetDisplayNameOf(pidlSpecial, SHGDN_FORPARSING, &strretSpecial);
197             ok(hr == S_OK, "%d: hr = %lx\n", Tests[i].testline, hr);
198 
199             ok(strret.uType == STRRET_WSTR, "%d: Expected STRRET_WSTR\n", Tests[i].testline);
200 
201             ok(!wcscmp(strret.pOleStr, strretSpecial.pOleStr), "%d: expected %S got %S\n", Tests[i].testline, strretSpecial.pOleStr, strret.pOleStr);
202         }
203     }
204 
205     CoUninitialize();
206 }
207