ReactOS 0.4.15-dev-7924-g5949c20
shortcut.c
Go to the documentation of this file.
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 "initguid.h"
44#include "shlobj.h"
45#include "shobjidl.h"
46#include "shlguid.h"
47#include "ole2.h"
48
49#include "wine/test.h"
50
51/* The following definitions and helper functions are meant to make the de-/registration
52 * of the various necessary registry keys easier. */
53
54struct registry_value {
55 const char *szName;
57 const char *szValue;
59};
60
61#define REG_VALUE_ADDR(x) ((x->dwType==REG_SZ)?(const BYTE *)x->szValue:(const BYTE *)&x->dwValue)
62#define REG_VALUE_SIZE(x) ((x->dwType==REG_SZ)?strlen(x->szValue)+1:sizeof(DWORD))
63
65 const char *szName;
66 const struct registry_value *pValues;
67 const unsigned int cValues;
68 const struct registry_key *pSubKeys;
69 const unsigned int cSubKeys;
70};
71
72static const struct registry_value ShellFolder_values[] = {
73 { "WantsFORPARSING", REG_SZ, "", 0 },
74 { "Attributes", REG_DWORD, NULL, 0xF8000100 }
75};
76
77static const struct registry_value Instance_values[] = {
78 { "CLSID", REG_SZ, "{0AFACED1-E828-11D1-9187-B532F1E9575D}", 0 }
79};
80
81static const struct registry_value InitPropertyBag_values[] = {
82 { "Attributes", REG_DWORD, NULL, 0x00000015 },
83 { "Target", REG_SZ, "C:\\", 0 }
84};
85
86static const struct registry_key Instance_keys[] = {
87 { "InitPropertyBag", InitPropertyBag_values, 2, NULL, 0 }
88};
89
90static const struct registry_value InProcServer32_values[] = {
91 { NULL, REG_SZ, "shdocvw.dll", 0 },
92 { "ThreadingModel", REG_SZ, "Apartment", 0 }
93};
94
95static const struct registry_value DefaultIcon_values[] = {
96 { NULL, REG_SZ,"shell32.dll,8", 0 }
97};
98
99static const struct registry_key ShortcutCLSID_keys[] = {
100 { "DefaultIcon", DefaultIcon_values, 1, NULL, 0 },
101 { "InProcServer32", InProcServer32_values, 2, NULL, 0 },
102 { "Instance", Instance_values, 1, Instance_keys, 1 },
103 { "ShellFolder", ShellFolder_values, 2, NULL, 0 }
104};
105
106static const struct registry_value ShortcutCLSID_values[] = {
107 { NULL, REG_SZ, "WineTest", 0 }
108};
109
110static const struct registry_key HKEY_CLASSES_ROOT_keys[] = {
111 { "CLSID\\{9B352EBF-2765-45C1-B4C6-85CC7F7ABC64}", ShortcutCLSID_values, 1, ShortcutCLSID_keys, 4}
112};
113
114/* register_keys - helper function, which recursively creates the registry keys and values in
115 * parameter 'keys' in the registry under hRootKey. */
116static BOOL register_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) {
117 HKEY hKey;
118 unsigned int iKey, iValue;
119
120 for (iKey = 0; iKey < numKeys; iKey++) {
121 if (ERROR_SUCCESS == RegCreateKeyExA(hRootKey, keys[iKey].szName, 0, NULL, 0,
122 KEY_WRITE, NULL, &hKey, NULL))
123 {
124 for (iValue = 0; iValue < keys[iKey].cValues; iValue++) {
125 const struct registry_value * value = &keys[iKey].pValues[iValue];
126 if (ERROR_SUCCESS != RegSetValueExA(hKey, value->szName, 0, value->dwType,
128 {
130 return FALSE;
131 }
132 }
133
134 if (!register_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys)) {
136 return FALSE;
137 }
138
140 }
141 }
142
143 return TRUE;
144}
145
146/* unregister_keys - clean up after register_keys */
147static void unregister_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) {
148 HKEY hKey;
149 unsigned int iKey;
150
151 for (iKey = 0; iKey < numKeys; iKey++) {
152 if (ERROR_SUCCESS == RegOpenKeyExA(hRootKey, keys[iKey].szName, 0, DELETE, &hKey)) {
153 unregister_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys);
155 }
156 RegDeleteKeyA(hRootKey, keys[iKey].szName);
157 }
158}
159
160static void test_ShortcutFolder(void) {
161 LPSHELLFOLDER pDesktopFolder, pWineTestFolder;
162 IPersistFolder3 *pWineTestPersistFolder;
163 LPITEMIDLIST pidlWineTestFolder, pidlCurFolder;
164 HRESULT hr;
165 CLSID clsid;
166 const CLSID CLSID_WineTest =
167 { 0x9b352ebf, 0x2765, 0x45c1, { 0xb4, 0xc6, 0x85, 0xcc, 0x7f, 0x7a, 0xbc, 0x64 } };
168 WCHAR wszWineTestFolder[] = {
169 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
170 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
171
172 /* First, we register all the necessary registry keys/values for our 'WineTest'
173 * shell object. */
175
176 hr = SHGetDesktopFolder(&pDesktopFolder);
177 ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
178 if (FAILED(hr)) goto cleanup;
179
180 /* Convert the wszWineTestFolder string to an ITEMIDLIST. */
181 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
182 &pidlWineTestFolder, NULL);
184 {
186 "Expected %08x, got %08x\n", HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), hr);
187 }
188 if (FAILED(hr)) {
189 IShellFolder_Release(pDesktopFolder);
190 goto cleanup;
191 }
192
193 /* FIXME: these tests are never run */
194
195 /* Bind to a WineTest folder object. There has to be some support for this in shdocvw.dll.
196 * This isn't implemented in wine yet.*/
197 hr = IShellFolder_BindToObject(pDesktopFolder, pidlWineTestFolder, NULL, &IID_IShellFolder,
198 (LPVOID*)&pWineTestFolder);
199 IShellFolder_Release(pDesktopFolder);
200 ILFree(pidlWineTestFolder);
201 ok (SUCCEEDED(hr), "IShellFolder::BindToObject(WineTestFolder) failed! hr = %08x\n", hr);
202 if (FAILED(hr)) goto cleanup;
203
204 hr = IShellFolder_QueryInterface(pWineTestFolder, &IID_IPersistFolder3, (LPVOID*)&pWineTestPersistFolder);
205 ok (SUCCEEDED(hr), "IShellFolder::QueryInterface(IPersistFolder3) failed! hr = %08x\n", hr);
206 IShellFolder_Release(pWineTestFolder);
207 if (FAILED(hr)) goto cleanup;
208
209 /* The resulting folder object has the FolderShortcut CLSID, instead of its own. */
210 hr = IPersistFolder3_GetClassID(pWineTestPersistFolder, &clsid);
211 ok (SUCCEEDED(hr), "IPersist::GetClassID failed! hr = %08x\n", hr);
212 ok (IsEqualCLSID(&CLSID_FolderShortcut, &clsid), "GetClassId returned wrong CLSID!\n");
213
214 pidlCurFolder = (LPITEMIDLIST)0xdeadbeef;
215 hr = IPersistFolder3_GetCurFolder(pWineTestPersistFolder, &pidlCurFolder);
216 ok (SUCCEEDED(hr), "IPersistFolder3::GetCurFolder failed! hr = %08x\n", hr);
217 ok (pidlCurFolder->mkid.cb == 20 && ((LPSHITEMID)((BYTE*)pidlCurFolder+20))->cb == 0 &&
218 IsEqualCLSID(&CLSID_WineTest, (REFCLSID)((LPBYTE)pidlCurFolder+4)),
219 "GetCurFolder returned unexpected pidl!\n");
220
221 ILFree(pidlCurFolder);
222 IPersistFolder3_Release(pWineTestPersistFolder);
223
224cleanup:
226}
227
228START_TEST(shortcut)
229{
233}
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
#define ok(value,...)
Definition: atltest.h:57
#define START_TEST(x)
Definition: atltest.h:75
#define RegCloseKey(hKey)
Definition: registry.h:49
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LONG WINAPI RegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE *lpData, DWORD cbData)
Definition: reg.c:4799
LONG WINAPI RegOpenKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ DWORD ulOptions, _In_ REGSAM samDesired, _Out_ PHKEY phkResult)
Definition: reg.c:3298
LONG WINAPI RegCreateKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ DWORD Reserved, _In_ LPSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_ LPDWORD lpdwDisposition)
Definition: reg.c:1034
LONG WINAPI RegDeleteKeyA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey)
Definition: reg.c:1224
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
static void cleanup(void)
Definition: main.c:1335
HRESULT WINAPI DECLSPEC_HOTPATCH OleInitialize(LPVOID reserved)
Definition: ole2.c:169
void WINAPI DECLSPEC_HOTPATCH OleUninitialize(void)
Definition: ole2.c:230
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define REG_SZ
Definition: layer.c:22
#define todo_wine
Definition: custom.c:79
#define CLSID_WineTest
Definition: marshal.c:139
REFCLSID clsid
Definition: msctf.c:82
#define DELETE
Definition: nt_native.h:57
#define KEY_WRITE
Definition: nt_native.h:1031
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:938
static const WCHAR szName[]
Definition: powrprof.c:45
#define REFCLSID
Definition: guiddef.h:117
#define IsEqualCLSID(rclsid1, rclsid2)
Definition: guiddef.h:96
#define REG_DWORD
Definition: sdbapi.c:596
HRESULT hr
Definition: shlfolder.c:183
#define REG_VALUE_SIZE(x)
Definition: shortcut.c:62
static BOOL register_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys)
Definition: shortcut.c:116
static const struct registry_key ShortcutCLSID_keys[]
Definition: shortcut.c:99
static void test_ShortcutFolder(void)
Definition: shortcut.c:160
static const struct registry_value ShellFolder_values[]
Definition: shortcut.c:72
static const struct registry_value Instance_values[]
Definition: shortcut.c:77
static const struct registry_value InProcServer32_values[]
Definition: shortcut.c:90
static const struct registry_value DefaultIcon_values[]
Definition: shortcut.c:95
static const struct registry_value ShortcutCLSID_values[]
Definition: shortcut.c:106
#define REG_VALUE_ADDR(x)
Definition: shortcut.c:61
static const struct registry_value InitPropertyBag_values[]
Definition: shortcut.c:81
static const struct registry_key Instance_keys[]
Definition: shortcut.c:86
static const struct registry_key HKEY_CLASSES_ROOT_keys[]
Definition: shortcut.c:110
static void unregister_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys)
Definition: shortcut.c:147
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
const unsigned int cSubKeys
Definition: shortcut.c:69
const struct registry_value * pValues
Definition: shortcut.c:66
const unsigned int cValues
Definition: shortcut.c:67
const char * szName
Definition: shortcut.c:65
const struct registry_key * pSubKeys
Definition: shortcut.c:68
const DWORD dwType
Definition: shortcut.c:56
const char * szValue
Definition: shortcut.c:57
const char * szName
Definition: shortcut.c:55
const DWORD dwValue
Definition: shortcut.c:58
unsigned char * LPBYTE
Definition: typedefs.h:53
Definition: pdh_main.c:94
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92
#define HKEY_CLASSES_ROOT
Definition: winreg.h:10
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193