wrc: Use ARRAY_SIZE instead of open coding it.
[wine.git] / dlls / shlwapi / reg.c
blobb8070f44c78e236594f43118eeba2ca04f85549e
1 /*
2 * SHLWAPI registry functions
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2001 Guy Albertelli
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.
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.
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
22 #include <stdarg.h>
23 #include <string.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "wine/debug.h"
29 #define NO_SHLWAPI_STREAM
30 #include "shlwapi.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(shell);
34 /* Key/Value names for MIME content types */
35 static const char lpszContentTypeA[] = "Content Type";
36 static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
38 static const char szMimeDbContentA[] = "MIME\\Database\\Content Type\\";
39 static const WCHAR szMimeDbContentW[] = { 'M', 'I', 'M','E','\\',
40 'D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t',
41 ' ','T','y','p','e','\\', 0 };
42 static const DWORD dwLenMimeDbContent = 27; /* strlen of szMimeDbContentA/W */
44 static const char szExtensionA[] = "Extension";
45 static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0' };
47 INT WINAPI SHStringFromGUIDW(REFGUID,LPWSTR,INT);
48 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID,LPCWSTR,BOOL,BOOL,PHKEY);
50 /*************************************************************************
51 * SHDeleteOrphanKeyA [SHLWAPI.@]
53 * Delete a registry key with no sub keys or values.
55 * PARAMS
56 * hKey [I] Handle to registry key
57 * lpszSubKey [I] Name of sub key to possibly delete
59 * RETURNS
60 * Success: ERROR_SUCCESS. The key has been deleted if it was an orphan.
61 * Failure: An error from RegOpenKeyExA(), RegQueryValueExA(), or RegDeleteKeyA().
63 DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey)
65 HKEY hSubKey;
66 DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
68 TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey));
70 dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
72 if(!dwRet)
74 /* Get subkey and value count */
75 dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
76 NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
78 if(!dwRet && !dwKeyCount && !dwValueCount)
80 dwRet = RegDeleteKeyA(hKey, lpszSubKey);
82 RegCloseKey(hSubKey);
84 return dwRet;
87 /*************************************************************************
88 * SHDeleteOrphanKeyW [SHLWAPI.@]
90 * See SHDeleteOrphanKeyA.
92 DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey)
94 HKEY hSubKey;
95 DWORD dwKeyCount = 0, dwValueCount = 0, dwRet;
97 TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
99 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
101 if(!dwRet)
103 /* Get subkey and value count */
104 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
105 NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL);
107 if(!dwRet && !dwKeyCount && !dwValueCount)
109 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
111 RegCloseKey(hSubKey);
113 return dwRet;
116 /*************************************************************************
117 * @ [SHLWAPI.205]
120 DWORD WINAPI SHGetValueGoodBootA(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue,
121 LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
123 if (GetSystemMetrics(SM_CLEANBOOT))
124 return ERROR_INVALID_FUNCTION;
125 return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData);
128 /*************************************************************************
129 * @ [SHLWAPI.206]
132 DWORD WINAPI SHGetValueGoodBootW(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue,
133 LPDWORD pwType, LPVOID pvData, LPDWORD pbData)
135 if (GetSystemMetrics(SM_CLEANBOOT))
136 return ERROR_INVALID_FUNCTION;
137 return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData);
140 /*************************************************************************
141 * @ [SHLWAPI.320]
143 * Set a MIME content type in the registry.
145 * PARAMS
146 * lpszSubKey [I] Name of key under HKEY_CLASSES_ROOT.
147 * lpszValue [I] Value to set
149 * RETURNS
150 * Success: TRUE
151 * Failure: FALSE
153 BOOL WINAPI RegisterMIMETypeForExtensionA(LPCSTR lpszSubKey, LPCSTR lpszValue)
155 if (!lpszValue)
157 WARN("Invalid lpszValue would crash under Win32!\n");
158 return FALSE;
161 return !SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA,
162 REG_SZ, lpszValue, strlen(lpszValue));
165 /*************************************************************************
166 * @ [SHLWAPI.321]
168 * Unicode version of RegisterMIMETypeForExtensionA.
170 BOOL WINAPI RegisterMIMETypeForExtensionW(LPCWSTR lpszSubKey, LPCWSTR lpszValue)
172 if (!lpszValue)
174 WARN("Invalid lpszValue would crash under Win32!\n");
175 return FALSE;
178 return !SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW,
179 REG_SZ, lpszValue, lstrlenW(lpszValue));
182 /*************************************************************************
183 * @ [SHLWAPI.322]
185 * Delete a MIME content type from the registry.
187 * PARAMS
188 * lpszSubKey [I] Name of sub key
190 * RETURNS
191 * Success: TRUE
192 * Failure: FALSE
194 BOOL WINAPI UnregisterMIMETypeForExtensionA(LPCSTR lpszSubKey)
196 return !SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA);
199 /*************************************************************************
200 * @ [SHLWAPI.323]
202 * Unicode version of UnregisterMIMETypeForExtensionA.
204 BOOL WINAPI UnregisterMIMETypeForExtensionW(LPCWSTR lpszSubKey)
206 return !SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW);
209 /*************************************************************************
210 * @ [SHLWAPI.328]
212 * Get the registry path to a MIME content key.
214 * PARAMS
215 * lpszType [I] Content type to get the path for
216 * lpszBuffer [O] Destination for path
217 * dwLen [I] Length of lpszBuffer
219 * RETURNS
220 * Success: TRUE. lpszBuffer contains the full path.
221 * Failure: FALSE.
223 * NOTES
224 * The base path for the key is "MIME\Database\Content Type\"
226 BOOL WINAPI GetMIMETypeSubKeyA(LPCSTR lpszType, LPSTR lpszBuffer, DWORD dwLen)
228 TRACE("(%s,%p,%ld)\n", debugstr_a(lpszType), lpszBuffer, dwLen);
230 if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
232 size_t dwStrLen = strlen(lpszType);
234 if (dwStrLen < dwLen - dwLenMimeDbContent)
236 memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent);
237 memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, dwStrLen + 1);
238 return TRUE;
241 return FALSE;
244 /*************************************************************************
245 * @ [SHLWAPI.329]
247 * Unicode version of GetMIMETypeSubKeyA.
249 BOOL WINAPI GetMIMETypeSubKeyW(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen)
251 TRACE("(%s,%p,%ld)\n", debugstr_w(lpszType), lpszBuffer, dwLen);
253 if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer)
255 DWORD dwStrLen = lstrlenW(lpszType);
257 if (dwStrLen < dwLen - dwLenMimeDbContent)
259 memcpy(lpszBuffer, szMimeDbContentW, dwLenMimeDbContent * sizeof(WCHAR));
260 memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, (dwStrLen + 1) * sizeof(WCHAR));
261 return TRUE;
264 return FALSE;
267 /*************************************************************************
268 * @ [SHLWAPI.330]
270 * Get the file extension for a given Mime type.
272 * PARAMS
273 * lpszType [I] Mime type to get the file extension for
274 * lpExt [O] Destination for the resulting extension
275 * iLen [I] Length of lpExt in characters
277 * RETURNS
278 * Success: TRUE. lpExt contains the file extension.
279 * Failure: FALSE, if any parameter is invalid or the extension cannot be
280 * retrieved. If iLen > 0, lpExt is set to an empty string.
282 * NOTES
283 * - The extension returned in lpExt always has a leading '.' character, even
284 * if the registry Mime database entry does not.
285 * - iLen must be long enough for the file extension for this function to succeed.
287 BOOL WINAPI MIME_GetExtensionA(LPCSTR lpszType, LPSTR lpExt, INT iLen)
289 char szSubKey[MAX_PATH];
290 DWORD dwlen = iLen - 1, dwType;
291 BOOL bRet = FALSE;
293 if (iLen > 0 && lpExt)
294 *lpExt = '\0';
296 if (lpszType && lpExt && iLen > 2 &&
297 GetMIMETypeSubKeyA(lpszType, szSubKey, MAX_PATH) &&
298 !SHGetValueA(HKEY_CLASSES_ROOT, szSubKey, szExtensionA, &dwType, lpExt + 1, &dwlen) &&
299 lpExt[1])
301 if (lpExt[1] == '.')
302 memmove(lpExt, lpExt + 1, strlen(lpExt + 1) + 1);
303 else
304 *lpExt = '.'; /* Supply a '.' */
305 bRet = TRUE;
307 return bRet;
310 /*************************************************************************
311 * @ [SHLWAPI.331]
313 * Unicode version of MIME_GetExtensionA.
315 BOOL WINAPI MIME_GetExtensionW(LPCWSTR lpszType, LPWSTR lpExt, INT iLen)
317 WCHAR szSubKey[MAX_PATH];
318 DWORD dwlen = iLen - 1, dwType;
319 BOOL bRet = FALSE;
321 if (iLen > 0 && lpExt)
322 *lpExt = '\0';
324 if (lpszType && lpExt && iLen > 2 &&
325 GetMIMETypeSubKeyW(lpszType, szSubKey, MAX_PATH) &&
326 !SHGetValueW(HKEY_CLASSES_ROOT, szSubKey, szExtensionW, &dwType, lpExt + 1, &dwlen) &&
327 lpExt[1])
329 if (lpExt[1] == '.')
330 memmove(lpExt, lpExt + 1, (lstrlenW(lpExt + 1) + 1) * sizeof(WCHAR));
331 else
332 *lpExt = '.'; /* Supply a '.' */
333 bRet = TRUE;
335 return bRet;
338 /*************************************************************************
339 * @ [SHLWAPI.324]
341 * Set the file extension for a MIME content key.
343 * PARAMS
344 * lpszExt [I] File extension to set
345 * lpszType [I] Content type to set the extension for
347 * RETURNS
348 * Success: TRUE. The file extension is set in the registry.
349 * Failure: FALSE.
351 BOOL WINAPI RegisterExtensionForMIMETypeA(LPCSTR lpszExt, LPCSTR lpszType)
353 DWORD dwLen;
354 char szKey[MAX_PATH];
356 TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType));
358 if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
359 return FALSE;
361 dwLen = strlen(lpszExt) + 1;
363 if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen))
364 return FALSE;
365 return TRUE;
368 /*************************************************************************
369 * @ [SHLWAPI.325]
371 * Unicode version of RegisterExtensionForMIMETypeA.
373 BOOL WINAPI RegisterExtensionForMIMETypeW(LPCWSTR lpszExt, LPCWSTR lpszType)
375 DWORD dwLen;
376 WCHAR szKey[MAX_PATH];
378 TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType));
380 /* Get the full path to the key */
381 if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
382 return FALSE;
384 dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR);
386 if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen))
387 return FALSE;
388 return TRUE;
391 /*************************************************************************
392 * @ [SHLWAPI.326]
394 * Delete a file extension from a MIME content type.
396 * PARAMS
397 * lpszType [I] Content type to delete the extension for
399 * RETURNS
400 * Success: TRUE. The file extension is deleted from the registry.
401 * Failure: FALSE. The extension may have been removed but the key remains.
403 * NOTES
404 * If deleting the extension leaves an orphan key, the key is removed also.
406 BOOL WINAPI UnregisterExtensionForMIMETypeA(LPCSTR lpszType)
408 char szKey[MAX_PATH];
410 TRACE("(%s)\n", debugstr_a(lpszType));
412 if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
413 return FALSE;
415 if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA))
416 return FALSE;
418 if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey))
419 return FALSE;
420 return TRUE;
423 /*************************************************************************
424 * @ [SHLWAPI.327]
426 * Unicode version of UnregisterExtensionForMIMETypeA.
428 BOOL WINAPI UnregisterExtensionForMIMETypeW(LPCWSTR lpszType)
430 WCHAR szKey[MAX_PATH];
432 TRACE("(%s)\n", debugstr_w(lpszType));
434 if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */
435 return FALSE;
437 if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW))
438 return FALSE;
440 if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey))
441 return FALSE;
442 return TRUE;
446 * The following functions are ORDINAL ONLY:
449 /*************************************************************************
450 * @ [SHLWAPI.343]
452 * Create or open an explorer ClassId Key.
454 * PARAMS
455 * guid [I] Explorer ClassId key to open
456 * lpszValue [I] Value name under the ClassId Key
457 * bUseHKCU [I] TRUE=Use HKEY_CURRENT_USER, FALSE=Use HKEY_CLASSES_ROOT
458 * bCreate [I] TRUE=Create the key if it doesn't exist, FALSE=Don't
459 * phKey [O] Destination for the resulting key handle
461 * RETURNS
462 * Success: S_OK. phKey contains the resulting registry handle.
463 * Failure: An HRESULT error code indicating the problem.
465 HRESULT WINAPI SHRegGetCLSIDKeyA(REFGUID guid, LPCSTR lpszValue, BOOL bUseHKCU, BOOL bCreate, PHKEY phKey)
467 WCHAR szValue[MAX_PATH];
469 if (lpszValue)
470 MultiByteToWideChar(CP_ACP, 0, lpszValue, -1, szValue, ARRAY_SIZE(szValue));
472 return SHRegGetCLSIDKeyW(guid, lpszValue ? szValue : NULL, bUseHKCU, bCreate, phKey);
475 /*************************************************************************
476 * @ [SHLWAPI.344]
478 * Unicode version of SHRegGetCLSIDKeyA.
480 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU,
481 BOOL bCreate, PHKEY phKey)
483 static const WCHAR szClassIdKey[] = { 'S','o','f','t','w','a','r','e','\\',
484 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
485 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
486 'E','x','p','l','o','r','e','r','\\','C','L','S','I','D','\\' };
487 WCHAR szKey[MAX_PATH];
488 DWORD dwRet;
489 HKEY hkey;
491 /* Create the key string */
492 memcpy(szKey, szClassIdKey, sizeof(szClassIdKey));
493 SHStringFromGUIDW(guid, szKey + ARRAY_SIZE(szClassIdKey), 39); /* Append guid */
495 if(lpszValue)
497 szKey[ARRAY_SIZE(szClassIdKey) + 39] = '\\';
498 lstrcpyW(szKey + ARRAY_SIZE(szClassIdKey) + 40, lpszValue); /* Append value name */
501 hkey = bUseHKCU ? HKEY_CURRENT_USER : HKEY_CLASSES_ROOT;
503 if(bCreate)
504 dwRet = RegCreateKeyW(hkey, szKey, phKey);
505 else
506 dwRet = RegOpenKeyExW(hkey, szKey, 0, KEY_READ, phKey);
508 return dwRet ? HRESULT_FROM_WIN32(dwRet) : S_OK;
511 /*************************************************************************
512 * SHRegisterValidateTemplate [SHLWAPI.@]
514 * observed from the ie 5.5 installer:
515 * - allocates a buffer with the size of the given file
516 * - read the file content into the buffer
517 * - creates the key szTemplateKey
518 * - sets "205523652929647911071668590831910975402"=dword:00002e37 at
519 * the key
521 * PARAMS
522 * filename [I] An existing file its content is read into an allocated
523 * buffer
524 * unknown [I]
526 * RETURNS
527 * Success: ERROR_SUCCESS.
529 HRESULT WINAPI SHRegisterValidateTemplate(LPCWSTR filename, BOOL unknown)
531 /* static const WCHAR szTemplateKey[] = { 'S','o','f','t','w','a','r','e','\\',
532 * 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
533 * 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
534 * 'E','x','p','l','o','r','e','r','\\',
535 * 'T','e','m','p','l','a','t','e','R','e','g','i','s','t','r','y',0 };
537 FIXME("stub: %s, %08x\n", debugstr_w(filename), unknown);
539 return S_OK;