2 * Copyright 2005 Jacek Caban
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(atl);
40 /**************************************************************
41 * ATLRegistrar implementation
48 {{'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0},
50 {{'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0},
52 {{'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0},
54 {{'H','K','E','Y','_','U','S','E','R','S',0},
56 {{'H','K','E','Y','_','P','E','R','F','O','R','M','A','N','C','E','_','D','A','T','A',0},
57 HKEY_PERFORMANCE_DATA},
58 {{'H','K','E','Y','_','D','Y','N','_','D','A','T','A',0},
60 {{'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0},
62 {{'H','K','C','R',0}, HKEY_CLASSES_ROOT},
63 {{'H','K','C','U',0}, HKEY_CURRENT_USER},
64 {{'H','K','L','M',0}, HKEY_LOCAL_MACHINE},
65 {{'H','K','U',0}, HKEY_USERS},
66 {{'H','K','P','D',0}, HKEY_PERFORMANCE_DATA},
67 {{'H','K','D','D',0}, HKEY_DYN_DATA},
68 {{'H','K','C','C',0}, HKEY_CURRENT_CONFIG}
71 typedef struct rep_list_str {
75 struct rep_list_str *next;
79 IRegistrarVtbl *lpVtbl;
90 static void strbuf_init(strbuf *buf)
92 buf->str = HeapAlloc(GetProcessHeap(), 0, 128*sizeof(WCHAR));
97 static void strbuf_write(LPCOLESTR str, strbuf *buf, int len)
101 if(buf->len+len+1 >= buf->alloc) {
102 buf->alloc = (buf->len+len)<<1;
103 buf->str = HeapReAlloc(GetProcessHeap(), 0, buf->str, buf->alloc*sizeof(WCHAR));
105 memcpy(buf->str+buf->len, str, len*sizeof(OLECHAR));
107 buf->str[buf->len] = '\0';
110 static HRESULT get_word(LPCOLESTR *str, strbuf *buf)
112 LPCOLESTR iter, iter2 = *str;
117 while(isspaceW(*iter2))
125 if(*iter == '{' || *iter == '}' || *iter == '=') {
126 strbuf_write(iter++, buf, 1);
127 }else if(*iter == '\'') {
129 iter = strchrW(iter, '\'');
131 WARN("Unexpected end of script\n");
133 return DISP_E_EXCEPTION;
135 strbuf_write(iter2, buf, iter-iter2);
138 while(*iter && !isspaceW(*iter))
140 strbuf_write(iter2, buf, iter-iter2);
143 while(isspaceW(*iter))
149 static HRESULT do_preprocess(Registrar *This, LPCOLESTR data, strbuf *buf)
151 LPCOLESTR iter, iter2 = data;
153 static const WCHAR wstr[] = {'%',0};
155 iter = strchrW(data, '%');
157 strbuf_write(iter2, buf, iter-iter2);
161 return DISP_E_EXCEPTION;
162 iter = strchrW(iter2, '%');
164 return DISP_E_EXCEPTION;
167 strbuf_write(wstr, buf, 1);
169 for(rep_iter = This->rep; rep_iter; rep_iter = rep_iter->next) {
170 if(rep_iter->key_len == iter-iter2
171 && !memcmp(iter2, rep_iter->key, rep_iter->key_len*sizeof(OLECHAR)))
175 return DISP_E_EXCEPTION;
177 strbuf_write(rep_iter->item, buf, -1);
181 iter = strchrW(iter, '%');
184 strbuf_write(iter2, buf, -1);
185 TRACE("%s\n", debugstr_w(buf->str));
190 static HRESULT do_process_key(LPCOLESTR *pstr, HKEY parent_key, strbuf *buf, BOOL do_register)
192 LPCOLESTR iter = *pstr;
193 BOOL no_remove = FALSE, is_val = FALSE, force_remove = FALSE, do_delete = FALSE;
199 static const WCHAR wstrNoRemove[] = {'N','o','R','e','m','o','v','e',0};
200 static const WCHAR wstrForceRemove[] = {'F','o','r','c','e','R','e','m','o','v','e',0};
201 static const WCHAR wstrDelete[] = {'D','e','l','e','t','e',0};
202 static const WCHAR wstrval[] = {'v','a','l',0};
205 hres = get_word(&iter, buf);
210 while(buf->str[1] || buf->str[0] != '}') {
211 if(!lstrcmpW(buf->str, wstrNoRemove)) {
213 }else if(!lstrcmpW(buf->str, wstrForceRemove)) {
215 }else if(!lstrcmpW(buf->str, wstrval)) {
217 }else if(!lstrcmpW(buf->str, wstrDelete)) {
220 TRACE("name = %s\n", debugstr_w(buf->str));
223 if(force_remove || no_remove || do_delete) {
224 WARN("Attribites for value!\n");
225 hres = DISP_E_EXCEPTION;
229 strbuf_write(buf->str, &name, -1);
230 }else if(do_delete) {
231 TRACE("Deleting %s\n", debugstr_w(buf->str));
232 lres = SHDeleteKeyW(parent_key, buf->str);
235 SHDeleteKeyW(parent_key, buf->str);
236 lres = RegCreateKeyW(parent_key, buf->str, &hkey);
237 if(lres != ERROR_SUCCESS) {
238 WARN("Could not create(open) key: %08lx\n", lres);
239 hres = HRESULT_FROM_WIN32(lres);
243 }else if(!is_val && !do_delete) {
244 strbuf_write(buf->str, &name, -1);
245 lres = RegOpenKeyW(parent_key, buf->str, &hkey);
246 if(lres != ERROR_SUCCESS)
247 WARN("Could not open key %s: %08lx\n", debugstr_w(name.str), lres);
249 if(!do_delete && *iter == '=') {
251 hres = get_word(&iter, buf);
255 WARN("Wrong registry type: %s\n", debugstr_w(buf->str));
256 hres = DISP_E_EXCEPTION;
260 switch(buf->str[0]) {
262 hres = get_word(&iter, buf);
265 lres = RegSetValueExW(hkey, name.len ? name.str : NULL, 0, REG_SZ, (PBYTE)buf->str,
266 (lstrlenW(buf->str)+1)*sizeof(WCHAR));
267 if(lres != ERROR_SUCCESS) {
268 WARN("Could set value of key: %08lx\n", lres);
269 hres = HRESULT_FROM_WIN32(lres);
275 if(*iter == '0' && iter[1] == 'x') {
277 dw = strtolW(iter, (WCHAR**)&iter, 16);
279 dw = strtolW(iter, (WCHAR**)&iter, 10);
281 lres = RegSetValueExW(hkey, name.len ? name.str : NULL, 0, REG_DWORD,
282 (PBYTE)&dw, sizeof(dw));
283 if(lres != ERROR_SUCCESS) {
284 WARN("Could set value of key: %08lx\n", lres);
285 hres = HRESULT_FROM_WIN32(lres);
291 WARN("Wrong resource type: %s\n", debugstr_w(buf->str));
292 hres = DISP_E_EXCEPTION;
299 hres = get_word(&iter, buf);
304 WARN("value not set!\n");
305 hres = DISP_E_EXCEPTION;
308 if(!is_val && !do_delete && *iter == '{') {
309 hres = get_word(&iter, buf);
312 hres = do_process_key(&iter, hkey, buf, do_register);
316 if(!do_register && !do_delete && !is_val && !no_remove) {
317 TRACE("Deleting %s\n", debugstr_w(name.str));
318 RegDeleteKeyW(parent_key, name.str);
324 no_remove = is_val = force_remove = do_delete = FALSE;
326 hres = get_word(&iter, buf);
331 HeapFree(GetProcessHeap(), 0, name.str);
338 static HRESULT do_process_root_key(LPCOLESTR data, BOOL do_register)
340 LPCOLESTR iter = data;
346 hres = get_word(&iter, &buf);
352 WARN("ward.len == 0, failed\n");
353 hres = DISP_E_EXCEPTION;
356 for(i=0; i<sizeof(root_keys)/sizeof(root_keys[0]); i++) {
357 if(!lstrcmpW(buf.str, root_keys[i].name))
360 if(i == sizeof(root_keys)/sizeof(root_keys[0])) {
361 WARN("Wrong root key name: %s\n", debugstr_w(buf.str));
362 hres = DISP_E_EXCEPTION;
365 hres = get_word(&iter, &buf);
368 if(buf.str[1] || buf.str[0] != '{') {
369 WARN("Failed, expected '{', got %s\n", debugstr_w(buf.str));
370 hres = DISP_E_EXCEPTION;
373 hres = do_process_key(&iter, root_keys[i].key, &buf, do_register);
375 WARN("Processing key failed: %08lx\n", hres);
378 hres = get_word(&iter, &buf);
382 HeapFree(GetProcessHeap(), 0, buf.str);
386 static HRESULT string_register(Registrar *This, LPCOLESTR data, BOOL do_register)
391 TRACE("(%p %s %x)\n", This, debugstr_w(data), do_register);
394 hres = do_preprocess(This, data, &buf);
396 WARN("preprocessing failed!\n");
397 HeapFree(GetProcessHeap(), 0, buf.str);
401 hres = do_process_root_key(buf.str, do_register);
402 if(FAILED(hres) && do_register)
403 do_process_root_key(buf.str, FALSE);
405 HeapFree(GetProcessHeap(), 0, buf.str);
409 static HRESULT resource_register(Registrar *This, LPCOLESTR resFileName,
410 UINT nID, LPCOLESTR szType, BOOL do_register)
419 hins = LoadLibraryExW(resFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
421 src = FindResourceW(hins, (LPWSTR)nID, szType);
423 regstra = (LPSTR)LoadResource(hins, src);
424 reslen = SizeofResource(hins, src);
426 len = MultiByteToWideChar(CP_ACP, 0, regstra, reslen, NULL, 0)+1;
427 regstrw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR));
428 MultiByteToWideChar(CP_ACP, 0, regstra, reslen, regstrw, -1);
429 regstrw[len-1] = '\0';
431 hres = string_register(This, regstrw, do_register);
433 HeapFree(GetProcessHeap(), 0, regstrw);
434 HeapFree(GetProcessHeap(), 0, regstra);
436 WARN("could not load resource\n");
437 hres = HRESULT_FROM_WIN32(GetLastError());
440 WARN("Could not find source\n");
441 hres = HRESULT_FROM_WIN32(GetLastError());
445 WARN("Could not load resource file\n");
446 hres = HRESULT_FROM_WIN32(GetLastError());
452 static HRESULT WINAPI Registrar_QueryInterface(IRegistrar *iface, REFIID riid, void **ppvObject)
454 TRACE("(%p)->(%s %p\n", iface, debugstr_guid(riid), ppvObject);
456 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRegistrar, riid)) {
457 IRegistrar_AddRef(iface);
461 return E_NOINTERFACE;
464 static ULONG WINAPI Registrar_AddRef(IRegistrar *iface)
466 Registrar *This = (Registrar*)iface;
467 ULONG ref = InterlockedIncrement(&This->ref);
468 TRACE("(%p) ->%ld\n", This, ref);
472 static ULONG WINAPI Registrar_Release(IRegistrar *iface)
474 Registrar *This = (Registrar*)iface;
475 ULONG ref = InterlockedDecrement(&This->ref);
477 TRACE("(%p) ->%ld\n", This, ref);
479 IRegistrar_ClearReplacements(iface);
480 HeapFree(GetProcessHeap(), 0, This);
485 static HRESULT WINAPI Registrar_AddReplacement(IRegistrar *iface, LPCOLESTR Key, LPCOLESTR item)
487 Registrar *This = (Registrar*)iface;
491 TRACE("(%p)->(%s %s)\n", This, debugstr_w(Key), debugstr_w(item));
493 new_rep = HeapAlloc(GetProcessHeap(), 0, sizeof(rep_list));
495 new_rep->key_len = lstrlenW(Key);
496 new_rep->key = HeapAlloc(GetProcessHeap(), 0, new_rep->key_len*sizeof(OLECHAR)+1);
497 memcpy(new_rep->key, Key, (new_rep->key_len+1)*sizeof(OLECHAR));
499 len = lstrlenW(item)+1;
500 new_rep->item = HeapAlloc(GetProcessHeap(), 0, len*sizeof(OLECHAR));
501 memcpy(new_rep->item, item, len*sizeof(OLECHAR));
503 new_rep->next = This->rep;
509 static HRESULT WINAPI Registrar_ClearReplacements(IRegistrar *iface)
511 Registrar *This = (Registrar*)iface;
512 rep_list *iter, *iter2;
514 TRACE("(%p)\n", This);
522 HeapFree(GetProcessHeap(), 0, iter->key);
523 HeapFree(GetProcessHeap(), 0, iter->item);
524 HeapFree(GetProcessHeap(), 0, iter);
532 static HRESULT WINAPI Registrar_ResourceRegisterSz(IRegistrar* iface, LPCOLESTR resFileName,
533 LPCOLESTR szID, LPCOLESTR szType)
535 Registrar *This = (Registrar*)iface;
536 FIXME("(%p)->(%s %s %s)\n", This, debugstr_w(resFileName), debugstr_w(szID), debugstr_w(szType));
540 static HRESULT WINAPI Registrar_ResourceUnregisterSz(IRegistrar* iface, LPCOLESTR resFileName,
541 LPCOLESTR szID, LPCOLESTR szType)
543 Registrar *This = (Registrar*)iface;
544 FIXME("(%p)->(%s %s %s)\n", This, debugstr_w(resFileName), debugstr_w(szID), debugstr_w(szType));
548 static HRESULT WINAPI Registrar_FileRegister(IRegistrar* iface, LPCOLESTR fileName)
550 Registrar *This = (Registrar*)iface;
551 FIXME("(%p)->(%s)\n", This, debugstr_w(fileName));
555 static HRESULT WINAPI Registrar_FileUnregister(IRegistrar* iface, LPCOLESTR fileName)
557 Registrar *This = (Registrar*)iface;
558 FIXME("(%p)->(%s)\n", This, debugstr_w(fileName));
562 static HRESULT WINAPI Registrar_StringRegister(IRegistrar* iface, LPCOLESTR data)
564 Registrar *This = (Registrar*)iface;
565 TRACE("(%p)->(%s)\n", This, debugstr_w(data));
566 return string_register(This, data, TRUE);
569 static HRESULT WINAPI Registrar_StringUnregister(IRegistrar* iface, LPCOLESTR data)
571 Registrar *This = (Registrar*)iface;
572 TRACE("(%p)->(%s)\n", This, debugstr_w(data));
573 return string_register(This, data, FALSE);
576 static HRESULT WINAPI Registrar_ResourceRegister(IRegistrar* iface, LPCOLESTR resFileName,
577 UINT nID, LPCOLESTR szType)
579 Registrar *This = (Registrar*)iface;
580 TRACE("(%p)->(%s %d %s)\n", iface, debugstr_w(resFileName), nID, debugstr_w(szType));
581 return resource_register(This, resFileName, nID, szType, TRUE);
584 static HRESULT WINAPI Registrar_ResourceUnregister(IRegistrar* iface, LPCOLESTR resFileName,
585 UINT nID, LPCOLESTR szType)
587 Registrar *This = (Registrar*)iface;
588 TRACE("(%p)->(%s %d %s)\n", This, debugstr_w(resFileName), nID, debugstr_w(szType));
589 return resource_register(This, resFileName, nID, szType, FALSE);
592 static IRegistrarVtbl RegistrarVtbl = {
593 Registrar_QueryInterface,
596 Registrar_AddReplacement,
597 Registrar_ClearReplacements,
598 Registrar_ResourceRegisterSz,
599 Registrar_ResourceUnregisterSz,
600 Registrar_FileRegister,
601 Registrar_FileUnregister,
602 Registrar_StringRegister,
603 Registrar_StringUnregister,
604 Registrar_ResourceRegister,
605 Registrar_ResourceUnregister,
609 /**************************************************************
610 * ClassFactory implementation
613 static HRESULT WINAPI RegistrarCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppvObject)
615 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
617 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRegistrar, riid)) {
622 return E_NOINTERFACE;
625 static ULONG WINAPI RegistrarCF_AddRef(IClassFactory *iface)
630 static ULONG WINAPI RegistrarCF_Release(IClassFactory *iface)
635 static HRESULT WINAPI RegistrarCF_CreateInstance(IClassFactory *iface, LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObject)
638 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
640 if(!IsEqualGUID(&IID_IUnknown, riid) && !IsEqualGUID(&IID_IRegistrar, riid))
641 return E_NOINTERFACE;
643 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Registrar));
644 ret->lpVtbl = &RegistrarVtbl;
652 static HRESULT WINAPI RegistrarCF_LockServer(IClassFactory *iface, BOOL lock)
654 FIXME("(%p)->(%x)\n", iface, lock);
658 static const IClassFactoryVtbl IRegistrarCFVtbl = {
659 RegistrarCF_QueryInterface,
662 RegistrarCF_CreateInstance,
663 RegistrarCF_LockServer
666 static IClassFactory RegistrarCF = { &IRegistrarCFVtbl };
668 /**************************************************************
669 * DllGetClassObject implementation
671 HRESULT WINAPI ATL_DllGetClassObject(REFCLSID clsid, REFIID riid, LPVOID *ppvObject)
673 TRACE("(%s %s %p)", debugstr_guid(clsid), debugstr_guid(riid), ppvObject);
675 if(IsEqualGUID(&CLSID_ATLRegistrar, clsid)) {
676 *ppvObject = &RegistrarCF;
680 FIXME("Not supported class %s\n", debugstr_guid(clsid));
681 return CLASS_E_CLASSNOTAVAILABLE;