xref: /reactos/dll/win32/shell32/wine/classes.c (revision 803b5e13)
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 
336     if (ret)
337         TRACE("-- %s %i\n", szDest, *picon_idx);
338     else
339         TRACE("-- not found\n");
340 
341 	return ret;
342 }
343 
344 /***************************************************************************************
345 *	HCR_GetClassName	[internal]
346 *
347 * Gets the name of a registered class
348 */
349 static const WCHAR swEmpty[] = {0};
350 
351 BOOL HCR_GetClassNameW(REFIID riid, LPWSTR szDest, DWORD len)
352 {
353 	HKEY	hkey;
354 	BOOL ret = FALSE;
355 	DWORD buflen = len;
356 #ifdef __REACTOS__
357         WCHAR szName[100];
358         LPOLESTR pStr;
359 #endif
360 
361  	szDest[0] = 0;
362 
363 #ifdef __REACTOS__
364         if (StringFromCLSID(riid, &pStr) == S_OK)
365         {
366             DWORD dwLen = buflen * sizeof(WCHAR);
367             swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr);
368             if (!RegGetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, NULL, (PVOID)szDest, &dwLen))
369             {
370                 ret = TRUE;
371             }
372             CoTaskMemFree(pStr);
373         }
374         if (!ret && HCR_RegOpenClassIDKey(riid, &hkey))
375 #else
376 	if (HCR_RegOpenClassIDKey(riid, &hkey))
377 #endif
378 	{
379           static const WCHAR wszLocalizedString[] =
380             { 'L','o','c','a','l','i','z','e','d','S','t','r','i','n','g', 0 };
381           if (!RegLoadMUIStringW(hkey, wszLocalizedString, szDest, len, NULL, 0, NULL) ||
382               !RegQueryValueExW(hkey, swEmpty, 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 (LoadStringW(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
394 	      ret = TRUE;
395 	  }
396 	  else if (IsEqualIID(riid, &CLSID_MyComputer))
397 	  {
398 	    if(LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
399 	      ret = TRUE;
400 	  }
401 #ifdef __REACTOS__
402           else if (IsEqualIID(riid, &CLSID_MyDocuments))
403           {
404               if(LoadStringW(shell32_hInstance, IDS_PERSONAL, szDest, buflen))
405                   ret = TRUE;
406           }
407           else if (IsEqualIID(riid, &CLSID_RecycleBin))
408           {
409               if(LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_FOLDER_NAME, szDest, buflen))
410                   ret = TRUE;
411           }
412           else if (IsEqualIID(riid, &CLSID_ControlPanel))
413           {
414               if(LoadStringW(shell32_hInstance, IDS_CONTROLPANEL, szDest, buflen))
415                   ret = TRUE;
416           }
417           else if (IsEqualIID(riid, &CLSID_AdminFolderShortcut))
418           {
419               if(LoadStringW(shell32_hInstance, IDS_ADMINISTRATIVETOOLS, szDest, buflen))
420                   ret = TRUE;
421           }
422 #endif
423 	}
424 	TRACE("-- %s\n", debugstr_w(szDest));
425 	return ret;
426 }
427 
428 BOOL HCR_GetClassNameA(REFIID riid, LPSTR szDest, DWORD len)
429 {	HKEY	hkey;
430 	BOOL ret = FALSE;
431 	DWORD buflen = len;
432 #ifdef __REACTOS__
433         CHAR szName[100];
434         LPOLESTR pStr;
435 #endif
436 
437 	szDest[0] = 0;
438 
439 #ifdef __REACTOS__
440         if (StringFromCLSID(riid, &pStr) == S_OK)
441         {
442             DWORD dwLen = buflen * sizeof(CHAR);
443             sprintf(szName, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%S", pStr);
444             if (!RegGetValueA(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, NULL, (PVOID)szDest, &dwLen))
445             {
446                 ret = TRUE;
447             }
448             CoTaskMemFree(pStr);
449         }
450         if (!ret && HCR_RegOpenClassIDKey(riid, &hkey))
451 #else
452 	if (HCR_RegOpenClassIDKey(riid, &hkey))
453 #endif
454 	{
455           if (!RegLoadMUIStringA(hkey,"LocalizedString",szDest,len,NULL,0,NULL) ||
456               !RegQueryValueExA(hkey,"",0,NULL,(LPBYTE)szDest,&len))
457           {
458 	    ret = TRUE;
459 	  }
460 	  RegCloseKey(hkey);
461 	}
462 
463 	if (!ret || !szDest[0])
464 	{
465 	  if(IsEqualIID(riid, &CLSID_ShellDesktop))
466 	  {
467 	    if (LoadStringA(shell32_hInstance, IDS_DESKTOP, szDest, buflen))
468 	      ret = TRUE;
469 	  }
470 	  else if (IsEqualIID(riid, &CLSID_MyComputer))
471 	  {
472 	    if(LoadStringA(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen))
473 	      ret = TRUE;
474 	  }
475 #ifdef __REACTOS__
476           else if (IsEqualIID(riid, &CLSID_MyDocuments))
477           {
478               if(LoadStringA(shell32_hInstance, IDS_PERSONAL, szDest, buflen))
479                   ret = TRUE;
480           }
481           else if (IsEqualIID(riid, &CLSID_RecycleBin))
482           {
483               if(LoadStringA(shell32_hInstance, IDS_RECYCLEBIN_FOLDER_NAME, szDest, buflen))
484                   ret = TRUE;
485           }
486           else if (IsEqualIID(riid, &CLSID_ControlPanel))
487           {
488               if(LoadStringA(shell32_hInstance, IDS_CONTROLPANEL, szDest, buflen))
489                   ret = TRUE;
490           }
491           else if (IsEqualIID(riid, &CLSID_AdminFolderShortcut))
492           {
493               if(LoadStringA(shell32_hInstance, IDS_ADMINISTRATIVETOOLS, szDest, buflen))
494                   ret = TRUE;
495           }
496 #endif
497 	}
498 
499 	TRACE("-- (%s)\n", szDest);
500 
501 	return ret;
502 }
503 
504 /******************************************************************************
505  * HCR_GetFolderAttributes [Internal]
506  *
507  * Query the registry for a shell folders' attributes
508  *
509  * PARAMS
510  *  pidlFolder    [I]  A simple pidl of type PT_GUID.
511  *  pdwAttributes [IO] In: Attributes to be queried, OUT: Resulting attributes.
512  *
513  * RETURNS
514  *  TRUE:  Found information for the attributes in the registry
515  *  FALSE: No attribute information found
516  *
517  * NOTES
518  *  If queried for an attribute, which is set in the CallForAttributes registry
519  *  value, the function binds to the shellfolder objects and queries it.
520  */
521 BOOL HCR_GetFolderAttributes(LPCITEMIDLIST pidlFolder, LPDWORD pdwAttributes)
522 {
523     HKEY hSFKey;
524     LPOLESTR pwszCLSID;
525     LONG lResult;
526     DWORD dwTemp, dwLen;
527     static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
528     static const WCHAR wszCallForAttributes[] = {
529         'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
530     WCHAR wszShellFolderKey[] = { 'C','L','S','I','D','\\','{','0','0','0','2','1','4','0','0','-',
531         '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0','0',
532         '0','0','0','4','6','}','\\','S','h','e','l','l','F','o','l','d','e','r',0 };
533 
534     TRACE("(pidlFolder=%p, pdwAttributes=%p)\n", pidlFolder, pdwAttributes);
535 
536     if (!_ILIsPidlSimple(pidlFolder)) {
537         static BOOL firstHit = TRUE;
538         if (firstHit) {
539             ERR("should be called for simple PIDL's only!\n");
540             firstHit = FALSE;
541         }
542         return FALSE;
543     }
544 
545     if (!_ILIsDesktop(pidlFolder)) {
546         if (FAILED(StringFromCLSID(_ILGetGUIDPointer(pidlFolder), &pwszCLSID))) return FALSE;
547         memcpy(&wszShellFolderKey[6], pwszCLSID, 38 * sizeof(WCHAR));
548         CoTaskMemFree(pwszCLSID);
549     }
550 
551     lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszShellFolderKey, 0, KEY_READ, &hSFKey);
552 #ifdef __REACTOS__
553     if (lResult != ERROR_SUCCESS)
554     {
555         ERR("Cannot open key: %ls\n", wszShellFolderKey);
556         return FALSE;
557     }
558 #else
559     if (lResult != ERROR_SUCCESS) return FALSE;
560 #endif
561 
562     dwLen = sizeof(DWORD);
563     lResult = RegQueryValueExW(hSFKey, wszCallForAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
564     if ((lResult == ERROR_SUCCESS) && (dwTemp & *pdwAttributes)) {
565         LPSHELLFOLDER psfDesktop, psfFolder;
566         HRESULT hr;
567 
568         RegCloseKey(hSFKey);
569         hr = SHGetDesktopFolder(&psfDesktop);
570         if (SUCCEEDED(hr)) {
571             hr = IShellFolder_BindToObject(psfDesktop, pidlFolder, NULL, &IID_IShellFolder,
572                                            (LPVOID*)&psfFolder);
573             if (SUCCEEDED(hr)) {
574                 hr = IShellFolder_GetAttributesOf(psfFolder, 0, NULL, pdwAttributes);
575                 IShellFolder_Release(psfFolder);
576             }
577             IShellFolder_Release(psfDesktop);
578         }
579         if (FAILED(hr)) return FALSE;
580     } else {
581         lResult = RegQueryValueExW(hSFKey, wszAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen);
582         RegCloseKey(hSFKey);
583         if (lResult == ERROR_SUCCESS) {
584             *pdwAttributes &= dwTemp;
585         } else {
586             return FALSE;
587         }
588     }
589 
590     TRACE("-- *pdwAttributes == 0x%08x\n", *pdwAttributes);
591 
592     return TRUE;
593 }
594