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