xref: /reactos/dll/win32/shell32/wine/classes.c (revision 84ccccab)
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 <wine/config.h>
23 
24 #include <stdio.h>
25 
26 #define WIN32_NO_STATUS
27 #define _INC_WINDOWS
28 #define COBJMACROS
29 
30 #include <windef.h>
31 #include <winbase.h>
32 #include <shlobj.h>
33 #include <shlguid_undoc.h>
34 #include <shlwapi.h>
35 #include <wine/debug.h>
36 #include <wine/unicode.h>
37 
38 #include "pidl.h"
39 #include "shell32_main.h"
40 #include "shresdef.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(shell);
43 
44 #define MAX_EXTENSION_LENGTH 20
45 
46 BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG len, BOOL bPrependDot)
47 {
48 	HKEY	hkey;
49 	WCHAR	szTemp[MAX_EXTENSION_LENGTH + 2];
50 
51 	TRACE("%s %p\n", debugstr_w(szExtension), szFileType);
52 
53         /* added because we do not want to have double dots */
54         if (szExtension[0] == '.')
55           bPrependDot = FALSE;
56 
57 	if (bPrependDot)
58 	  szTemp[0] = '.';
59 
60 	lstrcpynW(szTemp + (bPrependDot?1:0), szExtension, MAX_EXTENSION_LENGTH);
61 
62 	if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkey))
63 	{
64 	  return FALSE;
65 	}
66 
67 #ifdef __REACTOS__
68         if (!RegLoadMUIStringW(hkey, L"FriendlyTypeName", szFileType, len, NULL, 0, NULL))
69         {
70             RegCloseKey(hkey);
71             return TRUE;
72         }
73 #endif
74 
75 	if (RegQueryValueW(hkey, NULL, szFileType, &len))
76 	{
77 	  RegCloseKey(hkey);
78 	  return FALSE;
79 	}
80 
81 	RegCloseKey(hkey);
82 
83 	TRACE("--UE;\n} %s\n", debugstr_w(szFileType));
84 
85 	return TRUE;
86 }
87 
88 BOOL HCR_MapTypeToValueA(LPCSTR szExtension, LPSTR szFileType, LONG len, BOOL bPrependDot)
89 {
90 	HKEY	hkey;
91 	char	szTemp[MAX_EXTENSION_LENGTH + 2];
92 
93 	TRACE("%s %p\n", szExtension, szFileType);
94 
95         /* added because we do not want to have double dots */
96         if (szExtension[0] == '.')
97           bPrependDot = FALSE;
98 
99 	if (bPrependDot)
100 	  szTemp[0] = '.';
101 
102 	lstrcpynA(szTemp + (bPrependDot?1:0), szExtension, MAX_EXTENSION_LENGTH);
103 
104 	if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkey))
105 	{
106 	  return FALSE;
107 	}
108 
109 #ifdef __REACTOS__
110         if (!RegLoadMUIStringA(hkey, "FriendlyTypeName", szFileType, len, NULL, 0, NULL))
111         {
112             RegCloseKey(hkey);
113             return TRUE;
114         }
115 #endif
116 
117 	if (RegQueryValueA(hkey, NULL, szFileType, &len))
118 	{
119 	  RegCloseKey(hkey);
120 	  return FALSE;
121 	}
122 
123 	RegCloseKey(hkey);
124 
125 	TRACE("--UE;\n} %s\n", szFileType);
126 
127 	return TRUE;
128 }
129 
130 static const WCHAR swShell[] = {'s','h','e','l','l','\\',0};
131 static const WCHAR swOpen[] = {'o','p','e','n',0};
132 static const WCHAR swCommand[] = {'\\','c','o','m','m','a','n','d',0};
133 
134 BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
135 {
136         WCHAR sTemp[MAX_PATH];
137         LONG size;
138         HKEY hkey;
139 
140 	TRACE("%p %s %p\n", hkeyClass, debugstr_w(szVerb), szDest);
141 
142         if (szVerb && *szVerb)
143         {
144             lstrcpynW(szDest, szVerb, len);
145             return TRUE;
146         }
147 
148         size=len;
149         *szDest='\0';
150         if (!RegQueryValueW(hkeyClass, swShell, szDest, &size) && *szDest)
151         {
152             /* The MSDN says to first try the default verb */
153             lstrcpyW(sTemp, swShell);
154             lstrcatW(sTemp, szDest);
155             lstrcatW(sTemp, swCommand);
156             if (!RegOpenKeyExW(hkeyClass, sTemp, 0, KEY_READ, &hkey))
157             {
158                 RegCloseKey(hkey);
159                 TRACE("default verb=%s\n", debugstr_w(szDest));
160                 return TRUE;
161             }
162         }
163 
164         /* then fallback to 'open' */
165         lstrcpyW(sTemp, swShell);
166         lstrcatW(sTemp, swOpen);
167         lstrcatW(sTemp, swCommand);
168         if (!RegOpenKeyExW(hkeyClass, sTemp, 0, KEY_READ, &hkey))
169         {
170             RegCloseKey(hkey);
171             lstrcpynW(szDest, swOpen, len);
172             TRACE("default verb=open\n");
173             return TRUE;
174         }
175 
176         /* and then just use the first verb on Windows >= 2000 */
177 #ifdef __REACTOS__
178         if (!RegOpenKeyExW(hkeyClass, L"shell", 0, KEY_READ, &hkey))
179         {
180             if (!RegEnumKeyW(hkey, 0, szDest, len) && *szDest)
181             {
182                 TRACE("default verb=first verb=%s\n", debugstr_w(szDest));
183                 RegCloseKey(hkey);
184                 return TRUE;
185             }
186             RegCloseKey(hkey);
187         }
188 #else
189         if (!RegEnumKeyW(hkeyClass, 0, szDest, len) && *szDest)
190         {
191             TRACE("default verb=first verb=%s\n", debugstr_w(szDest));
192             return TRUE;
193         }
194 #endif
195 
196         TRACE("no default verb!\n");
197 	return FALSE;
198 }
199 
200 BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len )
201 {
202 	WCHAR sTempVerb[MAX_PATH];
203 	BOOL ret;
204 
205 	TRACE("%p %s %s %p\n", hkeyClass, debugstr_w(szClass), debugstr_w(szVerb), szDest);
206 
207 	if (szClass)
208             RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, KEY_READ, &hkeyClass);
209         if (!hkeyClass)
210             return FALSE;
211         ret = FALSE;
212 
213         if (HCR_GetDefaultVerbW(hkeyClass, szVerb, sTempVerb, sizeof(sTempVerb)/sizeof(sTempVerb[0])))
214         {
215             WCHAR sTemp[MAX_PATH];
216             lstrcpyW(sTemp, swShell);
217             lstrcatW(sTemp, sTempVerb);
218             lstrcatW(sTemp, swCommand);
219             ret = (ERROR_SUCCESS == SHGetValueW(hkeyClass, sTemp, NULL, NULL, szDest, &len));
220         }
221         if (szClass)
222             RegCloseKey(hkeyClass);
223 
224 	TRACE("-- %s\n", debugstr_w(szDest) );
225 	return ret;
226 }
227 
228 /***************************************************************************************
229 *	HCR_GetDefaultIcon	[internal]
230 *
231 * Gets the icon for a filetype
232 */
233 BOOL HCR_RegOpenClassIDKey(REFIID riid, HKEY *hkey)
234 {
235 	char	xriid[50];
236     sprintf( xriid, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
237                  riid->Data1, riid->Data2, riid->Data3,
238                  riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
239                  riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] );
240 
241  	TRACE("%s\n",xriid );
242 
243 	return !RegOpenKeyExA(HKEY_CLASSES_ROOT, xriid, 0, KEY_READ, hkey);
244 }
245 
246 static BOOL HCR_RegGetIconW(HKEY hkey, LPWSTR szDest, LPCWSTR szName, DWORD len, int* picon_idx)
247 {
248     DWORD dwType;
249     WCHAR sTemp[MAX_PATH];
250     WCHAR sNum[7];
251 
252     if (!RegQueryValueExW(hkey, szName, 0, &dwType, (LPBYTE)szDest, &len))
253     {
254       if (dwType == REG_EXPAND_SZ)
255       {
256         ExpandEnvironmentStringsW(szDest, sTemp, MAX_PATH);
257         lstrcpynW(szDest, sTemp, len);
258       }
259         if (ParseFieldW (szDest, 2, sNum, _countof(sNum)))
260              *picon_idx = atoiW(sNum);
261           else
262              *picon_idx=0; /* sometimes the icon number is missing */
263       ParseFieldW (szDest, 1, szDest, len);
264           PathUnquoteSpacesW(szDest);
265       return TRUE;
266     }
267     return FALSE;
268 }
269 
270 static BOOL HCR_RegGetIconA(HKEY hkey, LPSTR szDest, LPCSTR szName, DWORD len, int* picon_idx)
271 {
272 	DWORD dwType;
273 	char sTemp[MAX_PATH];
274 	char  sNum[5];
275 
276 	if (!RegQueryValueExA(hkey, szName, 0, &dwType, (LPBYTE)szDest, &len))
277 	{
278           if (dwType == REG_EXPAND_SZ)
279 	  {
280 	    ExpandEnvironmentStringsA(szDest, sTemp, MAX_PATH);
281 	    lstrcpynA(szDest, sTemp, len);
282 	  }
283 	  if (ParseFieldA (szDest, 2, sNum, 5))
284              *picon_idx=atoi(sNum);
285           else
286              *picon_idx=0; /* sometimes the icon number is missing */
287 	  ParseFieldA (szDest, 1, szDest, len);
288           PathUnquoteSpacesA(szDest);
289 	  return TRUE;
290 	}
291 	return FALSE;
292 }
293 
294 BOOL HCR_GetIconW(LPCWSTR szClass, LPWSTR szDest, LPCWSTR szName, DWORD len, int* picon_idx)
295 {
296         static const WCHAR swDefaultIcon[] = {'\\','D','e','f','a','u','l','t','I','c','o','n',0};
297 	HKEY	hkey;
298 	WCHAR	sTemp[MAX_PATH];
299 	BOOL	ret = FALSE;
300 
301 	TRACE("%s\n",debugstr_w(szClass) );
302 
303 	lstrcpynW(sTemp, szClass, MAX_PATH);
304 	lstrcatW(sTemp, swDefaultIcon);
305 
306 	if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, sTemp, 0, KEY_READ, &hkey))
307 	{
308 	  ret = HCR_RegGetIconW(hkey, szDest, szName, len, picon_idx);
309 	  RegCloseKey(hkey);
310 	}
311 
312         if(ret)
313             TRACE("-- %s %i\n", debugstr_w(szDest), *picon_idx);
314         else
315             TRACE("-- not found\n");
316 
317 	return ret;
318 }
319 
320 BOOL HCR_GetIconA(LPCSTR szClass, LPSTR szDest, LPCSTR szName, DWORD len, int* picon_idx)
321 {
322 	HKEY	hkey;
323 	char	sTemp[MAX_PATH];
324 	BOOL	ret = FALSE;
325 
326 	TRACE("%s\n",szClass );
327 
328 	sprintf(sTemp, "%s\\DefaultIcon",szClass);
329 
330 	if (!RegOpenKeyExA(HKEY_CLASSES_ROOT, sTemp, 0, KEY_READ, &hkey))
331 	{
332 	  ret = HCR_RegGetIconA(hkey, szDest, szName, len, picon_idx);
333 	  RegCloseKey(hkey);
334 	}
335 	TRACE("-- %s %i\n", szDest, *picon_idx);
336 	return ret;
337 }
338 
339 /***************************************************************************************
340 *	HCR_GetClassName	[internal]
341 *
342 * Gets the name of a registered class
343 */
344 static const WCHAR swEmpty[] = {0};
345 
346 BOOL HCR_GetClassNameW(REFIID riid, LPWSTR szDest, DWORD len)
347 {
348 	HKEY	hkey;
349 	BOOL ret = FALSE;
350 	DWORD buflen = len;
351 #ifdef __REACTOS__
352         WCHAR szName[100];
353         LPOLESTR pStr;
354 #endif
355 
356  	szDest[0] = 0;
357 
358 #ifdef __REACTOS__
359         if (StringFromCLSID(riid, &pStr) == S_OK)
360         {
361             DWORD dwLen = buflen * sizeof(WCHAR);
362             swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr);
363             if (!RegGetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, NULL, (PVOID)szDest, &dwLen))
364             {
365                 ret = TRUE;
366             }
367             CoTaskMemFree(pStr);
368         }
369         if (!ret && HCR_RegOpenClassIDKey(riid, &hkey))
370 #else
371 	if (HCR_RegOpenClassIDKey(riid, &hkey))
372 #endif
373 	{
374           static const WCHAR wszLocalizedString[] =
375             { 'L','o','c','a','l','i','z','e','d','S','t','r','i','n','g', 0 };
376           if (!RegLoadMUIStringW(hkey, wszLocalizedString, szDest, len, NULL, 0, NULL) ||
377               !RegQueryValueExW(hkey, swEmpty, 0, NULL, (LPBYTE)szDest, &len))
378           {
379 	    ret = TRUE;
380 	  }
381 	  RegCloseKey(hkey);
382 	}
383 
384 	if (!ret || !szDest[0])
385 	{
386 	  if(IsEqualIID(riid, &CLSID_ShellDesktop))
387 	  {
388 	    if (LoadStringW(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
389 	      ret = TRUE;
390 	  }
391 	  else if (IsEqualIID(riid, &CLSID_MyComputer))
392 	  {
393 	    if(LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
394 	      ret = TRUE;
395 	  }
396 #ifdef __REACTOS__
397           else if (IsEqualIID(riid, &CLSID_MyDocuments))
398           {
399               if(LoadStringW(shell32_hInstance, IDS_PERSONAL, szDest, buflen))
400                   ret = TRUE;
401           }
402           else if (IsEqualIID(riid, &CLSID_RecycleBin))
403           {
404               if(LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_FOLDER_NAME, szDest, buflen))
405                   ret = TRUE;
406           }
407           else if (IsEqualIID(riid, &CLSID_ControlPanel))
408           {
409               if(LoadStringW(shell32_hInstance, IDS_CONTROLPANEL, szDest, buflen))
410                   ret = TRUE;
411           }
412           else if (IsEqualIID(riid, &CLSID_AdminFolderShortcut))
413           {
414               if(LoadStringW(shell32_hInstance, IDS_ADMINISTRATIVETOOLS, szDest, buflen))
415                   ret = TRUE;
416           }
417 #endif
418 	}
419 	TRACE("-- %s\n", debugstr_w(szDest));
420 	return ret;
421 }
422 
423 BOOL HCR_GetClassNameA(REFIID riid, LPSTR szDest, DWORD len)
424 {	HKEY	hkey;
425 	BOOL ret = FALSE;
426 	DWORD buflen = len;
427 #ifdef __REACTOS__
428         CHAR szName[100];
429         LPOLESTR pStr;
430 #endif
431 
432 	szDest[0] = 0;
433 
434 #ifdef __REACTOS__
435         if (StringFromCLSID(riid, &pStr) == S_OK)
436         {
437             DWORD dwLen = buflen * sizeof(CHAR);
438             sprintf(szName, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%S", pStr);
439             if (!RegGetValueA(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, NULL, (PVOID)szDest, &dwLen))
440             {
441                 ret = TRUE;
442             }
443             CoTaskMemFree(pStr);
444         }
445         if (!ret && HCR_RegOpenClassIDKey(riid, &hkey))
446 #else
447 	if (HCR_RegOpenClassIDKey(riid, &hkey))
448 #endif
449 	{
450           if (!RegLoadMUIStringA(hkey,"LocalizedString",szDest,len,NULL,0,NULL) ||
451               !RegQueryValueExA(hkey,"",0,NULL,(LPBYTE)szDest,&len))
452           {
453 	    ret = TRUE;
454 	  }
455 	  RegCloseKey(hkey);
456 	}
457 
458 	if (!ret || !szDest[0])
459 	{
460 	  if(IsEqualIID(riid, &CLSID_ShellDesktop))
461 	  {
462 	    if (LoadStringA(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
463 	      ret = TRUE;
464 	  }
465 	  else if (IsEqualIID(riid, &CLSID_MyComputer))
466 	  {
467 	    if(LoadStringA(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
468 	      ret = TRUE;
469 	  }
470 #ifdef __REACTOS__
471           else if (IsEqualIID(riid, &CLSID_MyDocuments))
472           {
473               if(LoadStringA(shell32_hInstance, IDS_PERSONAL, szDest, buflen))
474                   ret = TRUE;
475           }
476           else if (IsEqualIID(riid, &CLSID_RecycleBin))
477           {
478               if(LoadStringA(shell32_hInstance, IDS_RECYCLEBIN_FOLDER_NAME, szDest, buflen))
479                   ret = TRUE;
480           }
481           else if (IsEqualIID(riid, &CLSID_ControlPanel))
482           {
483               if(LoadStringA(shell32_hInstance, IDS_CONTROLPANEL, szDest, buflen))
484                   ret = TRUE;
485           }
486           else if (IsEqualIID(riid, &CLSID_AdminFolderShortcut))
487           {
488               if(LoadStringA(shell32_hInstance, IDS_ADMINISTRATIVETOOLS, szDest, buflen))
489                   ret = TRUE;
490           }
491 #endif
492 	}
493 
494 	TRACE("-- (%s)\n", szDest);
495 
496 	return ret;
497 }
498 
499 /******************************************************************************
500  * HCR_GetFolderAttributes [Internal]
501  *
502  * Query the registry for a shell folders' attributes
503  *
504  * PARAMS
505  *  pidlFolder    [I]  A simple pidl of type PT_GUID.
506  *  pdwAttributes [IO] In: Attributes to be queried, OUT: Resulting attributes.
507  *
508  * RETURNS
509  *  TRUE:  Found information for the attributes in the registry
510  *  FALSE: No attribute information found
511  *
512  * NOTES
513  *  If queried for an attribute, which is set in the CallForAttributes registry
514  *  value, the function binds to the shellfolder objects and queries it.
515  */
516 BOOL HCR_GetFolderAttributes(LPCITEMIDLIST pidlFolder, LPDWORD pdwAttributes)
517 {
518     HKEY hSFKey;
519     LPOLESTR pwszCLSID;
520     LONG lResult;
521     DWORD dwTemp, dwLen;
522     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
523     static const WCHAR wszCallForAttributes[] = {
524         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
525     WCHAR wszShellFolderKey[] = { 'C','L','S','I','D','\\','{','0','0','0','2','1','4','0','0','-',
526         '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0','0',
527         '0','0','0','4','6','}','\\','S','h','e','l','l','F','o','l','d','e','r',0 };
528 
529     TRACE("(pidlFolder=%p, pdwAttributes=%p)\n", pidlFolder, pdwAttributes);
530 
531     if (!_ILIsPidlSimple(pidlFolder)) {
532         static BOOL firstHit = TRUE;
533         if (firstHit) {
534             ERR("should be called for simple PIDL's only!\n");
535             firstHit = FALSE;
536         }
537         return FALSE;
538     }
539 
540     if (!_ILIsDesktop(pidlFolder)) {
541         if (FAILED(StringFromCLSID(_ILGetGUIDPointer(pidlFolder), &pwszCLSID))) return FALSE;
542         memcpy(&wszShellFolderKey[6], pwszCLSID, 38 * sizeof(WCHAR));
543         CoTaskMemFree(pwszCLSID);
544     }
545 
546     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszShellFolderKey, 0, KEY_READ, &hSFKey);
547 #ifdef __REACTOS__
548     if (lResult != ERROR_SUCCESS)
549     {
550         ERR("Cannot open key: %ls\n", wszShellFolderKey);
551         return FALSE;
552     }
553 #else
554     if (lResult != ERROR_SUCCESS) return FALSE;
555 #endif
556 
557     dwLen = sizeof(DWORD);
558     lResult = RegQueryValueExW(hSFKey, wszCallForAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
559     if ((lResult == ERROR_SUCCESS) && (dwTemp & *pdwAttributes)) {
560         LPSHELLFOLDER psfDesktop, psfFolder;
561         HRESULT hr;
562 
563         RegCloseKey(hSFKey);
564         hr = SHGetDesktopFolder(&psfDesktop);
565         if (SUCCEEDED(hr)) {
566             hr = IShellFolder_BindToObject(psfDesktop, pidlFolder, NULL, &IID_IShellFolder,
567                                            (LPVOID*)&psfFolder);
568             if (SUCCEEDED(hr)) {
569                 hr = IShellFolder_GetAttributesOf(psfFolder, 0, NULL, pdwAttributes);
570                 IShellFolder_Release(psfFolder);
571             }
572             IShellFolder_Release(psfDesktop);
573         }
574         if (FAILED(hr)) return FALSE;
575     } else {
576         lResult = RegQueryValueExW(hSFKey, wszAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
577         RegCloseKey(hSFKey);
578         if (lResult == ERROR_SUCCESS) {
579             *pdwAttributes &= dwTemp;
580         } else {
581             return FALSE;
582         }
583     }
584 
585     TRACE("-- *pdwAttributes == 0x%08x\n", *pdwAttributes);
586 
587     return TRUE;
588 }
589