xref: /reactos/dll/win32/atl/registrar.c (revision c2c66aff)
1 /*
2  * Copyright 2005 Jacek Caban
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <precomp.h>
20 
21 
22 /**************************************************************
23  * ATLRegistrar implementation
24  */
25 
26 static const struct {
27     WCHAR name[22];
28     HKEY  key;
29 } root_keys[] = {
30     {{'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0},
31                     HKEY_CLASSES_ROOT},
32     {{'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0},
33                     HKEY_CURRENT_USER},
34     {{'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0},
35                     HKEY_LOCAL_MACHINE},
36     {{'H','K','E','Y','_','U','S','E','R','S',0},
37                     HKEY_USERS},
38     {{'H','K','E','Y','_','P','E','R','F','O','R','M','A','N','C','E','_','D','A','T','A',0},
39                     HKEY_PERFORMANCE_DATA},
40     {{'H','K','E','Y','_','D','Y','N','_','D','A','T','A',0},
41                     HKEY_DYN_DATA},
42     {{'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0},
43                     HKEY_CURRENT_CONFIG},
44     {{'H','K','C','R',0}, HKEY_CLASSES_ROOT},
45     {{'H','K','C','U',0}, HKEY_CURRENT_USER},
46     {{'H','K','L','M',0}, HKEY_LOCAL_MACHINE},
47     {{'H','K','U',0},     HKEY_USERS},
48     {{'H','K','P','D',0}, HKEY_PERFORMANCE_DATA},
49     {{'H','K','D','D',0}, HKEY_DYN_DATA},
50     {{'H','K','C','C',0}, HKEY_CURRENT_CONFIG}
51 };
52 
53 typedef struct rep_list_str {
54     LPOLESTR key;
55     LPOLESTR item;
56     int key_len;
57     struct rep_list_str *next;
58 } rep_list;
59 
60 typedef struct {
61     IRegistrar IRegistrar_iface;
62     LONG ref;
63     rep_list *rep;
64 } Registrar;
65 
66 typedef struct {
67     LPOLESTR str;
68     DWORD alloc;
69     DWORD len;
70 } strbuf;
71 
72 static inline Registrar *impl_from_IRegistrar(IRegistrar *iface)
73 {
74     return CONTAINING_RECORD(iface, Registrar, IRegistrar_iface);
75 }
76 
77 static void strbuf_init(strbuf *buf)
78 {
79     buf->str = HeapAlloc(GetProcessHeap(), 0, 128*sizeof(WCHAR));
80     buf->alloc = 128;
81     buf->len = 0;
82 }
83 
84 static void strbuf_write(LPCOLESTR str, strbuf *buf, int len)
85 {
86     if(len == -1)
87         len = lstrlenW(str);
88     if(buf->len+len+1 >= buf->alloc) {
89         buf->alloc = (buf->len+len)<<1;
90         buf->str = HeapReAlloc(GetProcessHeap(), 0, buf->str, buf->alloc*sizeof(WCHAR));
91     }
92     memcpy(buf->str+buf->len, str, len*sizeof(OLECHAR));
93     buf->len += len;
94     buf->str[buf->len] = '\0';
95 }
96 
97 static HRESULT get_word(LPCOLESTR *str, strbuf *buf)
98 {
99     LPCOLESTR iter, iter2 = *str;
100 
101     buf->len = 0;
102     buf->str[0] = '\0';
103 
104     while(isspaceW(*iter2))
105         iter2++;
106     iter = iter2;
107     if(!*iter) {
108         *str = iter;
109         return S_OK;
110     }
111 
112     if(*iter == '}' || *iter == '=') {
113         strbuf_write(iter++, buf, 1);
114     }else if(*iter == '\'') {
115         iter2 = ++iter;
116         iter = strchrW(iter, '\'');
117         if(!iter) {
118             WARN("Unexpected end of script\n");
119             *str = iter;
120             return DISP_E_EXCEPTION;
121         }
122         strbuf_write(iter2, buf, iter-iter2);
123         iter++;
124     }else {
125         while(*iter && !isspaceW(*iter))
126             iter++;
127         strbuf_write(iter2, buf, iter-iter2);
128     }
129 
130     while(isspaceW(*iter))
131         iter++;
132     *str = iter;
133     return S_OK;
134 }
135 
136 static HRESULT do_preprocess(const Registrar *This, LPCOLESTR data, strbuf *buf)
137 {
138     LPCOLESTR iter, iter2 = data;
139     rep_list *rep_iter;
140     static const WCHAR wstr[] = {'%',0};
141 
142     iter = strchrW(data, '%');
143     while(iter) {
144         strbuf_write(iter2, buf, iter-iter2);
145 
146         iter2 = ++iter;
147         if(!*iter2)
148             return DISP_E_EXCEPTION;
149         iter = strchrW(iter2, '%');
150         if(!iter)
151             return DISP_E_EXCEPTION;
152 
153         if(iter == iter2) {
154             strbuf_write(wstr, buf, 1);
155         }else {
156             for(rep_iter = This->rep; rep_iter; rep_iter = rep_iter->next) {
157                 if(rep_iter->key_len == iter-iter2
158                         && !memicmpW(iter2, rep_iter->key, rep_iter->key_len))
159                     break;
160             }
161             if(!rep_iter) {
162                 WARN("Could not find replacement: %s\n", debugstr_wn(iter2, iter-iter2));
163                 return DISP_E_EXCEPTION;
164             }
165 
166             strbuf_write(rep_iter->item, buf, -1);
167         }
168 
169         iter2 = ++iter;
170         iter = strchrW(iter, '%');
171     }
172 
173     strbuf_write(iter2, buf, -1);
174     TRACE("%s\n", debugstr_w(buf->str));
175 
176     return S_OK;
177 }
178 
179 static HRESULT do_process_key(LPCOLESTR *pstr, HKEY parent_key, strbuf *buf, BOOL do_register)
180 {
181     LPCOLESTR iter;
182     HRESULT hres;
183     LONG lres;
184     HKEY hkey = 0;
185     strbuf name;
186 
187     enum {
188         NORMAL,
189         NO_REMOVE,
190         IS_VAL,
191         FORCE_REMOVE,
192         DO_DELETE
193     } key_type = NORMAL;
194 
195     static const WCHAR wstrNoRemove[] = {'N','o','R','e','m','o','v','e',0};
196     static const WCHAR wstrForceRemove[] = {'F','o','r','c','e','R','e','m','o','v','e',0};
197     static const WCHAR wstrDelete[] = {'D','e','l','e','t','e',0};
198     static const WCHAR wstrval[] = {'v','a','l',0};
199 
200     iter = *pstr;
201     hres = get_word(&iter, buf);
202     if(FAILED(hres))
203         return hres;
204     strbuf_init(&name);
205 
206     while(buf->str[1] || buf->str[0] != '}') {
207         key_type = NORMAL;
208         if(!lstrcmpiW(buf->str, wstrNoRemove))
209             key_type = NO_REMOVE;
210         else if(!lstrcmpiW(buf->str, wstrForceRemove))
211             key_type = FORCE_REMOVE;
212         else if(!lstrcmpiW(buf->str, wstrval))
213             key_type = IS_VAL;
214         else if(!lstrcmpiW(buf->str, wstrDelete))
215             key_type = DO_DELETE;
216 
217         if(key_type != NORMAL) {
218             hres = get_word(&iter, buf);
219             if(FAILED(hres))
220                 break;
221         }
222         TRACE("name = %s\n", debugstr_w(buf->str));
223 
224         if(do_register) {
225             if(key_type == IS_VAL) {
226                 hkey = parent_key;
227                 strbuf_write(buf->str, &name, -1);
228             }else if(key_type == DO_DELETE) {
229                 TRACE("Deleting %s\n", debugstr_w(buf->str));
230                 RegDeleteTreeW(parent_key, buf->str);
231             }else {
232                 if(key_type == FORCE_REMOVE)
233                     RegDeleteTreeW(parent_key, buf->str);
234                 lres = RegCreateKeyW(parent_key, buf->str, &hkey);
235                 if(lres != ERROR_SUCCESS) {
236                     WARN("Could not create(open) key: %08x\n", lres);
237                     hres = HRESULT_FROM_WIN32(lres);
238                     break;
239                 }
240             }
241         }else if(key_type != IS_VAL && key_type != DO_DELETE) {
242             strbuf_write(buf->str, &name, -1);
243             lres = RegOpenKeyW(parent_key, buf->str, &hkey);
244               if(lres != ERROR_SUCCESS)
245                 WARN("Could not open key %s: %08x\n", debugstr_w(name.str), lres);
246         }
247 
248         if(key_type != DO_DELETE && *iter == '=') {
249             iter++;
250             hres = get_word(&iter, buf);
251             if(FAILED(hres))
252                 break;
253             if(buf->len != 1) {
254                 WARN("Wrong registry type: %s\n", debugstr_w(buf->str));
255                 hres = DISP_E_EXCEPTION;
256                 break;
257             }
258             if(do_register) {
259                 switch(buf->str[0]) {
260                 case 's':
261                     hres = get_word(&iter, buf);
262                     if(FAILED(hres))
263                         break;
264                     lres = RegSetValueExW(hkey, name.len ? name.str :  NULL, 0, REG_SZ, (PBYTE)buf->str,
265                             (lstrlenW(buf->str)+1)*sizeof(WCHAR));
266                     if(lres != ERROR_SUCCESS) {
267                         WARN("Could set value of key: %08x\n", lres);
268                         hres = HRESULT_FROM_WIN32(lres);
269                         break;
270                     }
271                     break;
272                 case 'd': {
273                     DWORD dw;
274                     hres = get_word(&iter, buf);
275                     if(FAILED(hres))
276                         break;
277                     dw = atoiW(buf->str);
278                     lres = RegSetValueExW(hkey, name.len ? name.str :  NULL, 0, REG_DWORD,
279                             (PBYTE)&dw, sizeof(dw));
280                     if(lres != ERROR_SUCCESS) {
281                         WARN("Could set value of key: %08x\n", lres);
282                         hres = HRESULT_FROM_WIN32(lres);
283                         break;
284                     }
285                     break;
286                 }
287                 case 'b': {
288                     BYTE *bytes;
289                     DWORD count;
290                     DWORD i;
291                     hres = get_word(&iter, buf);
292                     if(FAILED(hres))
293                         break;
294                     count = (lstrlenW(buf->str) + 1) / 2;
295                     bytes = HeapAlloc(GetProcessHeap(), 0, count);
296                     if(bytes == NULL) {
297                         hres = E_OUTOFMEMORY;
298                         break;
299                     }
300                     for(i = 0; i < count && buf->str[2*i]; i++) {
301                         WCHAR digits[3];
302                         if(!isxdigitW(buf->str[2*i]) || !isxdigitW(buf->str[2*i + 1])) {
303                             hres = E_FAIL;
304                             break;
305                         }
306                         digits[0] = buf->str[2*i];
307                         digits[1] = buf->str[2*i + 1];
308                         digits[2] = 0;
309                         bytes[i] = (BYTE) strtoulW(digits, NULL, 16);
310                     }
311                     if(SUCCEEDED(hres)) {
312                         lres = RegSetValueExW(hkey, name.len ? name.str :  NULL, 0, REG_BINARY,
313                             bytes, count);
314                         if(lres != ERROR_SUCCESS) {
315                             WARN("Could not set value of key: 0x%08x\n", lres);
316                             hres = HRESULT_FROM_WIN32(lres);
317                         }
318                     }
319                     HeapFree(GetProcessHeap(), 0, bytes);
320                     break;
321                 }
322                 default:
323                     WARN("Wrong resource type: %s\n", debugstr_w(buf->str));
324                     hres = DISP_E_EXCEPTION;
325                 };
326                 if(FAILED(hres))
327                     break;
328             }else {
329                 if(*iter == '-')
330                     iter++;
331                 hres = get_word(&iter, buf);
332                 if(FAILED(hres))
333                     break;
334             }
335         }else if(key_type == IS_VAL) {
336             WARN("value not set!\n");
337             hres = DISP_E_EXCEPTION;
338             break;
339         }
340 
341         if(key_type != IS_VAL && key_type != DO_DELETE && *iter == '{' && isspaceW(iter[1])) {
342             hres = get_word(&iter, buf);
343             if(FAILED(hres))
344                 break;
345             hres = do_process_key(&iter, hkey, buf, do_register);
346             if(FAILED(hres))
347                 break;
348         }
349 
350         TRACE("%x %x\n", do_register, key_type);
351         if(!do_register && (key_type == NORMAL || key_type == FORCE_REMOVE)) {
352             TRACE("Deleting %s\n", debugstr_w(name.str));
353             RegDeleteKeyW(parent_key, name.str);
354         }
355 
356         if(hkey && key_type != IS_VAL)
357             RegCloseKey(hkey);
358         hkey = 0;
359         name.len = 0;
360 
361         hres = get_word(&iter, buf);
362         if(FAILED(hres))
363             break;
364     }
365 
366     HeapFree(GetProcessHeap(), 0, name.str);
367     if(hkey && key_type != IS_VAL)
368         RegCloseKey(hkey);
369     *pstr = iter;
370     return hres;
371 }
372 
373 static HRESULT do_process_root_key(LPCOLESTR data, BOOL do_register)
374 {
375     LPCOLESTR iter = data;
376     strbuf buf;
377     HRESULT hres;
378     unsigned int i;
379 
380     strbuf_init(&buf);
381     hres = get_word(&iter, &buf);
382     if(FAILED(hres))
383         return hres;
384 
385     while(*iter) {
386         if(!buf.len) {
387             WARN("ward.len == 0, failed\n");
388             hres = DISP_E_EXCEPTION;
389             break;
390         }
391         for(i=0; i<sizeof(root_keys)/sizeof(root_keys[0]); i++) {
392             if(!lstrcmpiW(buf.str, root_keys[i].name))
393                 break;
394         }
395         if(i == sizeof(root_keys)/sizeof(root_keys[0])) {
396             WARN("Wrong root key name: %s\n", debugstr_w(buf.str));
397             hres = DISP_E_EXCEPTION;
398             break;
399         }
400         hres = get_word(&iter, &buf);
401         if(FAILED(hres))
402             break;
403         if(buf.str[1] || buf.str[0] != '{') {
404             WARN("Failed, expected '{', got %s\n", debugstr_w(buf.str));
405             hres = DISP_E_EXCEPTION;
406             break;
407         }
408         hres = do_process_key(&iter, root_keys[i].key, &buf, do_register);
409         if(FAILED(hres)) {
410             WARN("Processing key failed: %08x\n", hres);
411             break;
412         }
413         hres = get_word(&iter, &buf);
414         if(FAILED(hres))
415             break;
416     }
417     HeapFree(GetProcessHeap(), 0, buf.str);
418     return hres;
419 }
420 
421 static HRESULT string_register(Registrar *This, LPCOLESTR data, BOOL do_register)
422 {
423     strbuf buf;
424     HRESULT hres;
425 
426     TRACE("(%p %s %x)\n", This, debugstr_w(data), do_register);
427 
428     strbuf_init(&buf);
429     hres = do_preprocess(This, data, &buf);
430     if(FAILED(hres)) {
431         WARN("preprocessing failed!\n");
432         HeapFree(GetProcessHeap(), 0, buf.str);
433         return hres;
434     }
435 
436     hres = do_process_root_key(buf.str, do_register);
437     if(FAILED(hres) && do_register)
438         do_process_root_key(buf.str, FALSE);
439 
440     HeapFree(GetProcessHeap(), 0, buf.str);
441     return hres;
442 }
443 
444 static HRESULT resource_register(Registrar *This, LPCOLESTR resFileName,
445                         LPCOLESTR szID, LPCOLESTR szType, BOOL do_register)
446 {
447     HINSTANCE hins;
448     HRSRC src;
449     LPSTR regstra;
450     LPWSTR regstrw;
451     DWORD len, reslen;
452     HRESULT hres;
453 
454     hins = LoadLibraryExW(resFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
455     if(hins) {
456         src = FindResourceW(hins, szID, szType);
457         if(src) {
458             regstra = LoadResource(hins, src);
459             reslen = SizeofResource(hins, src);
460             if(regstra) {
461                 len = MultiByteToWideChar(CP_ACP, 0, regstra, reslen, NULL, 0)+1;
462                 regstrw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR));
463                 MultiByteToWideChar(CP_ACP, 0, regstra, reslen, regstrw, len);
464                 regstrw[len-1] = '\0';
465 
466                 hres = string_register(This, regstrw, do_register);
467 
468                 HeapFree(GetProcessHeap(), 0, regstrw);
469             }else {
470                 WARN("could not load resource\n");
471                 hres = HRESULT_FROM_WIN32(GetLastError());
472             }
473         }else {
474             WARN("Could not find source\n");
475             hres = HRESULT_FROM_WIN32(GetLastError());
476         }
477         FreeLibrary(hins);
478     }else {
479         WARN("Could not load resource file\n");
480         hres = HRESULT_FROM_WIN32(GetLastError());
481     }
482 
483     return hres;
484 }
485 
486 static HRESULT file_register(Registrar *This, LPCOLESTR fileName, BOOL do_register)
487 {
488     HANDLE file;
489     DWORD filelen, len;
490     LPWSTR regstrw;
491     LPSTR regstra;
492     HRESULT hres;
493 
494     file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
495     if(file != INVALID_HANDLE_VALUE) {
496         filelen = GetFileSize(file, NULL);
497         regstra = HeapAlloc(GetProcessHeap(), 0, filelen);
498         if(ReadFile(file, regstra, filelen, NULL, NULL)) {
499             len = MultiByteToWideChar(CP_ACP, 0, regstra, filelen, NULL, 0)+1;
500             regstrw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR));
501             MultiByteToWideChar(CP_ACP, 0, regstra, filelen, regstrw, len);
502             regstrw[len-1] = '\0';
503 
504             hres = string_register(This, regstrw, do_register);
505 
506             HeapFree(GetProcessHeap(), 0, regstrw);
507         }else {
508             WARN("Failed to read file %s\n", debugstr_w(fileName));
509             hres = HRESULT_FROM_WIN32(GetLastError());
510         }
511         HeapFree(GetProcessHeap(), 0, regstra);
512         CloseHandle(file);
513     }else {
514         WARN("Could not open file %s\n", debugstr_w(fileName));
515         hres = HRESULT_FROM_WIN32(GetLastError());
516     }
517 
518     return hres;
519 }
520 
521 static HRESULT WINAPI Registrar_QueryInterface(IRegistrar *iface, REFIID riid, void **ppvObject)
522 {
523     TRACE("(%p)->(%s %p\n", iface, debugstr_guid(riid), ppvObject);
524 
525     if(IsEqualGUID(&IID_IUnknown, riid)
526        || IsEqualGUID(&IID_IRegistrar, riid)
527        || IsEqualGUID(&IID_IRegistrarBase, riid)) {
528         IRegistrar_AddRef(iface);
529         *ppvObject = iface;
530         return S_OK;
531     }
532     return E_NOINTERFACE;
533 }
534 
535 static ULONG WINAPI Registrar_AddRef(IRegistrar *iface)
536 {
537     Registrar *This = impl_from_IRegistrar(iface);
538     ULONG ref = InterlockedIncrement(&This->ref);
539     TRACE("(%p) ->%d\n", This, ref);
540     return ref;
541 }
542 
543 static ULONG WINAPI Registrar_Release(IRegistrar *iface)
544 {
545     Registrar *This = impl_from_IRegistrar(iface);
546     ULONG ref = InterlockedDecrement(&This->ref);
547 
548     TRACE("(%p) ->%d\n", This, ref);
549     if(!ref) {
550         IRegistrar_ClearReplacements(iface);
551         HeapFree(GetProcessHeap(), 0, This);
552     }
553     return ref;
554 }
555 
556 static HRESULT WINAPI Registrar_AddReplacement(IRegistrar *iface, LPCOLESTR Key, LPCOLESTR item)
557 {
558     Registrar *This = impl_from_IRegistrar(iface);
559     int len;
560     rep_list *new_rep;
561 
562     TRACE("(%p)->(%s %s)\n", This, debugstr_w(Key), debugstr_w(item));
563 
564     new_rep = HeapAlloc(GetProcessHeap(), 0, sizeof(rep_list));
565 
566     new_rep->key_len  = lstrlenW(Key);
567     new_rep->key = HeapAlloc(GetProcessHeap(), 0, (new_rep->key_len + 1) * sizeof(OLECHAR));
568     memcpy(new_rep->key, Key, (new_rep->key_len+1)*sizeof(OLECHAR));
569 
570     len = lstrlenW(item)+1;
571     new_rep->item = HeapAlloc(GetProcessHeap(), 0, len*sizeof(OLECHAR));
572     memcpy(new_rep->item, item, len*sizeof(OLECHAR));
573 
574     new_rep->next = This->rep;
575     This->rep = new_rep;
576 
577     return S_OK;
578 }
579 
580 static HRESULT WINAPI Registrar_ClearReplacements(IRegistrar *iface)
581 {
582     Registrar *This = impl_from_IRegistrar(iface);
583     rep_list *iter, *iter2;
584 
585     TRACE("(%p)\n", This);
586 
587     if(!This->rep)
588         return S_OK;
589 
590     iter = This->rep;
591     while(iter) {
592         iter2 = iter->next;
593         HeapFree(GetProcessHeap(), 0, iter->key);
594         HeapFree(GetProcessHeap(), 0, iter->item);
595         HeapFree(GetProcessHeap(), 0, iter);
596         iter = iter2;
597     }
598 
599     This->rep = NULL;
600     return S_OK;
601 }
602 
603 static HRESULT WINAPI Registrar_ResourceRegisterSz(IRegistrar* iface, LPCOLESTR resFileName,
604                 LPCOLESTR szID, LPCOLESTR szType)
605 {
606     Registrar *This = impl_from_IRegistrar(iface);
607     TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(resFileName), debugstr_w(szID), debugstr_w(szType));
608     return resource_register(This, resFileName, szID, szType, TRUE);
609 }
610 
611 static HRESULT WINAPI Registrar_ResourceUnregisterSz(IRegistrar* iface, LPCOLESTR resFileName,
612                 LPCOLESTR szID, LPCOLESTR szType)
613 {
614     Registrar *This = impl_from_IRegistrar(iface);
615     TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(resFileName), debugstr_w(szID), debugstr_w(szType));
616     return resource_register(This, resFileName, szID, szType, FALSE);
617 }
618 
619 static HRESULT WINAPI Registrar_FileRegister(IRegistrar* iface, LPCOLESTR fileName)
620 {
621     Registrar *This = impl_from_IRegistrar(iface);
622     TRACE("(%p)->(%s)\n", This, debugstr_w(fileName));
623     return file_register(This, fileName, TRUE);
624 }
625 
626 static HRESULT WINAPI Registrar_FileUnregister(IRegistrar* iface, LPCOLESTR fileName)
627 {
628     Registrar *This = impl_from_IRegistrar(iface);
629     FIXME("(%p)->(%s)\n", This, debugstr_w(fileName));
630     return file_register(This, fileName, FALSE);
631 }
632 
633 static HRESULT WINAPI Registrar_StringRegister(IRegistrar* iface, LPCOLESTR data)
634 {
635     Registrar *This = impl_from_IRegistrar(iface);
636     TRACE("(%p)->(%s)\n", This, debugstr_w(data));
637     return string_register(This, data, TRUE);
638 }
639 
640 static HRESULT WINAPI Registrar_StringUnregister(IRegistrar* iface, LPCOLESTR data)
641 {
642     Registrar *This = impl_from_IRegistrar(iface);
643     TRACE("(%p)->(%s)\n", This, debugstr_w(data));
644     return string_register(This, data, FALSE);
645 }
646 
647 static HRESULT WINAPI Registrar_ResourceRegister(IRegistrar* iface, LPCOLESTR resFileName,
648                 UINT nID, LPCOLESTR szType)
649 {
650     Registrar *This = impl_from_IRegistrar(iface);
651     TRACE("(%p)->(%s %d %s)\n", iface, debugstr_w(resFileName), nID, debugstr_w(szType));
652     return resource_register(This, resFileName, MAKEINTRESOURCEW(nID), szType, TRUE);
653 }
654 
655 static HRESULT WINAPI Registrar_ResourceUnregister(IRegistrar* iface, LPCOLESTR resFileName,
656                 UINT nID, LPCOLESTR szType)
657 {
658     Registrar *This = impl_from_IRegistrar(iface);
659     TRACE("(%p)->(%s %d %s)\n", This, debugstr_w(resFileName), nID, debugstr_w(szType));
660     return resource_register(This, resFileName, MAKEINTRESOURCEW(nID), szType, FALSE);
661 }
662 
663 static const IRegistrarVtbl RegistrarVtbl = {
664     Registrar_QueryInterface,
665     Registrar_AddRef,
666     Registrar_Release,
667     Registrar_AddReplacement,
668     Registrar_ClearReplacements,
669     Registrar_ResourceRegisterSz,
670     Registrar_ResourceUnregisterSz,
671     Registrar_FileRegister,
672     Registrar_FileUnregister,
673     Registrar_StringRegister,
674     Registrar_StringUnregister,
675     Registrar_ResourceRegister,
676     Registrar_ResourceUnregister,
677 };
678 
679 /***********************************************************************
680  *           AtlCreateRegistrar              [atl100.@]
681  */
682 HRESULT WINAPI AtlCreateRegistrar(IRegistrar **ret)
683 {
684     Registrar *registrar;
685 
686     registrar = HeapAlloc(GetProcessHeap(), 0, sizeof(*registrar));
687     if(!registrar)
688         return E_OUTOFMEMORY;
689 
690     registrar->IRegistrar_iface.lpVtbl = &RegistrarVtbl;
691     registrar->ref = 1;
692     registrar->rep = NULL;
693 
694     *ret = &registrar->IRegistrar_iface;
695     return S_OK;
696 }
697 
698 /***********************************************************************
699  *           AtlUpdateRegistryFromResourceD         [atl100.@]
700  */
701 HRESULT WINAPI AtlUpdateRegistryFromResourceD(HINSTANCE inst, LPCOLESTR res,
702         BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries, IRegistrar *pReg)
703 {
704     const struct _ATL_REGMAP_ENTRY *iter;
705     WCHAR module_name[MAX_PATH];
706     IRegistrar *registrar;
707     HRESULT hres;
708 
709     static const WCHAR moduleW[] = {'M','O','D','U','L','E',0};
710     static const WCHAR registryW[] = {'R','E','G','I','S','T','R','Y',0};
711 
712     if(!GetModuleFileNameW(inst, module_name, MAX_PATH)) {
713         FIXME("hinst %p: did not get module name\n", inst);
714         return E_FAIL;
715     }
716 
717     TRACE("%p (%s), %s, %d, %p, %p\n", inst, debugstr_w(module_name),
718 	debugstr_w(res), bRegister, pMapEntries, pReg);
719 
720     if(pReg) {
721         registrar = pReg;
722     }else {
723         hres = AtlCreateRegistrar(&registrar);
724         if(FAILED(hres))
725             return hres;
726     }
727 
728     IRegistrar_AddReplacement(registrar, moduleW, module_name);
729 
730     for (iter = pMapEntries; iter && iter->szKey; iter++)
731         IRegistrar_AddReplacement(registrar, iter->szKey, iter->szData);
732 
733     if(bRegister)
734         hres = IRegistrar_ResourceRegisterSz(registrar, module_name, res, registryW);
735     else
736         hres = IRegistrar_ResourceUnregisterSz(registrar, module_name, res, registryW);
737 
738     if(registrar != pReg)
739         IRegistrar_Release(registrar);
740     return hres;
741 }
742