xref: /reactos/sdk/lib/atl/statreg.h (revision 53221834)
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         (void)hResult;
67     }
68 
69     HRESULT STDMETHODCALLTYPE QueryInterface(const IID & /* riid */, void ** /* ppvObject */ )
70     {
71         ATLASSERT(FALSE && TEXT("statically linked in CRegObject is not a com object. Do not call this function"));
72         return E_NOTIMPL;
73     }
74 
75     ULONG STDMETHODCALLTYPE AddRef()
76     {
77         ATLASSERT(FALSE && TEXT("statically linked in CRegObject is not a com object. Do not call this function"));
78         return 1;
79     }
80 
81     ULONG STDMETHODCALLTYPE Release()
82     {
83         ATLASSERT(FALSE && TEXT("statically linked in CRegObject is not a com object. Do not call this 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         if (new_rep == NULL)
94             return E_OUTOFMEMORY;
95 
96         new_rep->key_len  = lstrlenW(key);
97         new_rep->key = reinterpret_cast<OLECHAR *>(HeapAlloc(GetProcessHeap(), 0, (new_rep->key_len + 1) * sizeof(OLECHAR)));
98         if (new_rep->key == NULL)
99         {
100             HeapFree(GetProcessHeap(), 0, new_rep);
101             return E_OUTOFMEMORY;
102         }
103         memcpy(new_rep->key, key, (new_rep->key_len + 1) * sizeof(OLECHAR));
104 
105         len = lstrlenW(item) + 1;
106         new_rep->item = reinterpret_cast<OLECHAR *>(HeapAlloc(GetProcessHeap(), 0, len * sizeof(OLECHAR)));
107         if (new_rep->item == NULL)
108         {
109             HeapFree(GetProcessHeap(), 0, new_rep->key);
110             HeapFree(GetProcessHeap(), 0, new_rep);
111             return E_OUTOFMEMORY;
112         }
113         memcpy(new_rep->item, item, len * sizeof(OLECHAR));
114 
115         new_rep->next = m_rep;
116         m_rep = new_rep;
117 
118         return S_OK;
119     }
120 
121     HRESULT STDMETHODCALLTYPE ClearReplacements()
122     {
123         rep_list *iter;
124         rep_list *iter2;
125 
126         iter = m_rep;
127         while (iter)
128         {
129             iter2 = iter->next;
130             HeapFree(GetProcessHeap(), 0, iter->key);
131             HeapFree(GetProcessHeap(), 0, iter->item);
132             HeapFree(GetProcessHeap(), 0, iter);
133             iter = iter2;
134         }
135 
136         m_rep = NULL;
137         return S_OK;
138     }
139 
140     HRESULT STDMETHODCALLTYPE ResourceRegisterSz(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType)
141     {
142         return RegisterWithResource(resFileName, szID, szType, TRUE);
143     }
144 
145     HRESULT STDMETHODCALLTYPE ResourceUnregisterSz(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType)
146     {
147         return RegisterWithResource(resFileName, szID, szType, FALSE);
148     }
149 
150     HRESULT STDMETHODCALLTYPE FileRegister(LPCOLESTR fileName)
151     {
152         return RegisterWithFile(fileName, TRUE);
153     }
154 
155     HRESULT STDMETHODCALLTYPE FileUnregister(LPCOLESTR fileName)
156     {
157         return RegisterWithFile(fileName, FALSE);
158     }
159 
160     HRESULT STDMETHODCALLTYPE StringRegister(LPCOLESTR data)
161     {
162         return RegisterWithString(data, TRUE);
163     }
164 
165     HRESULT STDMETHODCALLTYPE StringUnregister(LPCOLESTR data)
166     {
167         return RegisterWithString(data, FALSE);
168     }
169 
170     HRESULT STDMETHODCALLTYPE ResourceRegister(LPCOLESTR resFileName, UINT nID, LPCOLESTR szType)
171     {
172         return ResourceRegisterSz(resFileName, MAKEINTRESOURCEW(nID), szType);
173     }
174 
175     HRESULT STDMETHODCALLTYPE ResourceUnregister(LPCOLESTR resFileName, UINT nID, LPCOLESTR szType)
176     {
177         return ResourceUnregisterSz(resFileName, MAKEINTRESOURCEW(nID), szType);
178     }
179 
180 protected:
181     HRESULT STDMETHODCALLTYPE RegisterWithResource(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType, BOOL doRegister)
182     {
183         return resource_register(resFileName, szID, szType, doRegister);
184     }
185 
186     HRESULT STDMETHODCALLTYPE RegisterWithFile(LPCOLESTR fileName, BOOL doRegister)
187     {
188         return file_register(fileName, doRegister);
189     }
190 
191     HRESULT STDMETHODCALLTYPE RegisterWithString(LPCOLESTR data, BOOL doRegister)
192     {
193         return string_register(data, doRegister);
194     }
195 
196 private:
197     inline LONG RegDeleteTreeX(HKEY parentKey, LPCWSTR subKeyName)
198     {
199         wchar_t szBuffer[256];
200         DWORD dwSize;
201         FILETIME time;
202         HKEY childKey;
203         LONG lRes;
204 
205         ATLASSERT(parentKey != NULL);
206         lRes = RegOpenKeyExW(parentKey, subKeyName, 0, KEY_READ | KEY_WRITE, &childKey);
207         if (lRes != ERROR_SUCCESS)
208             return lRes;
209 
210         dwSize = sizeof(szBuffer) / sizeof(szBuffer[0]);
211         while (RegEnumKeyExW(parentKey, 0, szBuffer, &dwSize, NULL, NULL, NULL, &time) == ERROR_SUCCESS)
212         {
213             lRes = RegDeleteTreeX(childKey, szBuffer);
214             if (lRes != ERROR_SUCCESS)
215                 return lRes;
216             dwSize = sizeof(szBuffer) / sizeof(szBuffer[0]);
217         }
218         RegCloseKey(childKey);
219         return RegDeleteKeyW(parentKey, subKeyName);
220     }
221 
222     HRESULT strbuf_init(strbuf *buf)
223     {
224         buf->str = reinterpret_cast<LPOLESTR>(HeapAlloc(GetProcessHeap(), 0, 128 * sizeof(WCHAR)));
225         if (buf->str == NULL)
226             return E_OUTOFMEMORY;
227         buf->alloc = 128;
228         buf->len = 0;
229         return S_OK;
230     }
231 
232     HRESULT strbuf_write(LPCOLESTR str, strbuf *buf, int len)
233     {
234         LPOLESTR newBuffer;
235 
236         if (len == -1)
237             len = lstrlenW(str);
238         if (buf->len + len + 1 >= buf->alloc)
239         {
240             buf->alloc = (buf->len + len) * 2;
241             newBuffer = reinterpret_cast<LPOLESTR>(HeapReAlloc(GetProcessHeap(), 0, buf->str, buf->alloc * sizeof(WCHAR)));
242             if (newBuffer == NULL)
243                 return E_OUTOFMEMORY;
244             buf->str = newBuffer;
245         }
246         memcpy(buf->str + buf->len, str, len * sizeof(OLECHAR));
247         buf->len += len;
248         buf->str[buf->len] = '\0';
249         return S_OK;
250     }
251 
252 
253     HRESULT file_register(LPCOLESTR fileName, BOOL do_register)
254     {
255         HANDLE file;
256         DWORD filelen;
257         DWORD len;
258         LPWSTR regstrw;
259         LPSTR regstra;
260         LRESULT lres;
261         HRESULT hResult;
262 
263         file = CreateFileW(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
264         if (file != INVALID_HANDLE_VALUE)
265         {
266             filelen = GetFileSize(file, NULL);
267             regstra = reinterpret_cast<LPSTR>(HeapAlloc(GetProcessHeap(), 0, filelen));
268             if (regstra == NULL)
269                 return E_OUTOFMEMORY;
270             lres = ReadFile(file, regstra, filelen, NULL, NULL);
271             if (lres == ERROR_SUCCESS)
272             {
273                 len = MultiByteToWideChar(CP_ACP, 0, regstra, filelen, NULL, 0) + 1;
274                 regstrw = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)));
275                 if (regstrw == NULL)
276                 {
277                     HeapFree(GetProcessHeap(), 0, regstra);
278                     return E_OUTOFMEMORY;
279                 }
280                 MultiByteToWideChar(CP_ACP, 0, regstra, filelen, regstrw, len);
281                 regstrw[len - 1] = '\0';
282 
283                 hResult = string_register(regstrw, do_register);
284 
285                 HeapFree(GetProcessHeap(), 0, regstrw);
286             }
287             else
288             {
289                 hResult = HRESULT_FROM_WIN32(lres);
290             }
291             HeapFree(GetProcessHeap(), 0, regstra);
292             CloseHandle(file);
293         }
294         else
295         {
296             hResult = HRESULT_FROM_WIN32(GetLastError());
297         }
298 
299         return hResult;
300     }
301 
302     HRESULT resource_register(LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType, BOOL do_register)
303     {
304         HINSTANCE hins;
305         HRSRC src;
306         HGLOBAL regstra;
307         LPWSTR regstrw;
308         DWORD len;
309         DWORD reslen;
310         HRESULT hResult;
311 
312         hins = LoadLibraryExW(resFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
313         if (hins)
314         {
315             src = FindResourceW(hins, szID, szType);
316             if (src)
317             {
318                 regstra = LoadResource(hins, src);
319                 reslen = SizeofResource(hins, src);
320                 if (regstra)
321                 {
322                     len = MultiByteToWideChar(CP_ACP, 0, reinterpret_cast<LPCSTR>(regstra), reslen, NULL, 0) + 1;
323                     regstrw = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)));
324                     if (regstrw == NULL)
325                         return E_OUTOFMEMORY;
326                     MultiByteToWideChar(CP_ACP, 0, reinterpret_cast<LPCSTR>(regstra), reslen, regstrw, len);
327                     regstrw[len - 1] = '\0';
328 
329                     hResult = string_register(regstrw, do_register);
330 
331                     HeapFree(GetProcessHeap(), 0, regstrw);
332                 }
333                 else
334                     hResult = HRESULT_FROM_WIN32(GetLastError());
335             }
336             else
337                 hResult = HRESULT_FROM_WIN32(GetLastError());
338             FreeLibrary(hins);
339         }
340         else
341             hResult = HRESULT_FROM_WIN32(GetLastError());
342 
343         return hResult;
344     }
345 
346     HRESULT string_register(LPCOLESTR data, BOOL do_register)
347     {
348         strbuf buf;
349         HRESULT hResult;
350 
351         hResult = strbuf_init(&buf);
352         if (FAILED(hResult))
353             return hResult;
354         hResult = do_preprocess(data, &buf);
355         if (SUCCEEDED(hResult))
356         {
357             hResult = do_process_root_key(buf.str, do_register);
358             if (FAILED(hResult) && do_register)
359                 do_process_root_key(buf.str, FALSE);
360         }
361 
362         HeapFree(GetProcessHeap(), 0, buf.str);
363         return hResult;
364     }
365 
366     HRESULT do_preprocess(LPCOLESTR data, strbuf *buf)
367     {
368         LPCOLESTR iter;
369         LPCOLESTR iter2;
370         rep_list *rep_iter;
371         HRESULT hResult;
372 
373         iter2 = data;
374         iter = wcschr(data, '%');
375         while (iter)
376         {
377             hResult = strbuf_write(iter2, buf, static_cast<int>(iter - iter2));
378             if (FAILED(hResult))
379                 return hResult;
380 
381             iter2 = ++iter;
382             if (!*iter2)
383                 return DISP_E_EXCEPTION;
384             iter = wcschr(iter2, '%');
385             if (!iter)
386                 return DISP_E_EXCEPTION;
387 
388             if (iter == iter2)
389             {
390                 hResult = strbuf_write(L"%", buf, 1);
391                 if (FAILED(hResult))
392                     return hResult;
393             }
394             else
395             {
396                 for (rep_iter = m_rep; rep_iter; rep_iter = rep_iter->next)
397                 {
398                     if (rep_iter->key_len == iter - iter2 && !_memicmp(iter2, rep_iter->key, rep_iter->key_len * sizeof(wchar_t)))
399                         break;
400                 }
401                 if (!rep_iter)
402                     return DISP_E_EXCEPTION;
403 
404                 hResult = strbuf_write(rep_iter->item, buf, -1);
405                 if (FAILED(hResult))
406                     return hResult;
407             }
408 
409             iter2 = ++iter;
410             iter = wcschr(iter, '%');
411         }
412 
413         hResult = strbuf_write(iter2, buf, -1);
414         if (FAILED(hResult))
415             return hResult;
416 
417         return S_OK;
418     }
419 
420     HRESULT get_word(LPCOLESTR *str, strbuf *buf)
421     {
422         LPCOLESTR iter;
423         LPCOLESTR iter2;
424         HRESULT hResult;
425 
426         iter2 = *str;
427         buf->len = 0;
428         buf->str[0] = '\0';
429 
430         while (iswspace (*iter2))
431             iter2++;
432         iter = iter2;
433         if (!*iter)
434         {
435             *str = iter;
436             return S_OK;
437         }
438 
439         if (*iter == '}' || *iter == '=')
440         {
441             hResult = strbuf_write(iter++, buf, 1);
442             if (FAILED(hResult))
443                 return hResult;
444         }
445         else if (*iter == '\'')
446         {
447             iter2 = ++iter;
448             iter = wcschr(iter, '\'');
449             if (!iter)
450             {
451                 *str = iter;
452                 return DISP_E_EXCEPTION;
453             }
454             hResult = strbuf_write(iter2, buf, static_cast<int>(iter - iter2));
455             if (FAILED(hResult))
456                 return hResult;
457             iter++;
458         }
459         else
460         {
461             while (*iter && !iswspace(*iter))
462                 iter++;
463             hResult = strbuf_write(iter2, buf, static_cast<int>(iter - iter2));
464             if (FAILED(hResult))
465                 return hResult;
466         }
467 
468         while (iswspace(*iter))
469             iter++;
470         *str = iter;
471         return S_OK;
472     }
473 
474     inline unsigned int HexToBin(OLECHAR a)
475     {
476         if (a >= '0' && a <= '9')
477             return a - '0';
478         if (a >= 'A' && a <= 'F')
479             return a - 'A' + 10;
480         if (a >= 'a' && a <= 'f')
481             return a - 'a' + 10;
482         ATLASSERT(false);
483         return 0;
484     }
485 
486     HRESULT do_process_key(LPCOLESTR *pstr, HKEY parent_key, strbuf *buf, BOOL do_register)
487     {
488         LPCOLESTR iter;
489         HRESULT hres;
490         LONG lres;
491         HKEY hkey;
492         strbuf name;
493 
494         enum {
495             NORMAL,
496             NO_REMOVE,
497             IS_VAL,
498             FORCE_REMOVE,
499             DO_DELETE
500         } key_type = NORMAL;
501 
502         static const wchar_t *wstrNoRemove = L"NoRemove";
503         static const wchar_t *wstrForceRemove = L"ForceRemove";
504         static const wchar_t *wstrDelete = L"Delete";
505         static const wchar_t *wstrval = L"val";
506 
507         iter = *pstr;
508         hkey = NULL;
509         hres = get_word(&iter, buf);
510         if (FAILED(hres))
511             return hres;
512         hres = strbuf_init(&name);
513         if (FAILED(hres))
514             return hres;
515 
516         while(buf->str[1] || buf->str[0] != '}')
517         {
518             key_type = NORMAL;
519             if (!lstrcmpiW(buf->str, wstrNoRemove))
520                 key_type = NO_REMOVE;
521             else if (!lstrcmpiW(buf->str, wstrForceRemove))
522                 key_type = FORCE_REMOVE;
523             else if (!lstrcmpiW(buf->str, wstrval))
524                 key_type = IS_VAL;
525             else if (!lstrcmpiW(buf->str, wstrDelete))
526                 key_type = DO_DELETE;
527 
528             if (key_type != NORMAL)
529             {
530                 hres = get_word(&iter, buf);
531                 if (FAILED(hres))
532                     break;
533             }
534 
535             if (do_register)
536             {
537                 if (key_type == IS_VAL)
538                 {
539                     hkey = parent_key;
540                     hres = strbuf_write(buf->str, &name, -1);
541                     if (FAILED(hres))
542                         return hres;
543                 }
544                 else if (key_type == DO_DELETE)
545                 {
546                     RegDeleteTreeX(parent_key, buf->str);
547                 }
548                 else
549                 {
550                     if (key_type == FORCE_REMOVE)
551                         RegDeleteTreeX(parent_key, buf->str);
552                     lres = RegCreateKeyW(parent_key, buf->str, &hkey);
553                     if (lres != ERROR_SUCCESS)
554                     {
555                         hres = HRESULT_FROM_WIN32(lres);
556                         break;
557                     }
558                 }
559             }
560             else if (key_type != IS_VAL && key_type != DO_DELETE)
561             {
562                 hres = strbuf_write(buf->str, &name, -1);
563                 if (FAILED(hres))
564                     return hres;
565                 lres = RegOpenKeyW(parent_key, buf->str, &hkey);
566                 if (lres != ERROR_SUCCESS)
567                 {
568                 }
569             }
570 
571             if (key_type != DO_DELETE && *iter == '=')
572             {
573                 iter++;
574                 hres = get_word(&iter, buf);
575                 if (FAILED(hres))
576                     break;
577                 if (buf->len != 1)
578                 {
579                     hres = DISP_E_EXCEPTION;
580                     break;
581                 }
582                 if (do_register)
583                 {
584                     switch(buf->str[0])
585                     {
586                         case 's':
587                             hres = get_word(&iter, buf);
588                             if (FAILED(hres))
589                                 break;
590                             lres = RegSetValueExW(hkey, name.len ? name.str :  NULL, 0, REG_SZ, (PBYTE)buf->str,
591                                     (lstrlenW(buf->str) + 1) * sizeof(WCHAR));
592                             if (lres != ERROR_SUCCESS)
593                                 hres = HRESULT_FROM_WIN32(lres);
594                             break;
595                         case 'e':
596                             hres = get_word(&iter, buf);
597                             if (FAILED(hres))
598                                 break;
599                             lres = RegSetValueExW(hkey, name.len ? name.str :  NULL, 0, REG_EXPAND_SZ, (PBYTE)buf->str,
600                                     (lstrlenW(buf->str) + 1) * sizeof(WCHAR));
601                             if (lres != ERROR_SUCCESS)
602                                 hres = HRESULT_FROM_WIN32(lres);
603                             break;
604                         case 'd':
605                             {
606                                 hres = get_word(&iter, buf);
607                                 if (FAILED(hres))
608                                     break;
609                                 WCHAR *end;
610                                 DWORD dw;
611                                 if ((buf->str[0] == '0' && buf->str[1] == 'x') || (buf->str[0] == '&' && buf->str[1] == 'H'))
612                                     dw = wcstoul(&buf->str[2], &end, 16);
613                                 else
614                                     dw = wcstol(&buf->str[0], &end, 10);
615                                 lres = RegSetValueExW(hkey, name.len ? name.str :  NULL, 0, REG_DWORD, (PBYTE)&dw, sizeof(dw));
616                                 if (lres != ERROR_SUCCESS)
617                                     hres = HRESULT_FROM_WIN32(lres);
618                                 break;
619                             }
620                         case 'b':
621                             {
622                                 DWORD            count;
623                                 DWORD            curIndex;
624 
625                                 hres = get_word(&iter, buf);
626                                 if (FAILED(hres))
627                                     break;
628                                 count = buf->len;
629                                 if ((count & 1) != 0)
630                                     return DISP_E_EXCEPTION;
631                                 count = count / 2;
632                                 for (curIndex = 0; curIndex < count; curIndex++)
633                                     ((BYTE*)buf->str)[curIndex] = (HexToBin(buf->str[curIndex * 2]) << 4) | HexToBin(buf->str[curIndex * 2 + 1]);
634                                 lres = RegSetValueExW(hkey, name.len ? name.str :  NULL, 0, REG_BINARY, (PBYTE)buf->str, count);
635                                 if (lres != ERROR_SUCCESS)
636                                     hres = HRESULT_FROM_WIN32(lres);
637                                 break;
638                             }
639                         default:
640                             hres = DISP_E_EXCEPTION;
641                     }
642                     if (FAILED(hres))
643                         break;
644                 }
645                 else
646                 {
647                     if (*iter == '-')
648                         iter++;
649                     hres = get_word(&iter, buf);
650                     if (FAILED(hres))
651                         break;
652                 }
653             }
654             else if(key_type == IS_VAL)
655             {
656                 hres = DISP_E_EXCEPTION;
657                 break;
658             }
659 
660             if (key_type != IS_VAL && key_type != DO_DELETE && *iter == '{' && iswspace(iter[1]))
661             {
662                 hres = get_word(&iter, buf);
663                 if (FAILED(hres))
664                     break;
665                 hres = do_process_key(&iter, hkey, buf, do_register);
666                 if (FAILED(hres))
667                     break;
668             }
669 
670             if (!do_register && (key_type == NORMAL || key_type == FORCE_REMOVE))
671             {
672                 RegDeleteKeyW(parent_key, name.str);
673             }
674 
675             if (hkey && key_type != IS_VAL)
676                 RegCloseKey(hkey);
677             hkey = 0;
678             name.len = 0;
679 
680             hres = get_word(&iter, buf);
681             if (FAILED(hres))
682                 break;
683         }
684 
685         HeapFree(GetProcessHeap(), 0, name.str);
686         if (hkey && key_type != IS_VAL)
687             RegCloseKey(hkey);
688         *pstr = iter;
689         return hres;
690     }
691 
692     HRESULT do_process_root_key(LPCOLESTR data, BOOL do_register)
693     {
694         LPCOLESTR iter;
695         strbuf buf;
696         unsigned int i;
697         HRESULT hResult;
698         static const struct {
699             const wchar_t *name;
700             HKEY key;
701         } root_keys[] = {
702             {L"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
703             {L"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
704             {L"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
705             {L"HKEY_USERS", HKEY_USERS},
706             {L"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA},
707             {L"HKEY_DYN_DATA", HKEY_DYN_DATA},
708             {L"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
709             {L"HKCR", HKEY_CLASSES_ROOT},
710             {L"HKCU", HKEY_CURRENT_USER},
711             {L"HKLM", HKEY_LOCAL_MACHINE},
712             {L"HKU", HKEY_USERS},
713             {L"HKPD", HKEY_PERFORMANCE_DATA},
714             {L"HKDD", HKEY_DYN_DATA},
715             {L"HKCC", HKEY_CURRENT_CONFIG},
716         };
717 
718         iter = data;
719 
720         hResult = strbuf_init(&buf);
721         if (FAILED(hResult))
722             return hResult;
723         hResult = get_word(&iter, &buf);
724         if (FAILED(hResult))
725             return hResult;
726 
727         while (*iter)
728         {
729             if (!buf.len)
730             {
731                 hResult = DISP_E_EXCEPTION;
732                 break;
733             }
734             for (i = 0; i < sizeof(root_keys) / sizeof(root_keys[0]); i++)
735             {
736                 if (!lstrcmpiW(buf.str, root_keys[i].name))
737                     break;
738             }
739             if (i == sizeof(root_keys) / sizeof(root_keys[0]))
740             {
741                 hResult = DISP_E_EXCEPTION;
742                 break;
743             }
744             hResult = get_word(&iter, &buf);
745             if (FAILED(hResult))
746                 break;
747             if (buf.str[1] || buf.str[0] != '{')
748             {
749                 hResult = DISP_E_EXCEPTION;
750                 break;
751             }
752             hResult = do_process_key(&iter, root_keys[i].key, &buf, do_register);
753             if (FAILED(hResult))
754                 break;
755             hResult = get_word(&iter, &buf);
756             if (FAILED(hResult))
757                 break;
758         }
759         HeapFree(GetProcessHeap(), 0, buf.str);
760         return hResult;
761     }
762 
763 };
764 
765 }; //namespace ATL
766