[browseui]
[reactos.git] / reactos / lib / atl / statreg.h
1 /*
2 * ReactOS ATL
3 *
4 * Copyright 2005 Jacek Caban
5 * Copyright 2009 Andrew Hill <ash77@reactos.org>
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #pragma once
23
24 class IRegistrarBase : public IUnknown
25 {
26 public:
27 virtual HRESULT STDMETHODCALLTYPE AddReplacement(LPCOLESTR key, LPCOLESTR item) = 0;
28 virtual HRESULT STDMETHODCALLTYPE ClearReplacements() = 0;
29 };
30
31 namespace ATL
32 {
33
34 class CRegObject : public IRegistrarBase
35 {
36 public:
37 typedef struct rep_list_str
38 {
39 LPOLESTR key;
40 LPOLESTR item;
41 int key_len;
42 struct rep_list_str *next;
43 } rep_list;
44
45 typedef struct
46 {
47 LPOLESTR str;
48 DWORD alloc;
49 DWORD len;
50 } strbuf;
51
52 rep_list *m_rep;
53
54 public:
55 CRegObject()
56 {
57 m_rep = NULL;
58 }
59
60 ~CRegObject()
61 {
62 HRESULT hResult;
63
64 hResult = ClearReplacements();
65 ATLASSERT(SUCCEEDED(hResult));
66 }
67
68 HRESULT STDMETHODCALLTYPE QueryInterface(const IID & /* riid */, void ** /* ppvObject */ )
69 {
70 ATLASSERT(_T("statically linked in CRegObject is not a com object. Do not callthis function"));
71 return E_NOTIMPL;
72 }
73
74 ULONG STDMETHODCALLTYPE AddRef()
75 {
76 ATLASSERT(_T("statically linked in CRegObject is not a com object. Do not callthis function"));
77 return 1;
78 }
79
80 ULONG STDMETHODCALLTYPE Release()
81 {
82 ATLASSERT(_T("statically linked in CRegObject is not a com object. Do not callthis function"));
83 return 0;
84 }
85
86 HRESULT STDMETHODCALLTYPE AddReplacement(LPCOLESTR key, LPCOLESTR item)
87 {
88 int len;
89 rep_list *new_rep;
90
91 new_rep = reinterpret_cast<rep_list *>(HeapAlloc(GetProcessHeap(), 0, sizeof(rep_list)));
92
93 new_rep->key_len = lstrlenW(key);
94 new_rep->key = reinterpret_cast<OLECHAR *>(HeapAlloc(GetProcessHeap(), 0, (new_rep->key_len + 1) * sizeof(OLECHAR)));
95 memcpy(new_rep->key, key, (new_rep->key_len + 1) * sizeof(OLECHAR));
96
97 len = lstrlenW(item) + 1;
98 new_rep->item = reinterpret_cast<OLECHAR *>(HeapAlloc(GetProcessHeap(), 0, len * sizeof(OLECHAR)));
99 memcpy(new_rep->item, item, len * sizeof(OLECHAR));
100
101 new_rep->next = m_rep;
102 m_rep = new_rep;
103
104 return S_OK;
105 }
106
107 HRESULT STDMETHODCALLTYPE ClearReplacements()
108 {
109 rep_list *iter;
110 rep_list *iter2;
111
112 iter = m_rep;
113 while (iter)
114 {
115 iter2 = iter->next;
116 HeapFree(GetProcessHeap(), 0, iter->key);
117 HeapFree(GetProcessHeap(), 0, iter->item);
118 HeapFree(GetProcessHeap(), 0, iter);
119 iter = iter2;
120 }
121
122 m_rep = NULL;
123 return S_OK;
124 }
125
126 HRESULT STDMETHODCALLTYPE ResourceRegisterSz(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType)
127 {
128 return RegisterWithResource(resFileName, szID, szType, TRUE);
129 }
130
131 HRESULT STDMETHODCALLTYPE ResourceUnregisterSz(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType)
132 {
133 return RegisterWithResource(resFileName, szID, szType, FALSE);
134 }
135
136 HRESULT STDMETHODCALLTYPE FileRegister(LPCOLESTR fileName)
137 {
138 return RegisterWithFile(fileName, TRUE);
139 }
140
141 HRESULT STDMETHODCALLTYPE FileUnregister(LPCOLESTR fileName)
142 {
143 return RegisterWithFile(fileName, FALSE);
144 }
145
146 HRESULT STDMETHODCALLTYPE StringRegister(LPCOLESTR data)
147 {
148 return RegisterWithString(data, TRUE);
149 }
150
151 HRESULT STDMETHODCALLTYPE StringUnregister(LPCOLESTR data)
152 {
153 return RegisterWithString(data, FALSE);
154 }
155
156 HRESULT STDMETHODCALLTYPE ResourceRegister(LPCOLESTR resFileName, UINT nID, LPCOLESTR szType)
157 {
158 return ResourceRegisterSz(resFileName, MAKEINTRESOURCEW(nID), szType);
159 }
160
161 HRESULT STDMETHODCALLTYPE ResourceUnregister(LPCOLESTR resFileName, UINT nID, LPCOLESTR szType)
162 {
163 return ResourceRegisterSz(resFileName, MAKEINTRESOURCEW(nID), szType);
164 }
165
166 protected:
167 HRESULT STDMETHODCALLTYPE RegisterWithResource(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType, BOOL doRegister)
168 {
169 return resource_register(resFileName, szID, szType, doRegister);
170 }
171
172 HRESULT STDMETHODCALLTYPE RegisterWithFile(LPCOLESTR fileName, BOOL doRegister)
173 {
174 return file_register(fileName, doRegister);
175 }
176
177 HRESULT STDMETHODCALLTYPE RegisterWithString(LPCOLESTR data, BOOL doRegister)
178 {
179 return string_register(data, doRegister);
180 }
181
182 private:
183 inline LONG RegDeleteTreeX(HKEY parentKey, LPCTSTR subKeyName)
184 {
185 wchar_t szBuffer[256];
186 DWORD dwSize;
187 FILETIME time;
188 HKEY childKey;
189 LONG lRes;
190
191 ATLASSERT(parentKey != NULL);
192 lRes = RegOpenKeyEx(parentKey, subKeyName, 0, KEY_READ | KEY_WRITE, &childKey);
193 if (lRes != ERROR_SUCCESS)
194 return lRes;
195
196 dwSize = sizeof(szBuffer) / sizeof(szBuffer[0]);
197 while (RegEnumKeyExW(parentKey, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == ERROR_SUCCESS)
198 {
199 lRes = RegDeleteTreeX(childKey, szBuffer);
200 if (lRes != ERROR_SUCCESS)
201 return lRes;
202 dwSize = sizeof(szBuffer) / sizeof(szBuffer[0]);
203 }
204 RegCloseKey(childKey);
205 return RegDeleteKey(parentKey, subKeyName);
206 }
207
208 void strbuf_init(strbuf *buf)
209 {
210 buf->str = reinterpret_cast<LPOLESTR>(HeapAlloc(GetProcessHeap(), 0, 128 * sizeof(WCHAR)));
211 buf->alloc = 128;
212 buf->len = 0;
213 }
214
215 void strbuf_write(LPCOLESTR str, strbuf *buf, int len)
216 {
217 if (len == -1)
218 len = lstrlenW(str);
219 if (buf->len+len+1 >= buf->alloc)
220 {
221 buf->alloc = (buf->len + len) * 2;
222 buf->str = reinterpret_cast<LPOLESTR>(HeapReAlloc(GetProcessHeap(), 0, buf->str, buf->alloc * sizeof(WCHAR)));
223 }
224 memcpy(buf->str + buf->len, str, len * sizeof(OLECHAR));
225 buf->len += len;
226 buf->str[buf->len] = '\0';
227 }
228
229
230 HRESULT file_register(LPCOLESTR fileName, BOOL do_register)
231 {
232 HANDLE file;
233 DWORD filelen;
234 DWORD len;
235 LPWSTR regstrw;
236 LPSTR regstra;
237 LRESULT lres;
238 HRESULT hResult;
239
240 file = CreateFileW(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
241 if (file != INVALID_HANDLE_VALUE)
242 {
243 filelen = GetFileSize(file, NULL);
244 regstra = reinterpret_cast<LPSTR>(HeapAlloc(GetProcessHeap(), 0, filelen));
245 lres = ReadFile(file, regstra, filelen, NULL, NULL);
246 if (lres == ERROR_SUCCESS)
247 {
248 len = MultiByteToWideChar(CP_ACP, 0, regstra, filelen, NULL, 0) + 1;
249 regstrw = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)));
250 MultiByteToWideChar(CP_ACP, 0, regstra, filelen, regstrw, len);
251 regstrw[len - 1] = '\0';
252
253 hResult = string_register(regstrw, do_register);
254
255 HeapFree(GetProcessHeap(), 0, regstrw);
256 }
257 else
258 {
259 hResult = HRESULT_FROM_WIN32(lres);
260 }
261 HeapFree(GetProcessHeap(), 0, regstra);
262 CloseHandle(file);
263 }
264 else
265 {
266 hResult = HRESULT_FROM_WIN32(GetLastError());
267 }
268
269 return hResult;
270 }
271
272 HRESULT resource_register(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType, BOOL do_register)
273 {
274 HINSTANCE hins;
275 HRSRC src;
276 HGLOBAL regstra;
277 LPWSTR regstrw;
278 DWORD len;
279 DWORD reslen;
280 HRESULT hResult;
281
282 hins = LoadLibraryExW(resFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
283 if (hins)
284 {
285 src = FindResourceW(hins, szID, szType);
286 if (src)
287 {
288 regstra = LoadResource(hins, src);
289 reslen = SizeofResource(hins, src);
290 if (regstra)
291 {
292 len = MultiByteToWideChar(CP_ACP, 0, reinterpret_cast<LPCSTR>(regstra), reslen, NULL, 0) + 1;
293 regstrw = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)));
294 MultiByteToWideChar(CP_ACP, 0, reinterpret_cast<LPCSTR>(regstra), reslen, regstrw, len);
295 regstrw[len - 1] = '\0';
296
297 hResult = string_register(regstrw, do_register);
298
299 HeapFree(GetProcessHeap(), 0, regstrw);
300 }
301 else
302 hResult = HRESULT_FROM_WIN32(GetLastError());
303 }
304 else
305 hResult = HRESULT_FROM_WIN32(GetLastError());
306 FreeLibrary(hins);
307 }
308 else
309 hResult = HRESULT_FROM_WIN32(GetLastError());
310
311 return hResult;
312 }
313
314 HRESULT string_register(LPCOLESTR data, BOOL do_register)
315 {
316 strbuf buf;
317 HRESULT hResult;
318
319 strbuf_init(&buf);
320 hResult = do_preprocess(data, &buf);
321 if (SUCCEEDED(hResult))
322 {
323 hResult = do_process_root_key(buf.str, do_register);
324 if (FAILED(hResult) && do_register)
325 do_process_root_key(buf.str, FALSE);
326 }
327
328 HeapFree(GetProcessHeap(), 0, buf.str);
329 return hResult;
330 }
331
332 HRESULT do_preprocess(LPCOLESTR data, strbuf *buf)
333 {
334 LPCOLESTR iter;
335 LPCOLESTR iter2;
336 rep_list *rep_iter;
337
338 iter2 = data;
339 iter = wcschr(data, '%');
340 while (iter)
341 {
342 strbuf_write(iter2, buf, static_cast<int>(iter - iter2));
343
344 iter2 = ++iter;
345 if (!*iter2)
346 return DISP_E_EXCEPTION;
347 iter = wcschr(iter2, '%');
348 if (!iter)
349 return DISP_E_EXCEPTION;
350
351 if (iter == iter2)
352 strbuf_write(_T("%"), buf, 1);
353 else
354 {
355 for (rep_iter = m_rep; rep_iter; rep_iter = rep_iter->next)
356 {
357 if (rep_iter->key_len == iter - iter2 && !_memicmp(iter2, rep_iter->key, rep_iter->key_len * sizeof(wchar_t)))
358 break;
359 }
360 if (!rep_iter)
361 return DISP_E_EXCEPTION;
362
363 strbuf_write(rep_iter->item, buf, -1);
364 }
365
366 iter2 = ++iter;
367 iter = wcschr(iter, '%');
368 }
369
370 strbuf_write(iter2, buf, -1);
371
372 return S_OK;
373 }
374
375 HRESULT get_word(LPCOLESTR *str, strbuf *buf)
376 {
377 LPCOLESTR iter;
378 LPCOLESTR iter2;
379
380 iter2 = *str;
381 buf->len = 0;
382 buf->str[0] = '\0';
383
384 while (iswspace (*iter2))
385 iter2++;
386 iter = iter2;
387 if (!*iter)
388 {
389 *str = iter;
390 return S_OK;
391 }
392
393 if (*iter == '}' || *iter == '=')
394 {
395 strbuf_write(iter++, buf, 1);
396 }
397 else if (*iter == '\'')
398 {
399 iter2 = ++iter;
400 iter = wcschr(iter, '\'');
401 if (!iter)
402 {
403 *str = iter;
404 return DISP_E_EXCEPTION;
405 }
406 strbuf_write(iter2, buf, static_cast<int>(iter - iter2));
407 iter++;
408 }
409 else
410 {
411 while (*iter && !iswspace(*iter))
412 iter++;
413 strbuf_write(iter2, buf, static_cast<int>(iter - iter2));
414 }
415
416 while (iswspace(*iter))
417 iter++;
418 *str = iter;
419 return S_OK;
420 }
421
422 HRESULT do_process_key(LPCOLESTR *pstr, HKEY parent_key, strbuf *buf, BOOL do_register)
423 {
424 LPCOLESTR iter;
425 HRESULT hres;
426 LONG lres;
427 HKEY hkey;
428 strbuf name;
429
430 enum {
431 NORMAL,
432 NO_REMOVE,
433 IS_VAL,
434 FORCE_REMOVE,
435 DO_DELETE
436 } key_type = NORMAL;
437
438 static const wchar_t *wstrNoRemove = _T("NoRemove");
439 static const wchar_t *wstrForceRemove = _T("ForceRemove");
440 static const wchar_t *wstrDelete = _T("Delete");
441 static const wchar_t *wstrval = _T("val");
442
443 iter = *pstr;
444 hkey = NULL;
445 iter = *pstr;
446 hres = get_word(&iter, buf);
447 if (FAILED(hres))
448 return hres;
449 strbuf_init(&name);
450
451 while(buf->str[1] || buf->str[0] != '}')
452 {
453 key_type = NORMAL;
454 if (!lstrcmpiW(buf->str, wstrNoRemove))
455 key_type = NO_REMOVE;
456 else if (!lstrcmpiW(buf->str, wstrForceRemove))
457 key_type = FORCE_REMOVE;
458 else if (!lstrcmpiW(buf->str, wstrval))
459 key_type = IS_VAL;
460 else if (!lstrcmpiW(buf->str, wstrDelete))
461 key_type = DO_DELETE;
462
463 if (key_type != NORMAL)
464 {
465 hres = get_word(&iter, buf);
466 if(FAILED(hres))
467 break;
468 }
469
470 if (do_register)
471 {
472 if (key_type == IS_VAL)
473 {
474 hkey = parent_key;
475 strbuf_write(buf->str, &name, -1);
476 }
477 else if (key_type == DO_DELETE)
478 {
479 RegDeleteTreeX(parent_key, buf->str);
480 }
481 else
482 {
483 if (key_type == FORCE_REMOVE)
484 RegDeleteTreeX(parent_key, buf->str);
485 lres = RegCreateKey(parent_key, buf->str, &hkey);
486 if (lres != ERROR_SUCCESS)
487 {
488 hres = HRESULT_FROM_WIN32(lres);
489 break;
490 }
491 }
492 }
493 else if (key_type != IS_VAL && key_type != DO_DELETE)
494 {
495 strbuf_write(buf->str, &name, -1);
496 lres = RegOpenKey(parent_key, buf->str, &hkey);
497 if (lres != ERROR_SUCCESS)
498 {
499 }
500 }
501
502 if (key_type != DO_DELETE && *iter == '=')
503 {
504 iter++;
505 hres = get_word(&iter, buf);
506 if (FAILED(hres))
507 break;
508 if (buf->len != 1)
509 {
510 hres = DISP_E_EXCEPTION;
511 break;
512 }
513 if (do_register)
514 {
515 switch(buf->str[0])
516 {
517 case 's':
518 hres = get_word(&iter, buf);
519 if (FAILED(hres))
520 break;
521 lres = RegSetValueEx(hkey, name.len ? name.str : NULL, 0, REG_SZ, (PBYTE)buf->str,
522 (lstrlenW(buf->str) + 1) * sizeof(WCHAR));
523 if (lres != ERROR_SUCCESS)
524 {
525 hres = HRESULT_FROM_WIN32(lres);
526 break;
527 }
528 break;
529 case 'd':
530 {
531 WCHAR *end;
532 DWORD dw;
533 if(*iter == '0' && iter[1] == 'x')
534 {
535 iter += 2;
536 dw = wcstol(iter, &end, 16);
537 }
538 else
539 {
540 dw = wcstol(iter, &end, 10);
541 }
542 iter = end;
543 lres = RegSetValueEx(hkey, name.len ? name.str : NULL, 0, REG_DWORD, (PBYTE)&dw, sizeof(dw));
544 if (lres != ERROR_SUCCESS)
545 {
546 hres = HRESULT_FROM_WIN32(lres);
547 break;
548 }
549 break;
550 }
551 default:
552 hres = DISP_E_EXCEPTION;
553 }
554 if (FAILED(hres))
555 break;
556 }
557 else
558 {
559 if (*iter == '-')
560 iter++;
561 hres = get_word(&iter, buf);
562 if (FAILED(hres))
563 break;
564 }
565 }
566 else if(key_type == IS_VAL)
567 {
568 hres = DISP_E_EXCEPTION;
569 break;
570 }
571
572 if (key_type != IS_VAL && key_type != DO_DELETE && *iter == '{' && iswspace(iter[1]))
573 {
574 hres = get_word(&iter, buf);
575 if (FAILED(hres))
576 break;
577 hres = do_process_key(&iter, hkey, buf, do_register);
578 if (FAILED(hres))
579 break;
580 }
581
582 if (!do_register && (key_type == NORMAL || key_type == FORCE_REMOVE))
583 {
584 RegDeleteKey(parent_key, name.str);
585 }
586
587 if (hkey && key_type != IS_VAL)
588 RegCloseKey(hkey);
589 hkey = 0;
590 name.len = 0;
591
592 hres = get_word(&iter, buf);
593 if (FAILED(hres))
594 break;
595 }
596
597 HeapFree(GetProcessHeap(), 0, name.str);
598 if (hkey && key_type != IS_VAL)
599 RegCloseKey(hkey);
600 *pstr = iter;
601 return hres;
602 }
603
604 HRESULT do_process_root_key(LPCOLESTR data, BOOL do_register)
605 {
606 LPCOLESTR iter;
607 strbuf buf;
608 unsigned int i;
609 HRESULT hResult;
610 static const struct {
611 const wchar_t *name;
612 HKEY key;
613 } root_keys[] = {
614 {_T("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT},
615 {_T("HKEY_CURRENT_USER"), HKEY_CURRENT_USER},
616 {_T("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE},
617 {_T("HKEY_USERS"), HKEY_USERS},
618 {_T("HKEY_PERFORMANCE_DATA"), HKEY_PERFORMANCE_DATA},
619 {_T("HKEY_DYN_DATA"), HKEY_DYN_DATA},
620 {_T("HKEY_CURRENT_CONFIG"), HKEY_CURRENT_CONFIG},
621 {_T("HKCR"), HKEY_CLASSES_ROOT},
622 {_T("HKCU"), HKEY_CURRENT_USER},
623 {_T("HKLM"), HKEY_LOCAL_MACHINE},
624 {_T("HKU"), HKEY_USERS},
625 {_T("HKPD"), HKEY_PERFORMANCE_DATA},
626 {_T("HKDD"), HKEY_DYN_DATA},
627 {_T("HKCC"), HKEY_CURRENT_CONFIG},
628 };
629
630 iter = data;
631 hResult = S_OK;
632
633 strbuf_init(&buf);
634 hResult = get_word(&iter, &buf);
635 if (FAILED(hResult))
636 return hResult;
637
638 while (*iter)
639 {
640 if (!buf.len)
641 {
642 hResult = DISP_E_EXCEPTION;
643 break;
644 }
645 for (i = 0; i < sizeof(root_keys) / sizeof(root_keys[0]); i++)
646 {
647 if (!lstrcmpiW(buf.str, root_keys[i].name))
648 break;
649 }
650 if (i == sizeof(root_keys) / sizeof(root_keys[0]))
651 {
652 hResult = DISP_E_EXCEPTION;
653 break;
654 }
655 hResult = get_word(&iter, &buf);
656 if (FAILED(hResult))
657 break;
658 if (buf.str[1] || buf.str[0] != '{')
659 {
660 hResult = DISP_E_EXCEPTION;
661 break;
662 }
663 hResult = do_process_key(&iter, root_keys[i].key, &buf, do_register);
664 if (FAILED(hResult))
665 break;
666 hResult = get_word(&iter, &buf);
667 if (FAILED(hResult))
668 break;
669 }
670 HeapFree(GetProcessHeap(), 0, buf.str);
671 return hResult;
672 }
673
674 };
675
676 }; //namespace ATL