shell32/tests: Fix a test failure on Vista and higher.
[wine] / dlls / shell32 / classes.c
1 /*
2  *      file type mapping
3  *      (HKEY_CLASSES_ROOT - Stuff)
4  *
5  * Copyright 1998, 1999, 2000 Juergen Schmied
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #define COBJMACROS
31
32 #include "wine/debug.h"
33 #include "winerror.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winreg.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39
40 #include "shlobj.h"
41 #include "shell32_main.h"
42 #include "shlguid.h"
43 #include "shresdef.h"
44 #include "shlwapi.h"
45 #include "pidl.h"
46 #include "wine/unicode.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49
50 #define MAX_EXTENSION_LENGTH 20
51
52 BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG len, BOOL bPrependDot)
53 {       
54         HKEY    hkey;
55         WCHAR   szTemp[MAX_EXTENSION_LENGTH + 2];
56
57         TRACE("%s %p\n", debugstr_w(szExtension), szFileType);
58
59     /* added because we do not want to have double dots */
60     if (szExtension[0] == '.')
61         bPrependDot = 0;
62
63         if (bPrependDot)
64           szTemp[0] = '.';
65
66         lstrcpynW(szTemp + (bPrependDot?1:0), szExtension, MAX_EXTENSION_LENGTH);
67
68         if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkey))
69         { 
70           return FALSE;
71         }
72
73         if (RegQueryValueW(hkey, NULL, szFileType, &len))
74         { 
75           RegCloseKey(hkey);
76           return FALSE;
77         }
78
79         RegCloseKey(hkey);
80
81         TRACE("--UE;\n} %s\n", debugstr_w(szFileType));
82
83         return TRUE;
84 }
85
86 BOOL HCR_MapTypeToValueA(LPCSTR szExtension, LPSTR szFileType, LONG len, BOOL bPrependDot)
87 {
88         HKEY    hkey;
89         char    szTemp[MAX_EXTENSION_LENGTH + 2];
90
91         TRACE("%s %p\n", szExtension, szFileType);
92
93     /* added because we do not want to have double dots */
94     if (szExtension[0] == '.')
95         bPrependDot = 0;
96
97         if (bPrependDot)
98           szTemp[0] = '.';
99
100         lstrcpynA(szTemp + (bPrependDot?1:0), szExtension, MAX_EXTENSION_LENGTH);
101
102         if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkey))
103         { 
104           return FALSE;
105         }
106
107         if (RegQueryValueA(hkey, NULL, szFileType, &len))
108         { 
109           RegCloseKey(hkey);
110           return FALSE;
111         }
112
113         RegCloseKey(hkey);
114
115         TRACE("--UE;\n} %s\n", szFileType);
116
117         return TRUE;
118 }
119
120 static const WCHAR swShell[] = {'s','h','e','l','l','\\',0};
121 static const WCHAR swOpen[] = {'o','p','e','n',0};
122 static const WCHAR swCommand[] = {'\\','c','o','m','m','a','n','d',0};
123
124 BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
125 {
126         WCHAR sTemp[MAX_PATH];
127         LONG size;
128         HKEY hkey;
129
130         TRACE("%p %s %p\n", hkeyClass, debugstr_w(szVerb), szDest);
131
132         if (szVerb)
133         {
134             lstrcpynW(szDest, szVerb, len);
135             return TRUE;
136         }
137
138         size=len;
139         *szDest='\0';
140         if (!RegQueryValueW(hkeyClass, swShell, szDest, &size) && *szDest)
141         {
142             /* The MSDN says to first try the default verb */
143             lstrcpyW(sTemp, swShell);
144             lstrcatW(sTemp, szDest);
145             lstrcatW(sTemp, swCommand);
146             if (!RegOpenKeyExW(hkeyClass, sTemp, 0, 0, &hkey))
147             {
148                 RegCloseKey(hkey);
149                 TRACE("default verb=%s\n", debugstr_w(szDest));
150                 return TRUE;
151             }
152         }
153
154         /* then fallback to 'open' */
155         lstrcpyW(sTemp, swShell);
156         lstrcatW(sTemp, swOpen);
157         lstrcatW(sTemp, swCommand);
158         if (!RegOpenKeyExW(hkeyClass, sTemp, 0, 0, &hkey))
159         {
160             RegCloseKey(hkey);
161             lstrcpynW(szDest, swOpen, len);
162             TRACE("default verb=open\n");
163             return TRUE;
164         }
165
166         /* and then just use the first verb on Windows >= 2000 */
167         if (!RegEnumKeyW(hkeyClass, 0, szDest, len) && *szDest)
168         {
169             TRACE("default verb=first verb=%s\n", debugstr_w(szDest));
170             return TRUE;
171         }
172
173         TRACE("no default verb!\n");
174         return FALSE;
175 }
176
177 BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
178 {
179         WCHAR sTempVerb[MAX_PATH];
180         BOOL ret;
181
182         TRACE("%p %s %s %p\n", hkeyClass, debugstr_w(szClass), debugstr_w(szVerb), szDest);
183
184         if (szClass)
185             RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, KEY_READ, &hkeyClass);
186         if (!hkeyClass)
187             return FALSE;
188         ret = FALSE;
189
190         if (HCR_GetDefaultVerbW(hkeyClass, szVerb, sTempVerb, sizeof(sTempVerb)/sizeof(sTempVerb[0])))
191         {
192             WCHAR sTemp[MAX_PATH];
193             lstrcpyW(sTemp, swShell);
194             lstrcatW(sTemp, sTempVerb);
195             lstrcatW(sTemp, swCommand);
196             ret = (ERROR_SUCCESS == SHGetValueW(hkeyClass, sTemp, NULL, NULL, szDest, &len));
197         }
198         if (szClass)
199             RegCloseKey(hkeyClass);
200
201         TRACE("-- %s\n", debugstr_w(szDest) );
202         return ret;
203 }
204
205 /***************************************************************************************
206 *       HCR_GetDefaultIcon      [internal]
207 *
208 * Gets the icon for a filetype
209 */
210 static BOOL HCR_RegOpenClassIDKey(REFIID riid, HKEY *hkey)
211 {
212         char    xriid[50];
213     sprintf( xriid, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
214                  riid->Data1, riid->Data2, riid->Data3,
215                  riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
216                  riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] );
217
218         TRACE("%s\n",xriid );
219
220         return !RegOpenKeyExA(HKEY_CLASSES_ROOT, xriid, 0, KEY_READ, hkey);
221 }
222
223 static BOOL HCR_RegGetDefaultIconW(HKEY hkey, LPWSTR szDest, DWORD len, int* picon_idx)
224 {
225     DWORD dwType;
226     WCHAR sTemp[MAX_PATH];
227     WCHAR sNum[5];
228
229     if (!RegQueryValueExW(hkey, NULL, 0, &dwType, (LPBYTE)szDest, &len))
230     {
231       if (dwType == REG_EXPAND_SZ)
232       {
233         ExpandEnvironmentStringsW(szDest, sTemp, MAX_PATH);
234         lstrcpynW(szDest, sTemp, len);
235       }
236       if (ParseFieldW (szDest, 2, sNum, 5))
237              *picon_idx = atoiW(sNum);
238           else
239              *picon_idx=0; /* sometimes the icon number is missing */
240       ParseFieldW (szDest, 1, szDest, len);
241           PathUnquoteSpacesW(szDest);
242       return TRUE;
243     }
244     return FALSE;
245 }
246
247 static BOOL HCR_RegGetDefaultIconA(HKEY hkey, LPSTR szDest, DWORD len, int* picon_idx)
248 {
249         DWORD dwType;
250         char sTemp[MAX_PATH];
251         char  sNum[5];
252
253         if (!RegQueryValueExA(hkey, NULL, 0, &dwType, (LPBYTE)szDest, &len))
254         {
255       if (dwType == REG_EXPAND_SZ)
256           {
257             ExpandEnvironmentStringsA(szDest, sTemp, MAX_PATH);
258             lstrcpynA(szDest, sTemp, len);
259           }
260           if (ParseFieldA (szDest, 2, sNum, 5))
261              *picon_idx=atoi(sNum);
262           else
263              *picon_idx=0; /* sometimes the icon number is missing */
264           ParseFieldA (szDest, 1, szDest, len);
265           PathUnquoteSpacesA(szDest);
266           return TRUE;
267         }
268         return FALSE;
269 }
270
271 BOOL HCR_GetDefaultIconW(LPCWSTR szClass, LPWSTR szDest, DWORD len, int* picon_idx)
272 {
273         static const WCHAR swDefaultIcon[] = {'\\','D','e','f','a','u','l','t','I','c','o','n',0};
274         HKEY    hkey;
275         WCHAR   sTemp[MAX_PATH];
276         BOOL    ret = FALSE;
277
278         TRACE("%s\n",debugstr_w(szClass) );
279
280         lstrcpynW(sTemp, szClass, MAX_PATH);
281         lstrcatW(sTemp, swDefaultIcon);
282
283         if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, sTemp, 0, KEY_READ, &hkey))
284         {
285           ret = HCR_RegGetDefaultIconW(hkey, szDest, len, picon_idx);
286           RegCloseKey(hkey);
287         }
288
289         if(ret)
290             TRACE("-- %s %i\n", debugstr_w(szDest), *picon_idx);
291         else
292             TRACE("-- not found\n");
293
294         return ret;
295 }
296
297 BOOL HCR_GetDefaultIconA(LPCSTR szClass, LPSTR szDest, DWORD len, int* picon_idx)
298 {
299         HKEY    hkey;
300         char    sTemp[MAX_PATH];
301         BOOL    ret = FALSE;
302
303         TRACE("%s\n",szClass );
304
305         sprintf(sTemp, "%s\\DefaultIcon",szClass);
306
307         if (!RegOpenKeyExA(HKEY_CLASSES_ROOT, sTemp, 0, KEY_READ, &hkey))
308         {
309           ret = HCR_RegGetDefaultIconA(hkey, szDest, len, picon_idx);
310           RegCloseKey(hkey);
311         }
312         TRACE("-- %s %i\n", szDest, *picon_idx);
313         return ret;
314 }
315
316 /***************************************************************************************
317 *       HCR_GetClassName        [internal]
318 *
319 * Gets the name of a registered class
320 */
321 static const WCHAR swEmpty[] = {0};
322
323 BOOL HCR_GetClassNameW(REFIID riid, LPWSTR szDest, DWORD len)
324 {       
325         HKEY    hkey;
326         BOOL ret = FALSE;
327         DWORD buflen = len;
328
329         szDest[0] = 0;
330         if (HCR_RegOpenClassIDKey(riid, &hkey))
331         {
332           static const WCHAR wszLocalizedString[] = 
333             { 'L','o','c','a','l','i','z','e','d','S','t','r','i','n','g', 0 };
334           if (!RegLoadMUIStringW(hkey, wszLocalizedString, szDest, len, NULL, 0, NULL) ||
335               !RegQueryValueExW(hkey, swEmpty, 0, NULL, (LPBYTE)szDest, &len))
336           {
337             ret = TRUE;
338           }
339           RegCloseKey(hkey);
340         }
341
342         if (!ret || !szDest[0])
343         {
344           if(IsEqualIID(riid, &CLSID_ShellDesktop))
345           {
346             if (LoadStringW(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
347               ret = TRUE;
348           }
349           else if (IsEqualIID(riid, &CLSID_MyComputer))
350           {
351             if(LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
352               ret = TRUE;
353           }
354         }
355         TRACE("-- %s\n", debugstr_w(szDest));
356         return ret;
357 }
358
359 BOOL HCR_GetClassNameA(REFIID riid, LPSTR szDest, DWORD len)
360 {       HKEY    hkey;
361         BOOL ret = FALSE;
362         DWORD buflen = len;
363
364         szDest[0] = 0;
365         if (HCR_RegOpenClassIDKey(riid, &hkey))
366         {
367           if (!RegLoadMUIStringA(hkey,"LocalizedString",szDest,len,NULL,0,NULL) ||
368               !RegQueryValueExA(hkey,"",0,NULL,(LPBYTE)szDest,&len))
369           {
370             ret = TRUE;
371           }
372           RegCloseKey(hkey);
373         }
374
375         if (!ret || !szDest[0])
376         {
377           if(IsEqualIID(riid, &CLSID_ShellDesktop))
378           {
379             if (LoadStringA(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
380               ret = TRUE;
381           }
382           else if (IsEqualIID(riid, &CLSID_MyComputer))
383           {
384             if(LoadStringA(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
385               ret = TRUE;
386           }
387         }
388
389         TRACE("-- %s\n", szDest);
390
391         return ret;
392 }
393
394 /******************************************************************************
395  * HCR_GetFolderAttributes [Internal]
396  *
397  * Query the registry for a shell folders' attributes
398  *
399  * PARAMS
400  *  pidlFolder    [I]  A simple pidl of type PT_GUID. 
401  *  pdwAttributes [IO] In: Attributes to be queried, OUT: Resulting attributes.
402  *
403  * RETURNS
404  *  TRUE:  Found information for the attributes in the registry
405  *  FALSE: No attribute information found
406  *
407  * NOTES
408  *  If queried for an attribute, which is set in the CallForAttributes registry
409  *  value, the function binds to the shellfolder objects and queries it.
410  */
411 BOOL HCR_GetFolderAttributes(LPCITEMIDLIST pidlFolder, LPDWORD pdwAttributes)
412 {
413     HKEY hSFKey;
414     LPOLESTR pwszCLSID;
415     LONG lResult;
416     DWORD dwTemp, dwLen;
417     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
418     static const WCHAR wszCallForAttributes[] = { 
419         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
420     WCHAR wszShellFolderKey[] = { 'C','L','S','I','D','\\','{','0','0','0','2','1','4','0','0','-',
421         '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0','0',
422         '0','0','0','4','6','}','\\','S','h','e','l','l','F','o','l','d','e','r',0 };
423
424     TRACE("(pidlFolder=%p, pdwAttributes=%p)\n", pidlFolder, pdwAttributes);
425        
426     if (!_ILIsPidlSimple(pidlFolder)) { 
427         static int firstHit = 1;
428         if (firstHit) {
429             ERR("HCR_GetFolderAttributes should be called for simple PIDL's only!\n");
430             firstHit = 0;
431         }
432         return FALSE;
433     }
434     
435     if (!_ILIsDesktop(pidlFolder)) {
436         if (FAILED(StringFromCLSID(_ILGetGUIDPointer(pidlFolder), &pwszCLSID))) return FALSE;
437         memcpy(&wszShellFolderKey[6], pwszCLSID, 38 * sizeof(WCHAR));
438         CoTaskMemFree(pwszCLSID);
439     }
440     
441     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszShellFolderKey, 0, KEY_READ, &hSFKey);
442     if (lResult != ERROR_SUCCESS) return FALSE;
443     
444     dwLen = sizeof(DWORD);
445     lResult = RegQueryValueExW(hSFKey, wszCallForAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
446     if ((lResult == ERROR_SUCCESS) && (dwTemp & *pdwAttributes)) {
447         LPSHELLFOLDER psfDesktop, psfFolder;
448         HRESULT hr;
449
450         RegCloseKey(hSFKey);
451         hr = SHGetDesktopFolder(&psfDesktop);
452         if (SUCCEEDED(hr)) {
453             hr = IShellFolder_BindToObject(psfDesktop, pidlFolder, NULL, &IID_IShellFolder, 
454                                            (LPVOID*)&psfFolder);
455             if (SUCCEEDED(hr)) { 
456                 hr = IShellFolder_GetAttributesOf(psfFolder, 0, NULL, pdwAttributes);
457                 IShellFolder_Release(psfFolder);
458             }
459             IShellFolder_Release(psfDesktop);
460         }
461         if (FAILED(hr)) return FALSE;
462     } else {
463         lResult = RegQueryValueExW(hSFKey, wszAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
464         RegCloseKey(hSFKey);
465         if (lResult == ERROR_SUCCESS) {
466             *pdwAttributes &= dwTemp;
467         } else {
468             return FALSE;
469         }
470     }
471
472     TRACE("-- *pdwAttributes == 0x%08x\n", *pdwAttributes);
473
474     return TRUE;
475 }