shell32/tests: Avoid SHDeleteKeyA() because shlwapi.dll is missing on Windows 95.
[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), debugstr_w(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)))
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 BOOL HCR_GetDefaultIconFromGUIDW(REFIID riid, LPWSTR szDest, DWORD len, int* picon_idx)
317 {
318         HKEY    hkey;
319         BOOL    ret = FALSE;
320
321         if (HCR_RegOpenClassIDKey(riid, &hkey))
322         {
323           ret = HCR_RegGetDefaultIconW(hkey, szDest, len, picon_idx);
324           RegCloseKey(hkey);
325         }
326         TRACE("-- %s %i\n", debugstr_w(szDest), *picon_idx);
327         return ret;
328 }
329
330 /***************************************************************************************
331 *       HCR_GetClassName        [internal]
332 *
333 * Gets the name of a registered class
334 */
335 static const WCHAR swEmpty[] = {0};
336
337 BOOL HCR_GetClassNameW(REFIID riid, LPWSTR szDest, DWORD len)
338 {       
339         HKEY    hkey;
340         BOOL ret = FALSE;
341         DWORD buflen = len;
342
343         szDest[0] = 0;
344         if (HCR_RegOpenClassIDKey(riid, &hkey))
345         {
346           static const WCHAR wszLocalizedString[] = 
347             { 'L','o','c','a','l','i','z','e','d','S','t','r','i','n','g', 0 };
348           if (!RegLoadMUIStringW(hkey, wszLocalizedString, szDest, len, NULL, 0, NULL) ||
349               !RegQueryValueExW(hkey, swEmpty, 0, NULL, (LPBYTE)szDest, &len))
350           {
351             ret = TRUE;
352           }
353           RegCloseKey(hkey);
354         }
355
356         if (!ret || !szDest[0])
357         {
358           if(IsEqualIID(riid, &CLSID_ShellDesktop))
359           {
360             if (LoadStringW(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
361               ret = TRUE;
362           }
363           else if (IsEqualIID(riid, &CLSID_MyComputer))
364           {
365             if(LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
366               ret = TRUE;
367           }
368         }
369         TRACE("-- %s\n", debugstr_w(szDest));
370         return ret;
371 }
372
373 BOOL HCR_GetClassNameA(REFIID riid, LPSTR szDest, DWORD len)
374 {       HKEY    hkey;
375         BOOL ret = FALSE;
376         DWORD buflen = len;
377
378         szDest[0] = 0;
379         if (HCR_RegOpenClassIDKey(riid, &hkey))
380         {
381           if (!RegLoadMUIStringA(hkey,"LocalizedString",szDest,len,NULL,0,NULL) ||
382               !RegQueryValueExA(hkey,"",0,NULL,(LPBYTE)szDest,&len))
383           {
384             ret = TRUE;
385           }
386           RegCloseKey(hkey);
387         }
388
389         if (!ret || !szDest[0])
390         {
391           if(IsEqualIID(riid, &CLSID_ShellDesktop))
392           {
393             if (LoadStringA(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
394               ret = TRUE;
395           }
396           else if (IsEqualIID(riid, &CLSID_MyComputer))
397           {
398             if(LoadStringA(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
399               ret = TRUE;
400           }
401         }
402
403         TRACE("-- %s\n", szDest);
404
405         return ret;
406 }
407
408 /******************************************************************************
409  * HCR_GetFolderAttributes [Internal]
410  *
411  * Query the registry for a shell folders' attributes
412  *
413  * PARAMS
414  *  pidlFolder    [I]  A simple pidl of type PT_GUID. 
415  *  pdwAttributes [IO] In: Attributes to be queried, OUT: Resulting attributes.
416  *
417  * RETURNS
418  *  TRUE:  Found information for the attributes in the registry
419  *  FALSE: No attribute information found
420  *
421  * NOTES
422  *  If queried for an attribute, which is set in the CallForAttributes registry
423  *  value, the function binds to the shellfolder objects and queries it.
424  */
425 BOOL HCR_GetFolderAttributes(LPCITEMIDLIST pidlFolder, LPDWORD pdwAttributes)
426 {
427     HKEY hSFKey;
428     LPOLESTR pwszCLSID;
429     LONG lResult;
430     DWORD dwTemp, dwLen;
431     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
432     static const WCHAR wszCallForAttributes[] = { 
433         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
434     WCHAR wszShellFolderKey[] = { 'C','L','S','I','D','\\','{','0','0','0','2','1','4','0','0','-',
435         '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0','0',
436         '0','0','0','4','6','}','\\','S','h','e','l','l','F','o','l','d','e','r',0 };
437
438     TRACE("(pidlFolder=%p, pdwAttributes=%p)\n", pidlFolder, pdwAttributes);
439        
440     if (!_ILIsPidlSimple(pidlFolder)) { 
441         ERR("HCR_GetFolderAttributes should be called for simple PIDL's only!\n");    
442         return FALSE;
443     }
444     
445     if (!_ILIsDesktop(pidlFolder)) {
446         if (FAILED(StringFromCLSID(_ILGetGUIDPointer(pidlFolder), &pwszCLSID))) return FALSE;
447         memcpy(&wszShellFolderKey[6], pwszCLSID, 38 * sizeof(WCHAR));
448         CoTaskMemFree(pwszCLSID);
449     }
450     
451     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszShellFolderKey, 0, KEY_READ, &hSFKey);
452     if (lResult != ERROR_SUCCESS) return FALSE;
453     
454     dwLen = sizeof(DWORD);
455     lResult = RegQueryValueExW(hSFKey, wszCallForAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
456     if ((lResult == ERROR_SUCCESS) && (dwTemp & *pdwAttributes)) {
457         LPSHELLFOLDER psfDesktop, psfFolder;
458         HRESULT hr;
459
460         RegCloseKey(hSFKey);
461         hr = SHGetDesktopFolder(&psfDesktop);
462         if (SUCCEEDED(hr)) {
463             hr = IShellFolder_BindToObject(psfDesktop, pidlFolder, NULL, &IID_IShellFolder, 
464                                            (LPVOID*)&psfFolder);
465             if (SUCCEEDED(hr)) { 
466                 hr = IShellFolder_GetAttributesOf(psfFolder, 0, NULL, pdwAttributes);
467                 IShellFolder_Release(psfFolder);
468             }
469             IShellFolder_Release(psfDesktop);
470         }
471         if (FAILED(hr)) return FALSE;
472     } else {
473         lResult = RegQueryValueExW(hSFKey, wszAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
474         RegCloseKey(hSFKey);
475         if (lResult == ERROR_SUCCESS) {
476             *pdwAttributes &= dwTemp;
477         } else {
478             return FALSE;
479         }
480     }
481
482     TRACE("-- *pdwAttributes == 0x%08x\n", *pdwAttributes);
483
484     return TRUE;
485 }