4 * Copyright 2005 Jacek Caban
5 * Copyright 2009 Andrew Hill <ash77@reactos.org>
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.
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.
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
24 class IRegistrarBase
: public IUnknown
27 virtual HRESULT STDMETHODCALLTYPE
AddReplacement(LPCOLESTR key
, LPCOLESTR item
) = 0;
28 virtual HRESULT STDMETHODCALLTYPE
ClearReplacements() = 0;
34 class CRegObject
: public IRegistrarBase
37 typedef struct rep_list_str
42 struct rep_list_str
*next
;
64 hResult
= ClearReplacements();
65 ATLASSERT(SUCCEEDED(hResult
));
69 HRESULT STDMETHODCALLTYPE
QueryInterface(const IID
& /* riid */, void ** /* ppvObject */ )
71 ATLASSERT(_T("statically linked in CRegObject is not a com object. Do not callthis function"));
75 ULONG STDMETHODCALLTYPE
AddRef()
77 ATLASSERT(_T("statically linked in CRegObject is not a com object. Do not callthis function"));
81 ULONG STDMETHODCALLTYPE
Release()
83 ATLASSERT(_T("statically linked in CRegObject is not a com object. Do not callthis function"));
87 HRESULT STDMETHODCALLTYPE
AddReplacement(LPCOLESTR key
, LPCOLESTR item
)
92 new_rep
= reinterpret_cast<rep_list
*>(HeapAlloc(GetProcessHeap(), 0, sizeof(rep_list
)));
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
)
100 HeapFree(GetProcessHeap(), 0, new_rep
);
101 return E_OUTOFMEMORY
;
103 memcpy(new_rep
->key
, key
, (new_rep
->key_len
+ 1) * sizeof(OLECHAR
));
105 len
= lstrlenW(item
) + 1;
106 new_rep
->item
= reinterpret_cast<OLECHAR
*>(HeapAlloc(GetProcessHeap(), 0, len
* sizeof(OLECHAR
)));
107 if (new_rep
->item
== NULL
)
109 HeapFree(GetProcessHeap(), 0, new_rep
->key
);
110 HeapFree(GetProcessHeap(), 0, new_rep
);
111 return E_OUTOFMEMORY
;
113 memcpy(new_rep
->item
, item
, len
* sizeof(OLECHAR
));
115 new_rep
->next
= m_rep
;
121 HRESULT STDMETHODCALLTYPE
ClearReplacements()
130 HeapFree(GetProcessHeap(), 0, iter
->key
);
131 HeapFree(GetProcessHeap(), 0, iter
->item
);
132 HeapFree(GetProcessHeap(), 0, iter
);
140 HRESULT STDMETHODCALLTYPE
ResourceRegisterSz(LPCOLESTR resFileName
, LPCOLESTR szID
, LPCOLESTR szType
)
142 return RegisterWithResource(resFileName
, szID
, szType
, TRUE
);
145 HRESULT STDMETHODCALLTYPE
ResourceUnregisterSz(LPCOLESTR resFileName
, LPCOLESTR szID
, LPCOLESTR szType
)
147 return RegisterWithResource(resFileName
, szID
, szType
, FALSE
);
150 HRESULT STDMETHODCALLTYPE
FileRegister(LPCOLESTR fileName
)
152 return RegisterWithFile(fileName
, TRUE
);
155 HRESULT STDMETHODCALLTYPE
FileUnregister(LPCOLESTR fileName
)
157 return RegisterWithFile(fileName
, FALSE
);
160 HRESULT STDMETHODCALLTYPE
StringRegister(LPCOLESTR data
)
162 return RegisterWithString(data
, TRUE
);
165 HRESULT STDMETHODCALLTYPE
StringUnregister(LPCOLESTR data
)
167 return RegisterWithString(data
, FALSE
);
170 HRESULT STDMETHODCALLTYPE
ResourceRegister(LPCOLESTR resFileName
, UINT nID
, LPCOLESTR szType
)
172 return ResourceRegisterSz(resFileName
, MAKEINTRESOURCEW(nID
), szType
);
175 HRESULT STDMETHODCALLTYPE
ResourceUnregister(LPCOLESTR resFileName
, UINT nID
, LPCOLESTR szType
)
177 return ResourceUnregisterSz(resFileName
, MAKEINTRESOURCEW(nID
), szType
);
181 HRESULT STDMETHODCALLTYPE
RegisterWithResource(LPCOLESTR resFileName
, LPCOLESTR szID
, LPCOLESTR szType
, BOOL doRegister
)
183 return resource_register(resFileName
, szID
, szType
, doRegister
);
186 HRESULT STDMETHODCALLTYPE
RegisterWithFile(LPCOLESTR fileName
, BOOL doRegister
)
188 return file_register(fileName
, doRegister
);
191 HRESULT STDMETHODCALLTYPE
RegisterWithString(LPCOLESTR data
, BOOL doRegister
)
193 return string_register(data
, doRegister
);
197 inline LONG
RegDeleteTreeX(HKEY parentKey
, LPCTSTR subKeyName
)
199 wchar_t szBuffer
[256];
205 ATLASSERT(parentKey
!= NULL
);
206 lRes
= RegOpenKeyEx(parentKey
, subKeyName
, 0, KEY_READ
| KEY_WRITE
, &childKey
);
207 if (lRes
!= ERROR_SUCCESS
)
210 dwSize
= sizeof(szBuffer
) / sizeof(szBuffer
[0]);
211 while (RegEnumKeyExW(parentKey
, 0, szBuffer
, &dwSize
, NULL
, NULL
, NULL
, &time
) == ERROR_SUCCESS
)
213 lRes
= RegDeleteTreeX(childKey
, szBuffer
);
214 if (lRes
!= ERROR_SUCCESS
)
216 dwSize
= sizeof(szBuffer
) / sizeof(szBuffer
[0]);
218 RegCloseKey(childKey
);
219 return RegDeleteKey(parentKey
, subKeyName
);
222 HRESULT
strbuf_init(strbuf
*buf
)
224 buf
->str
= reinterpret_cast<LPOLESTR
>(HeapAlloc(GetProcessHeap(), 0, 128 * sizeof(WCHAR
)));
225 if (buf
->str
== NULL
)
226 return E_OUTOFMEMORY
;
232 HRESULT
strbuf_write(LPCOLESTR str
, strbuf
*buf
, int len
)
238 if (buf
->len
+ len
+ 1 >= buf
->alloc
)
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
;
246 memcpy(buf
->str
+ buf
->len
, str
, len
* sizeof(OLECHAR
));
248 buf
->str
[buf
->len
] = '\0';
253 HRESULT
file_register(LPCOLESTR fileName
, BOOL do_register
)
263 file
= CreateFileW(fileName
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_READONLY
, NULL
);
264 if (file
!= INVALID_HANDLE_VALUE
)
266 filelen
= GetFileSize(file
, NULL
);
267 regstra
= reinterpret_cast<LPSTR
>(HeapAlloc(GetProcessHeap(), 0, filelen
));
269 return E_OUTOFMEMORY
;
270 lres
= ReadFile(file
, regstra
, filelen
, NULL
, NULL
);
271 if (lres
== ERROR_SUCCESS
)
273 len
= MultiByteToWideChar(CP_ACP
, 0, regstra
, filelen
, NULL
, 0) + 1;
274 regstrw
= reinterpret_cast<LPWSTR
>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof(WCHAR
)));
277 HeapFree(GetProcessHeap(), 0, regstra
);
278 return E_OUTOFMEMORY
;
280 MultiByteToWideChar(CP_ACP
, 0, regstra
, filelen
, regstrw
, len
);
281 regstrw
[len
- 1] = '\0';
283 hResult
= string_register(regstrw
, do_register
);
285 HeapFree(GetProcessHeap(), 0, regstrw
);
289 hResult
= HRESULT_FROM_WIN32(lres
);
291 HeapFree(GetProcessHeap(), 0, regstra
);
296 hResult
= HRESULT_FROM_WIN32(GetLastError());
302 HRESULT
resource_register(LPCOLESTR resFileName
, LPCOLESTR szID
, LPCOLESTR szType
, BOOL do_register
)
312 hins
= LoadLibraryExW(resFileName
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
315 src
= FindResourceW(hins
, szID
, szType
);
318 regstra
= LoadResource(hins
, src
);
319 reslen
= SizeofResource(hins
, src
);
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
)));
325 return E_OUTOFMEMORY
;
326 MultiByteToWideChar(CP_ACP
, 0, reinterpret_cast<LPCSTR
>(regstra
), reslen
, regstrw
, len
);
327 regstrw
[len
- 1] = '\0';
329 hResult
= string_register(regstrw
, do_register
);
331 HeapFree(GetProcessHeap(), 0, regstrw
);
334 hResult
= HRESULT_FROM_WIN32(GetLastError());
337 hResult
= HRESULT_FROM_WIN32(GetLastError());
341 hResult
= HRESULT_FROM_WIN32(GetLastError());
346 HRESULT
string_register(LPCOLESTR data
, BOOL do_register
)
351 hResult
= strbuf_init(&buf
);
354 hResult
= do_preprocess(data
, &buf
);
355 if (SUCCEEDED(hResult
))
357 hResult
= do_process_root_key(buf
.str
, do_register
);
358 if (FAILED(hResult
) && do_register
)
359 do_process_root_key(buf
.str
, FALSE
);
362 HeapFree(GetProcessHeap(), 0, buf
.str
);
366 HRESULT
do_preprocess(LPCOLESTR data
, strbuf
*buf
)
374 iter
= wcschr(data
, '%');
377 hResult
= strbuf_write(iter2
, buf
, static_cast<int>(iter
- iter2
));
383 return DISP_E_EXCEPTION
;
384 iter
= wcschr(iter2
, '%');
386 return DISP_E_EXCEPTION
;
390 hResult
= strbuf_write(_T("%"), buf
, 1);
396 for (rep_iter
= m_rep
; rep_iter
; rep_iter
= rep_iter
->next
)
398 if (rep_iter
->key_len
== iter
- iter2
&& !_memicmp(iter2
, rep_iter
->key
, rep_iter
->key_len
* sizeof(wchar_t)))
402 return DISP_E_EXCEPTION
;
404 hResult
= strbuf_write(rep_iter
->item
, buf
, -1);
410 iter
= wcschr(iter
, '%');
413 hResult
= strbuf_write(iter2
, buf
, -1);
420 HRESULT
get_word(LPCOLESTR
*str
, strbuf
*buf
)
430 while (iswspace (*iter2
))
439 if (*iter
== '}' || *iter
== '=')
441 hResult
= strbuf_write(iter
++, buf
, 1);
445 else if (*iter
== '\'')
448 iter
= wcschr(iter
, '\'');
452 return DISP_E_EXCEPTION
;
454 hResult
= strbuf_write(iter2
, buf
, static_cast<int>(iter
- iter2
));
461 while (*iter
&& !iswspace(*iter
))
463 hResult
= strbuf_write(iter2
, buf
, static_cast<int>(iter
- iter2
));
468 while (iswspace(*iter
))
474 inline unsigned int HexToBin(OLECHAR a
)
476 if (a
>= '0' && a
<= '9')
478 if (a
>= 'A' && a
<= 'F')
480 if (a
>= 'a' && a
<= 'f')
486 HRESULT
do_process_key(LPCOLESTR
*pstr
, HKEY parent_key
, strbuf
*buf
, BOOL do_register
)
502 static const wchar_t *wstrNoRemove
= _T("NoRemove");
503 static const wchar_t *wstrForceRemove
= _T("ForceRemove");
504 static const wchar_t *wstrDelete
= _T("Delete");
505 static const wchar_t *wstrval
= _T("val");
509 hres
= get_word(&iter
, buf
);
512 hres
= strbuf_init(&name
);
516 while(buf
->str
[1] || buf
->str
[0] != '}')
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
))
525 else if (!lstrcmpiW(buf
->str
, wstrDelete
))
526 key_type
= DO_DELETE
;
528 if (key_type
!= NORMAL
)
530 hres
= get_word(&iter
, buf
);
537 if (key_type
== IS_VAL
)
540 hres
= strbuf_write(buf
->str
, &name
, -1);
544 else if (key_type
== DO_DELETE
)
546 RegDeleteTreeX(parent_key
, buf
->str
);
550 if (key_type
== FORCE_REMOVE
)
551 RegDeleteTreeX(parent_key
, buf
->str
);
552 lres
= RegCreateKey(parent_key
, buf
->str
, &hkey
);
553 if (lres
!= ERROR_SUCCESS
)
555 hres
= HRESULT_FROM_WIN32(lres
);
560 else if (key_type
!= IS_VAL
&& key_type
!= DO_DELETE
)
562 hres
= strbuf_write(buf
->str
, &name
, -1);
565 lres
= RegOpenKey(parent_key
, buf
->str
, &hkey
);
566 if (lres
!= ERROR_SUCCESS
)
571 if (key_type
!= DO_DELETE
&& *iter
== '=')
574 hres
= get_word(&iter
, buf
);
579 hres
= DISP_E_EXCEPTION
;
587 hres
= get_word(&iter
, buf
);
590 lres
= RegSetValueEx(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
);
596 hres
= get_word(&iter
, buf
);
599 lres
= RegSetValueEx(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
);
606 hres
= get_word(&iter
, buf
);
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);
614 dw
= wcstol(&buf
->str
[0], &end
, 10);
615 lres
= RegSetValueEx(hkey
, name
.len
? name
.str
: NULL
, 0, REG_DWORD
, (PBYTE
)&dw
, sizeof(dw
));
616 if (lres
!= ERROR_SUCCESS
)
617 hres
= HRESULT_FROM_WIN32(lres
);
625 hres
= get_word(&iter
, buf
);
629 if ((count
& 1) != 0)
630 return DISP_E_EXCEPTION
;
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
= RegSetValueEx(hkey
, name
.len
? name
.str
: NULL
, 0, REG_BINARY
, (PBYTE
)buf
->str
, count
);
635 if (lres
!= ERROR_SUCCESS
)
636 hres
= HRESULT_FROM_WIN32(lres
);
640 hres
= DISP_E_EXCEPTION
;
649 hres
= get_word(&iter
, buf
);
654 else if(key_type
== IS_VAL
)
656 hres
= DISP_E_EXCEPTION
;
660 if (key_type
!= IS_VAL
&& key_type
!= DO_DELETE
&& *iter
== '{' && iswspace(iter
[1]))
662 hres
= get_word(&iter
, buf
);
665 hres
= do_process_key(&iter
, hkey
, buf
, do_register
);
670 if (!do_register
&& (key_type
== NORMAL
|| key_type
== FORCE_REMOVE
))
672 RegDeleteKey(parent_key
, name
.str
);
675 if (hkey
&& key_type
!= IS_VAL
)
680 hres
= get_word(&iter
, buf
);
685 HeapFree(GetProcessHeap(), 0, name
.str
);
686 if (hkey
&& key_type
!= IS_VAL
)
692 HRESULT
do_process_root_key(LPCOLESTR data
, BOOL do_register
)
698 static const struct {
702 {_T("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT
},
703 {_T("HKEY_CURRENT_USER"), HKEY_CURRENT_USER
},
704 {_T("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE
},
705 {_T("HKEY_USERS"), HKEY_USERS
},
706 {_T("HKEY_PERFORMANCE_DATA"), HKEY_PERFORMANCE_DATA
},
707 {_T("HKEY_DYN_DATA"), HKEY_DYN_DATA
},
708 {_T("HKEY_CURRENT_CONFIG"), HKEY_CURRENT_CONFIG
},
709 {_T("HKCR"), HKEY_CLASSES_ROOT
},
710 {_T("HKCU"), HKEY_CURRENT_USER
},
711 {_T("HKLM"), HKEY_LOCAL_MACHINE
},
712 {_T("HKU"), HKEY_USERS
},
713 {_T("HKPD"), HKEY_PERFORMANCE_DATA
},
714 {_T("HKDD"), HKEY_DYN_DATA
},
715 {_T("HKCC"), HKEY_CURRENT_CONFIG
},
720 hResult
= strbuf_init(&buf
);
723 hResult
= get_word(&iter
, &buf
);
731 hResult
= DISP_E_EXCEPTION
;
734 for (i
= 0; i
< sizeof(root_keys
) / sizeof(root_keys
[0]); i
++)
736 if (!lstrcmpiW(buf
.str
, root_keys
[i
].name
))
739 if (i
== sizeof(root_keys
) / sizeof(root_keys
[0]))
741 hResult
= DISP_E_EXCEPTION
;
744 hResult
= get_word(&iter
, &buf
);
747 if (buf
.str
[1] || buf
.str
[0] != '{')
749 hResult
= DISP_E_EXCEPTION
;
752 hResult
= do_process_key(&iter
, root_keys
[i
].key
, &buf
, do_register
);
755 hResult
= get_word(&iter
, &buf
);
759 HeapFree(GetProcessHeap(), 0, buf
.str
);