f38ae2b379cd30b1ee398d17b2a94fedbcaf1648
[reactos.git] / rostests / winetests / shdocvw / shortcut.c
1 /*
2 * Unit tests to document shdocvw's 'Shell Instance Objects' features
3 *
4 * Copyright 2005 Michael Jung
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /* At least since Windows 2000 it's possible to add FolderShortcut objects
22 * by creating some registry entries. Those objects, which refer to some
23 * point in the filesystem, can be registered in the shell namespace like other
24 * shell namespace extensions. Icons, names and filesystem location can be
25 * configured. This is documented at http://www.virtualplastic.net/html/ui_shell.html
26 * You can also google for a tool called "ShellObjectEditor" by "Tropical
27 * Technologies". This mechanism would be cool for wine, since we could
28 * map Gnome's virtual devices to FolderShortcuts and have them appear in the
29 * file dialogs. These unit tests are meant to document how this mechanism
30 * works on windows.
31 *
32 * Search MSDN for "Creating Shell Extensions with Shell Instance Objects" for
33 * more documentation.*/
34
35 #include <stdarg.h>
36
37 #define COBJMACROS
38
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winreg.h"
42
43 #include "shlobj.h"
44 #include "shobjidl.h"
45 #include "shlguid.h"
46 #include "ole2.h"
47
48 #include "wine/test.h"
49
50 /* The following definitions and helper functions are meant to make the de-/registration
51 * of the various necessary registry keys easier. */
52
53 struct registry_value {
54 const char *szName;
55 const DWORD dwType;
56 const char *szValue;
57 const DWORD dwValue;
58 };
59
60 #define REG_VALUE_ADDR(x) ((x->dwType==REG_SZ)?(const BYTE *)x->szValue:(const BYTE *)&x->dwValue)
61 #define REG_VALUE_SIZE(x) ((x->dwType==REG_SZ)?strlen(x->szValue)+1:sizeof(DWORD))
62
63 struct registry_key {
64 const char *szName;
65 const struct registry_value *pValues;
66 const unsigned int cValues;
67 const struct registry_key *pSubKeys;
68 const unsigned int cSubKeys;
69 };
70
71 static const struct registry_value ShellFolder_values[] = {
72 { "WantsFORPARSING", REG_SZ, "", 0 },
73 { "Attributes", REG_DWORD, NULL, 0xF8000100 }
74 };
75
76 static const struct registry_value Instance_values[] = {
77 { "CLSID", REG_SZ, "{0AFACED1-E828-11D1-9187-B532F1E9575D}", 0 }
78 };
79
80 static const struct registry_value InitPropertyBag_values[] = {
81 { "Attributes", REG_DWORD, NULL, 0x00000015 },
82 { "Target", REG_SZ, "C:\\", 0 }
83 };
84
85 static const struct registry_key Instance_keys[] = {
86 { "InitPropertyBag", InitPropertyBag_values, 2, NULL, 0 }
87 };
88
89 static const struct registry_value InProcServer32_values[] = {
90 { NULL, REG_SZ, "shdocvw.dll", 0 },
91 { "ThreadingModel", REG_SZ, "Apartment", 0 }
92 };
93
94 static const struct registry_value DefaultIcon_values[] = {
95 { NULL, REG_SZ,"shell32.dll,8", 0 }
96 };
97
98 static const struct registry_key ShortcutCLSID_keys[] = {
99 { "DefaultIcon", DefaultIcon_values, 1, NULL, 0 },
100 { "InProcServer32", InProcServer32_values, 2, NULL, 0 },
101 { "Instance", Instance_values, 1, Instance_keys, 1 },
102 { "ShellFolder", ShellFolder_values, 2, NULL, 0 }
103 };
104
105 static const struct registry_value ShortcutCLSID_values[] = {
106 { NULL, REG_SZ, "WineTest", 0 }
107 };
108
109 static const struct registry_key HKEY_CLASSES_ROOT_keys[] = {
110 { "CLSID\\{9B352EBF-2765-45C1-B4C6-85CC7F7ABC64}", ShortcutCLSID_values, 1, ShortcutCLSID_keys, 4}
111 };
112
113 /* register_keys - helper function, which recursively creates the registry keys and values in
114 * parameter 'keys' in the registry under hRootKey. */
115 static BOOL register_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) {
116 HKEY hKey;
117 unsigned int iKey, iValue;
118
119 for (iKey = 0; iKey < numKeys; iKey++) {
120 if (ERROR_SUCCESS == RegCreateKeyExA(hRootKey, keys[iKey].szName, 0, NULL, 0,
121 KEY_WRITE, NULL, &hKey, NULL))
122 {
123 for (iValue = 0; iValue < keys[iKey].cValues; iValue++) {
124 const struct registry_value * value = &keys[iKey].pValues[iValue];
125 if (ERROR_SUCCESS != RegSetValueExA(hKey, value->szName, 0, value->dwType,
126 REG_VALUE_ADDR(value), REG_VALUE_SIZE(value)))
127 {
128 RegCloseKey(hKey);
129 return FALSE;
130 }
131 }
132
133 if (!register_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys)) {
134 RegCloseKey(hKey);
135 return FALSE;
136 }
137
138 RegCloseKey(hKey);
139 }
140 }
141
142 return TRUE;
143 }
144
145 /* unregister_keys - clean up after register_keys */
146 static void unregister_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) {
147 HKEY hKey;
148 unsigned int iKey;
149
150 for (iKey = 0; iKey < numKeys; iKey++) {
151 if (ERROR_SUCCESS == RegOpenKeyExA(hRootKey, keys[iKey].szName, 0, DELETE, &hKey)) {
152 unregister_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys);
153 RegCloseKey(hKey);
154 }
155 RegDeleteKeyA(hRootKey, keys[iKey].szName);
156 }
157 }
158
159 static void test_ShortcutFolder(void) {
160 LPSHELLFOLDER pDesktopFolder, pWineTestFolder;
161 IPersistFolder3 *pWineTestPersistFolder;
162 LPITEMIDLIST pidlWineTestFolder, pidlCurFolder;
163 HRESULT hr;
164 CLSID clsid;
165 const CLSID CLSID_WineTest =
166 { 0x9b352ebf, 0x2765, 0x45c1, { 0xb4, 0xc6, 0x85, 0xcc, 0x7f, 0x7a, 0xbc, 0x64 } };
167 WCHAR wszWineTestFolder[] = {
168 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
169 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
170
171 /* First, we register all the necessary registry keys/values for our 'WineTest'
172 * shell object. */
173 register_keys(HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT_keys, 1);
174
175 hr = SHGetDesktopFolder(&pDesktopFolder);
176 ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
177 if (FAILED(hr)) goto cleanup;
178
179 /* Convert the wszWineTestFolder string to an ITEMIDLIST. */
180 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
181 &pidlWineTestFolder, NULL);
182 todo_wine
183 {
184 ok (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
185 "Expected %08x, got %08x\n", HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), hr);
186 }
187 if (FAILED(hr)) {
188 IShellFolder_Release(pDesktopFolder);
189 goto cleanup;
190 }
191
192 /* FIXME: these tests are never run */
193
194 /* Bind to a WineTest folder object. There has to be some support for this in shdocvw.dll.
195 * This isn't implemented in wine yet.*/
196 hr = IShellFolder_BindToObject(pDesktopFolder, pidlWineTestFolder, NULL, &IID_IShellFolder,
197 (LPVOID*)&pWineTestFolder);
198 IShellFolder_Release(pDesktopFolder);
199 ILFree(pidlWineTestFolder);
200 ok (SUCCEEDED(hr), "IShellFolder::BindToObject(WineTestFolder) failed! hr = %08x\n", hr);
201 if (FAILED(hr)) goto cleanup;
202
203 hr = IShellFolder_QueryInterface(pWineTestFolder, &IID_IPersistFolder3, (LPVOID*)&pWineTestPersistFolder);
204 ok (SUCCEEDED(hr), "IShellFolder::QueryInterface(IPersistFolder3) failed! hr = %08x\n", hr);
205 IShellFolder_Release(pWineTestFolder);
206 if (FAILED(hr)) goto cleanup;
207
208 /* The resulting folder object has the FolderShortcut CLSID, instead of it's own. */
209 hr = IPersistFolder3_GetClassID(pWineTestPersistFolder, &clsid);
210 ok (SUCCEEDED(hr), "IPersist::GetClassID failed! hr = %08x\n", hr);
211 ok (IsEqualCLSID(&CLSID_FolderShortcut, &clsid), "GetClassId returned wrong CLSID!\n");
212
213 pidlCurFolder = (LPITEMIDLIST)0xdeadbeef;
214 hr = IPersistFolder3_GetCurFolder(pWineTestPersistFolder, &pidlCurFolder);
215 ok (SUCCEEDED(hr), "IPersistFolder3::GetCurFolder failed! hr = %08x\n", hr);
216 ok (pidlCurFolder->mkid.cb == 20 && ((LPSHITEMID)((BYTE*)pidlCurFolder+20))->cb == 0 &&
217 IsEqualCLSID(&CLSID_WineTest, (REFCLSID)((LPBYTE)pidlCurFolder+4)),
218 "GetCurFolder returned unexpected pidl!\n");
219
220 ILFree(pidlCurFolder);
221 IPersistFolder3_Release(pWineTestPersistFolder);
222
223 cleanup:
224 unregister_keys(HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT_keys, 1);
225 }
226
227 START_TEST(shortcut)
228 {
229 OleInitialize(NULL);
230 test_ShortcutFolder();
231 OleUninitialize();
232 }