/* * Copyright 2005 Jacek Caban * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define COBJMACROS #include "atlbase.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(atl); /************************************************************** * ATLRegistrar implementation */ static const struct { WCHAR name[22]; HKEY key; } root_keys[] = { {{'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T',0}, HKEY_CLASSES_ROOT}, {{'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R',0}, HKEY_CURRENT_USER}, {{'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',0}, HKEY_LOCAL_MACHINE}, {{'H','K','E','Y','_','U','S','E','R','S',0}, HKEY_USERS}, {{'H','K','E','Y','_','P','E','R','F','O','R','M','A','N','C','E','_','D','A','T','A',0}, HKEY_PERFORMANCE_DATA}, {{'H','K','E','Y','_','D','Y','N','_','D','A','T','A',0}, HKEY_DYN_DATA}, {{'H','K','E','Y','_','C','U','R','R','E','N','T','_','C','O','N','F','I','G',0}, HKEY_CURRENT_CONFIG}, {{'H','K','C','R',0}, HKEY_CLASSES_ROOT}, {{'H','K','C','U',0}, HKEY_CURRENT_USER}, {{'H','K','L','M',0}, HKEY_LOCAL_MACHINE}, {{'H','K','U',0}, HKEY_USERS}, {{'H','K','P','D',0}, HKEY_PERFORMANCE_DATA}, {{'H','K','D','D',0}, HKEY_DYN_DATA}, {{'H','K','C','C',0}, HKEY_CURRENT_CONFIG} }; typedef struct rep_list_str { LPOLESTR key; LPOLESTR item; int key_len; struct rep_list_str *next; } rep_list; typedef struct { IRegistrar IRegistrar_iface; LONG ref; rep_list *rep; } Registrar; typedef struct { LPOLESTR str; DWORD alloc; DWORD len; } strbuf; static inline Registrar *impl_from_IRegistrar(IRegistrar *iface) { return CONTAINING_RECORD(iface, Registrar, IRegistrar_iface); } static void strbuf_init(strbuf *buf) { buf->str = HeapAlloc(GetProcessHeap(), 0, 128*sizeof(WCHAR)); buf->alloc = 128; buf->len = 0; } static void strbuf_write(LPCOLESTR str, strbuf *buf, int len) { if(len == -1) len = lstrlenW(str); if(buf->len+len+1 >= buf->alloc) { buf->alloc = (buf->len+len)<<1; buf->str = HeapReAlloc(GetProcessHeap(), 0, buf->str, buf->alloc*sizeof(WCHAR)); } memcpy(buf->str+buf->len, str, len*sizeof(OLECHAR)); buf->len += len; buf->str[buf->len] = '\0'; } static int xdigit_to_int(WCHAR c) { if('0' <= c && c <= '9') return c - '0'; if('a' <= c && c <= 'f') return c - 'a' + 10; if('A' <= c && c <= 'F') return c - 'A' + 10; return -1; } static HRESULT get_word(LPCOLESTR *str, strbuf *buf) { LPCOLESTR iter, iter2 = *str; buf->len = 0; buf->str[0] = '\0'; while(iswspace(*iter2)) iter2++; iter = iter2; if(!*iter) { *str = iter; return S_OK; } if(*iter == '}' || *iter == '=') { strbuf_write(iter++, buf, 1); }else if(*iter == '\'') { iter2 = ++iter; iter = wcschr(iter, '\''); if(!iter) { WARN("Unexpected end of script\n"); *str = iter; return DISP_E_EXCEPTION; } strbuf_write(iter2, buf, iter-iter2); iter++; }else { while(*iter && !iswspace(*iter)) iter++; strbuf_write(iter2, buf, iter-iter2); } while(iswspace(*iter)) iter++; *str = iter; return S_OK; } static HRESULT do_preprocess(const Registrar *This, LPCOLESTR data, strbuf *buf) { LPCOLESTR iter, iter2 = data; rep_list *rep_iter; static const WCHAR wstr[] = {'%',0}; iter = wcschr(data, '%'); while(iter) { strbuf_write(iter2, buf, iter-iter2); iter2 = ++iter; if(!*iter2) return DISP_E_EXCEPTION; iter = wcschr(iter2, '%'); if(!iter) return DISP_E_EXCEPTION; if(iter == iter2) { strbuf_write(wstr, buf, 1); }else { for(rep_iter = This->rep; rep_iter; rep_iter = rep_iter->next) { if(rep_iter->key_len == iter-iter2 && !wcsnicmp(iter2, rep_iter->key, rep_iter->key_len)) break; } if(!rep_iter) { WARN("Could not find replacement: %s\n", debugstr_wn(iter2, iter-iter2)); return DISP_E_EXCEPTION; } strbuf_write(rep_iter->item, buf, -1); } iter2 = ++iter; iter = wcschr(iter, '%'); } strbuf_write(iter2, buf, -1); TRACE("%s\n", debugstr_w(buf->str)); return S_OK; } static HRESULT do_process_key(LPCOLESTR *pstr, HKEY parent_key, strbuf *buf, BOOL do_register) { LPCOLESTR iter; HRESULT hres; LONG lres; HKEY hkey = 0; strbuf name; enum { NORMAL, NO_REMOVE, IS_VAL, FORCE_REMOVE, DO_DELETE } key_type = NORMAL; static const WCHAR wstrNoRemove[] = {'N','o','R','e','m','o','v','e',0}; static const WCHAR wstrForceRemove[] = {'F','o','r','c','e','R','e','m','o','v','e',0}; static const WCHAR wstrDelete[] = {'D','e','l','e','t','e',0}; static const WCHAR wstrval[] = {'v','a','l',0}; iter = *pstr; hres = get_word(&iter, buf); if(FAILED(hres)) return hres; strbuf_init(&name); while(buf->str[1] || buf->str[0] != '}') { key_type = NORMAL; if(!lstrcmpiW(buf->str, wstrNoRemove)) key_type = NO_REMOVE; else if(!lstrcmpiW(buf->str, wstrForceRemove)) key_type = FORCE_REMOVE; else if(!lstrcmpiW(buf->str, wstrval)) key_type = IS_VAL; else if(!lstrcmpiW(buf->str, wstrDelete)) key_type = DO_DELETE; if(key_type != NORMAL) { hres = get_word(&iter, buf); if(FAILED(hres)) break; } TRACE("name = %s\n", debugstr_w(buf->str)); if(do_register) { if(key_type == IS_VAL) { hkey = parent_key; strbuf_write(buf->str, &name, -1); }else if(key_type == DO_DELETE) { TRACE("Deleting %s\n", debugstr_w(buf->str)); RegDeleteTreeW(parent_key, buf->str); }else { if(key_type == FORCE_REMOVE) RegDeleteTreeW(parent_key, buf->str); lres = RegCreateKeyW(parent_key, buf->str, &hkey); if(lres != ERROR_SUCCESS) { WARN("Could not create(open) key: %08x\n", lres); hres = HRESULT_FROM_WIN32(lres); break; } } }else if(key_type != IS_VAL && key_type != DO_DELETE) { strbuf_write(buf->str, &name, -1); lres = RegOpenKeyW(parent_key, buf->str, &hkey); if(lres != ERROR_SUCCESS) WARN("Could not open key %s: %08x\n", debugstr_w(name.str), lres); } if(key_type != DO_DELETE && *iter == '=') { iter++; hres = get_word(&iter, buf); if(FAILED(hres)) break; if(buf->len != 1) { WARN("Wrong registry type: %s\n", debugstr_w(buf->str)); hres = DISP_E_EXCEPTION; break; } if(do_register) { switch(buf->str[0]) { case 's': hres = get_word(&iter, buf); if(FAILED(hres)) break; lres = RegSetValueExW(hkey, name.len ? name.str : NULL, 0, REG_SZ, (PBYTE)buf->str, (lstrlenW(buf->str)+1)*sizeof(WCHAR)); if(lres != ERROR_SUCCESS) { WARN("Could set value of key: %08x\n", lres); hres = HRESULT_FROM_WIN32(lres); break; } break; case 'd': { DWORD dw; hres = get_word(&iter, buf); if(FAILED(hres)) break; dw = wcstol(buf->str, NULL, 10); lres = RegSetValueExW(hkey, name.len ? name.str : NULL, 0, REG_DWORD, (PBYTE)&dw, sizeof(dw)); if(lres != ERROR_SUCCESS) { WARN("Could set value of key: %08x\n", lres); hres = HRESULT_FROM_WIN32(lres); break; } break; } case 'b': { BYTE *bytes; DWORD count; DWORD i; hres = get_word(&iter, buf); if(FAILED(hres)) break; count = (lstrlenW(buf->str) + 1) / 2; bytes = HeapAlloc(GetProcessHeap(), 0, count); if(bytes == NULL) { hres = E_OUTOFMEMORY; break; } for(i = 0; i < count && buf->str[2*i]; i++) { int d1, d2; if((d1 = xdigit_to_int(buf->str[2*i])) == -1 || (d2 = xdigit_to_int(buf->str[2*i + 1])) == -1) { hres = E_FAIL; break; } bytes[i] = (d1 << 4) | d2; } if(SUCCEEDED(hres)) { lres = RegSetValueExW(hkey, name.len ? name.str : NULL, 0, REG_BINARY, bytes, count); if(lres != ERROR_SUCCESS) { WARN("Could not set value of key: 0x%08x\n", lres); hres = HRESULT_FROM_WIN32(lres); } } HeapFree(GetProcessHeap(), 0, bytes); break; } default: WARN("Wrong resource type: %s\n", debugstr_w(buf->str)); hres = DISP_E_EXCEPTION; }; if(FAILED(hres)) break; }else { if(*iter == '-') iter++; hres = get_word(&iter, buf); if(FAILED(hres)) break; } }else if(key_type == IS_VAL) { WARN("value not set!\n"); hres = DISP_E_EXCEPTION; break; } if(key_type != IS_VAL && key_type != DO_DELETE && *iter == '{' && iswspace(iter[1])) { hres = get_word(&iter, buf); if(FAILED(hres)) break; hres = do_process_key(&iter, hkey, buf, do_register); if(FAILED(hres)) break; } TRACE("%x %x\n", do_register, key_type); if(!do_register && (key_type == NORMAL || key_type == FORCE_REMOVE)) { TRACE("Deleting %s\n", debugstr_w(name.str)); RegDeleteKeyW(parent_key, name.str); } if(hkey && key_type != IS_VAL) RegCloseKey(hkey); hkey = 0; name.len = 0; hres = get_word(&iter, buf); if(FAILED(hres)) break; } HeapFree(GetProcessHeap(), 0, name.str); if(hkey && key_type != IS_VAL) RegCloseKey(hkey); *pstr = iter; return hres; } static HRESULT do_process_root_key(LPCOLESTR data, BOOL do_register) { LPCOLESTR iter = data; strbuf buf; HRESULT hres; unsigned int i; strbuf_init(&buf); hres = get_word(&iter, &buf); if(FAILED(hres)) return hres; while(*iter) { if(!buf.len) { WARN("ward.len == 0, failed\n"); hres = DISP_E_EXCEPTION; break; } for(i=0; i(%s %p\n", iface, debugstr_guid(riid), ppvObject); if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRegistrar, riid) || IsEqualGUID(&IID_IRegistrarBase, riid)) { IRegistrar_AddRef(iface); *ppvObject = iface; return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI Registrar_AddRef(IRegistrar *iface) { Registrar *This = impl_from_IRegistrar(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ->%d\n", This, ref); return ref; } static ULONG WINAPI Registrar_Release(IRegistrar *iface) { Registrar *This = impl_from_IRegistrar(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ->%d\n", This, ref); if(!ref) { IRegistrar_ClearReplacements(iface); HeapFree(GetProcessHeap(), 0, This); } return ref; } static HRESULT WINAPI Registrar_AddReplacement(IRegistrar *iface, LPCOLESTR Key, LPCOLESTR item) { Registrar *This = impl_from_IRegistrar(iface); int len; rep_list *new_rep; TRACE("(%p)->(%s %s)\n", This, debugstr_w(Key), debugstr_w(item)); new_rep = HeapAlloc(GetProcessHeap(), 0, sizeof(rep_list)); new_rep->key_len = lstrlenW(Key); new_rep->key = HeapAlloc(GetProcessHeap(), 0, (new_rep->key_len + 1) * sizeof(OLECHAR)); memcpy(new_rep->key, Key, (new_rep->key_len+1)*sizeof(OLECHAR)); len = lstrlenW(item)+1; new_rep->item = HeapAlloc(GetProcessHeap(), 0, len*sizeof(OLECHAR)); memcpy(new_rep->item, item, len*sizeof(OLECHAR)); new_rep->next = This->rep; This->rep = new_rep; return S_OK; } static HRESULT WINAPI Registrar_ClearReplacements(IRegistrar *iface) { Registrar *This = impl_from_IRegistrar(iface); rep_list *iter, *iter2; TRACE("(%p)\n", This); if(!This->rep) return S_OK; iter = This->rep; while(iter) { iter2 = iter->next; HeapFree(GetProcessHeap(), 0, iter->key); HeapFree(GetProcessHeap(), 0, iter->item); HeapFree(GetProcessHeap(), 0, iter); iter = iter2; } This->rep = NULL; return S_OK; } static HRESULT WINAPI Registrar_ResourceRegisterSz(IRegistrar* iface, LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType) { Registrar *This = impl_from_IRegistrar(iface); TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(resFileName), debugstr_w(szID), debugstr_w(szType)); return resource_register(This, resFileName, szID, szType, TRUE); } static HRESULT WINAPI Registrar_ResourceUnregisterSz(IRegistrar* iface, LPCOLESTR resFileName, LPCOLESTR szID, LPCOLESTR szType) { Registrar *This = impl_from_IRegistrar(iface); TRACE("(%p)->(%s %s %s)\n", This, debugstr_w(resFileName), debugstr_w(szID), debugstr_w(szType)); return resource_register(This, resFileName, szID, szType, FALSE); } static HRESULT WINAPI Registrar_FileRegister(IRegistrar* iface, LPCOLESTR fileName) { Registrar *This = impl_from_IRegistrar(iface); TRACE("(%p)->(%s)\n", This, debugstr_w(fileName)); return file_register(This, fileName, TRUE); } static HRESULT WINAPI Registrar_FileUnregister(IRegistrar* iface, LPCOLESTR fileName) { Registrar *This = impl_from_IRegistrar(iface); FIXME("(%p)->(%s)\n", This, debugstr_w(fileName)); return file_register(This, fileName, FALSE); } static HRESULT WINAPI Registrar_StringRegister(IRegistrar* iface, LPCOLESTR data) { Registrar *This = impl_from_IRegistrar(iface); TRACE("(%p)->(%s)\n", This, debugstr_w(data)); return string_register(This, data, TRUE); } static HRESULT WINAPI Registrar_StringUnregister(IRegistrar* iface, LPCOLESTR data) { Registrar *This = impl_from_IRegistrar(iface); TRACE("(%p)->(%s)\n", This, debugstr_w(data)); return string_register(This, data, FALSE); } static HRESULT WINAPI Registrar_ResourceRegister(IRegistrar* iface, LPCOLESTR resFileName, UINT nID, LPCOLESTR szType) { Registrar *This = impl_from_IRegistrar(iface); TRACE("(%p)->(%s %d %s)\n", iface, debugstr_w(resFileName), nID, debugstr_w(szType)); return resource_register(This, resFileName, MAKEINTRESOURCEW(nID), szType, TRUE); } static HRESULT WINAPI Registrar_ResourceUnregister(IRegistrar* iface, LPCOLESTR resFileName, UINT nID, LPCOLESTR szType) { Registrar *This = impl_from_IRegistrar(iface); TRACE("(%p)->(%s %d %s)\n", This, debugstr_w(resFileName), nID, debugstr_w(szType)); return resource_register(This, resFileName, MAKEINTRESOURCEW(nID), szType, FALSE); } static const IRegistrarVtbl RegistrarVtbl = { Registrar_QueryInterface, Registrar_AddRef, Registrar_Release, Registrar_AddReplacement, Registrar_ClearReplacements, Registrar_ResourceRegisterSz, Registrar_ResourceUnregisterSz, Registrar_FileRegister, Registrar_FileUnregister, Registrar_StringRegister, Registrar_StringUnregister, Registrar_ResourceRegister, Registrar_ResourceUnregister, }; /*********************************************************************** * AtlCreateRegistrar [atl100.@] */ HRESULT WINAPI AtlCreateRegistrar(IRegistrar **ret) { Registrar *registrar; registrar = HeapAlloc(GetProcessHeap(), 0, sizeof(*registrar)); if(!registrar) return E_OUTOFMEMORY; registrar->IRegistrar_iface.lpVtbl = &RegistrarVtbl; registrar->ref = 1; registrar->rep = NULL; *ret = ®istrar->IRegistrar_iface; return S_OK; } /*********************************************************************** * AtlUpdateRegistryFromResourceD [atl100.@] */ HRESULT WINAPI AtlUpdateRegistryFromResourceD(HINSTANCE inst, LPCOLESTR res, BOOL bRegister, struct _ATL_REGMAP_ENTRY *pMapEntries, IRegistrar *pReg) { const struct _ATL_REGMAP_ENTRY *iter; WCHAR module_name[MAX_PATH]; IRegistrar *registrar; HRESULT hres; static const WCHAR moduleW[] = {'M','O','D','U','L','E',0}; static const WCHAR registryW[] = {'R','E','G','I','S','T','R','Y',0}; if(!GetModuleFileNameW(inst, module_name, MAX_PATH)) { FIXME("hinst %p: did not get module name\n", inst); return E_FAIL; } TRACE("%p (%s), %s, %d, %p, %p\n", inst, debugstr_w(module_name), debugstr_w(res), bRegister, pMapEntries, pReg); if(pReg) { registrar = pReg; }else { hres = AtlCreateRegistrar(®istrar); if(FAILED(hres)) return hres; } IRegistrar_AddReplacement(registrar, moduleW, module_name); for (iter = pMapEntries; iter && iter->szKey; iter++) IRegistrar_AddReplacement(registrar, iter->szKey, iter->szData); if(bRegister) hres = IRegistrar_ResourceRegisterSz(registrar, module_name, res, registryW); else hres = IRegistrar_ResourceUnregisterSz(registrar, module_name, res, registryW); if(registrar != pReg) IRegistrar_Release(registrar); return hres; }