Test passing NULL source to WideCharToMultiByte.
[wine] / dlls / ole32 / regsvr.c
1 /*
2  *      self-registerable dll functions for ole32.dll
3  *
4  * Copyright (C) 2003 John K. Hohm
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
31 #include "objbase.h"
32
33 #include "compobj_private.h"
34 #include "ole2.h"
35 #include "olectl.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40
41 /*
42  * Near the bottom of this file are the exported DllRegisterServer and
43  * DllUnregisterServer, which make all this worthwhile.
44  */
45
46 /***********************************************************************
47  *              interface for self-registering
48  */
49 struct regsvr_interface
50 {
51     IID const *iid;             /* NULL for end of list */
52     LPCSTR name;                /* can be NULL to omit */
53     IID const *base_iid;        /* can be NULL to omit */
54     int num_methods;            /* can be <0 to omit */
55     CLSID const *ps_clsid;      /* can be NULL to omit */
56     CLSID const *ps_clsid32;    /* can be NULL to omit */
57 };
58
59 static HRESULT register_interfaces(struct regsvr_interface const *list);
60 static HRESULT unregister_interfaces(struct regsvr_interface const *list);
61
62 struct regsvr_coclass
63 {
64     CLSID const *clsid;         /* NULL for end of list */
65     LPCSTR name;                /* can be NULL to omit */
66     LPCSTR ips;                 /* can be NULL to omit */
67     LPCSTR ips32;               /* can be NULL to omit */
68     LPCSTR ips32_tmodel;        /* can be NULL to omit */
69 };
70
71 static HRESULT register_coclasses(struct regsvr_coclass const *list);
72 static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
73
74 /***********************************************************************
75  *              static string constants
76  */
77 static WCHAR const interface_keyname[10] = {
78     'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
79 static WCHAR const base_ifa_keyname[14] = {
80     'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
81     'e', 0 };
82 static WCHAR const num_methods_keyname[11] = {
83     'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
84 static WCHAR const ps_clsid_keyname[15] = {
85     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
86     'i', 'd', 0 };
87 static WCHAR const ps_clsid32_keyname[17] = {
88     'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
89     'i', 'd', '3', '2', 0 };
90 static WCHAR const clsid_keyname[6] = {
91     'C', 'L', 'S', 'I', 'D', 0 };
92 static WCHAR const ips_keyname[13] = {
93     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
94     0 };
95 static WCHAR const ips32_keyname[15] = {
96     'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
97     '3', '2', 0 };
98 static char const tmodel_valuename[] = "ThreadingModel";
99
100 /***********************************************************************
101  *              static helper functions
102  */
103 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
104 static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
105                                    WCHAR const *value);
106 static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
107                                    char const *value);
108 static LONG recursive_delete_key(HKEY key);
109
110
111 /***********************************************************************
112  *              register_interfaces
113  */
114 static HRESULT register_interfaces(struct regsvr_interface const *list)
115 {
116     LONG res = ERROR_SUCCESS;
117     HKEY interface_key;
118
119     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
120                           KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
121     if (res != ERROR_SUCCESS) goto error_return;
122
123     for (; res == ERROR_SUCCESS && list->iid; ++list) {
124         WCHAR buf[39];
125         HKEY iid_key;
126
127         StringFromGUID2(list->iid, buf, 39);
128         res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
129                               KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
130         if (res != ERROR_SUCCESS) goto error_close_interface_key;
131
132         if (list->name) {
133             res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
134                                  (CONST BYTE*)(list->name),
135                                  strlen(list->name) + 1);
136             if (res != ERROR_SUCCESS) goto error_close_iid_key;
137         }
138
139         if (list->base_iid) {
140             register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
141             if (res != ERROR_SUCCESS) goto error_close_iid_key;
142         }
143
144         if (0 <= list->num_methods) {
145             static WCHAR const fmt[3] = { '%', 'd', 0 };
146             HKEY key;
147
148             res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
149                                   KEY_READ | KEY_WRITE, NULL, &key, NULL);
150             if (res != ERROR_SUCCESS) goto error_close_iid_key;
151
152             wsprintfW(buf, fmt, list->num_methods);
153             res = RegSetValueExW(key, NULL, 0, REG_SZ,
154                                  (CONST BYTE*)buf,
155                                  (lstrlenW(buf) + 1) * sizeof(WCHAR));
156             RegCloseKey(key);
157
158             if (res != ERROR_SUCCESS) goto error_close_iid_key;
159         }
160
161         if (list->ps_clsid) {
162             register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
163             if (res != ERROR_SUCCESS) goto error_close_iid_key;
164         }
165
166         if (list->ps_clsid32) {
167             register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
168             if (res != ERROR_SUCCESS) goto error_close_iid_key;
169         }
170
171     error_close_iid_key:
172         RegCloseKey(iid_key);
173     }
174
175 error_close_interface_key:
176     RegCloseKey(interface_key);
177 error_return:
178     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
179 }
180
181 /***********************************************************************
182  *              unregister_interfaces
183  */
184 static HRESULT unregister_interfaces(struct regsvr_interface const *list)
185 {
186     LONG res = ERROR_SUCCESS;
187     HKEY interface_key;
188
189     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
190                         KEY_READ | KEY_WRITE, &interface_key);
191     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
192     if (res != ERROR_SUCCESS) goto error_return;
193
194     for (; res == ERROR_SUCCESS && list->iid; ++list) {
195         WCHAR buf[39];
196         HKEY iid_key;
197
198         StringFromGUID2(list->iid, buf, 39);
199         res = RegOpenKeyExW(interface_key, buf, 0,
200                             KEY_READ | KEY_WRITE, &iid_key);
201         if (res == ERROR_FILE_NOT_FOUND) {
202             res = ERROR_SUCCESS;
203             continue;
204         }
205         if (res != ERROR_SUCCESS) goto error_close_interface_key;
206         res = recursive_delete_key(iid_key);
207         RegCloseKey(iid_key);
208         if (res != ERROR_SUCCESS) goto error_close_interface_key;
209     }
210
211 error_close_interface_key:
212     RegCloseKey(interface_key);
213 error_return:
214     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
215 }
216
217 /***********************************************************************
218  *              register_coclasses
219  */
220 static HRESULT register_coclasses(struct regsvr_coclass const *list)
221 {
222     LONG res = ERROR_SUCCESS;
223     HKEY coclass_key;
224
225     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
226                           KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
227     if (res != ERROR_SUCCESS) goto error_return;
228
229     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
230         WCHAR buf[39];
231         HKEY clsid_key;
232
233         StringFromGUID2(list->clsid, buf, 39);
234         res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
235                               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
236         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
237
238         if (list->name) {
239             res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
240                                  (CONST BYTE*)(list->name),
241                                  strlen(list->name) + 1);
242             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
243         }
244
245         if (list->ips) {
246             res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
247             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
248         }
249
250         if (list->ips32) {
251             HKEY ips32_key;
252
253             res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
254                                   KEY_READ | KEY_WRITE, NULL,
255                                   &ips32_key, NULL);
256             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
257
258             res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
259                                  (CONST BYTE*)list->ips32,
260                                  lstrlenA(list->ips32) + 1);
261             if (res == ERROR_SUCCESS && list->ips32_tmodel)
262                 res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
263                                      (CONST BYTE*)list->ips32_tmodel,
264                                      strlen(list->ips32_tmodel) + 1);
265             RegCloseKey(ips32_key);
266             if (res != ERROR_SUCCESS) goto error_close_clsid_key;
267         }
268
269     error_close_clsid_key:
270         RegCloseKey(clsid_key);
271     }
272
273 error_close_coclass_key:
274     RegCloseKey(coclass_key);
275 error_return:
276     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
277 }
278
279 /***********************************************************************
280  *              unregister_coclasses
281  */
282 static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
283 {
284     LONG res = ERROR_SUCCESS;
285     HKEY coclass_key;
286
287     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
288                         KEY_READ | KEY_WRITE, &coclass_key);
289     if (res == ERROR_FILE_NOT_FOUND) return S_OK;
290     if (res != ERROR_SUCCESS) goto error_return;
291
292     for (; res == ERROR_SUCCESS && list->clsid; ++list) {
293         WCHAR buf[39];
294         HKEY clsid_key;
295
296         StringFromGUID2(list->clsid, buf, 39);
297         res = RegOpenKeyExW(coclass_key, buf, 0,
298                             KEY_READ | KEY_WRITE, &clsid_key);
299         if (res == ERROR_FILE_NOT_FOUND) {
300             res = ERROR_SUCCESS;
301             continue;
302         }
303         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
304         res = recursive_delete_key(clsid_key);
305         RegCloseKey(clsid_key);
306         if (res != ERROR_SUCCESS) goto error_close_coclass_key;
307     }
308
309 error_close_coclass_key:
310     RegCloseKey(coclass_key);
311 error_return:
312     return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
313 }
314
315 /***********************************************************************
316  *              regsvr_key_guid
317  */
318 static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
319 {
320     WCHAR buf[39];
321
322     StringFromGUID2(guid, buf, 39);
323     return register_key_defvalueW(base, name, buf);
324 }
325
326 /***********************************************************************
327  *              regsvr_key_defvalueW
328  */
329 static LONG register_key_defvalueW(
330     HKEY base,
331     WCHAR const *name,
332     WCHAR const *value)
333 {
334     LONG res;
335     HKEY key;
336
337     res = RegCreateKeyExW(base, name, 0, NULL, 0,
338                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
339     if (res != ERROR_SUCCESS) return res;
340     res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
341                          (lstrlenW(value) + 1) * sizeof(WCHAR));
342     RegCloseKey(key);
343     return res;
344 }
345
346 /***********************************************************************
347  *              regsvr_key_defvalueA
348  */
349 static LONG register_key_defvalueA(
350     HKEY base,
351     WCHAR const *name,
352     char const *value)
353 {
354     LONG res;
355     HKEY key;
356
357     res = RegCreateKeyExW(base, name, 0, NULL, 0,
358                           KEY_READ | KEY_WRITE, NULL, &key, NULL);
359     if (res != ERROR_SUCCESS) return res;
360     res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
361                          lstrlenA(value) + 1);
362     RegCloseKey(key);
363     return res;
364 }
365
366 /***********************************************************************
367  *              recursive_delete_key
368  */
369 static LONG recursive_delete_key(HKEY key)
370 {
371     LONG res;
372     WCHAR subkey_name[MAX_PATH];
373     DWORD cName;
374     HKEY subkey;
375
376     for (;;) {
377         cName = sizeof(subkey_name) / sizeof(WCHAR);
378         res = RegEnumKeyExW(key, 0, subkey_name, &cName,
379                             NULL, NULL, NULL, NULL);
380         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
381             res = ERROR_SUCCESS; /* presumably we're done enumerating */
382             break;
383         }
384         res = RegOpenKeyExW(key, subkey_name, 0,
385                             KEY_READ | KEY_WRITE, &subkey);
386         if (res == ERROR_FILE_NOT_FOUND) continue;
387         if (res != ERROR_SUCCESS) break;
388
389         res = recursive_delete_key(subkey);
390         RegCloseKey(subkey);
391         if (res != ERROR_SUCCESS) break;
392     }
393
394     if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
395     return res;
396 }
397
398 /***********************************************************************
399  *              coclass list
400  */
401 static GUID const CLSID_FileMoniker = {
402     0x00000303, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
403
404 static GUID const CLSID_ItemMoniker = {
405     0x00000304, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
406
407 /* FIXME: DfMarshal and PSFactoryBuffer are defined elsewhere too */
408
409 static GUID const CLSID_DfMarshal = {
410     0x0000030B, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
411
412 static GUID const CLSID_PSFactoryBuffer = {
413     0x00000320, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
414
415 static struct regsvr_coclass const coclass_list[] = {
416     {   &CLSID_FileMoniker,
417         "FileMoniker",
418         NULL,
419         "ole32.dll",
420         "Both"
421     },
422     {   &CLSID_ItemMoniker,
423         "ItemMoniker",
424         NULL,
425         "ole32.dll",
426         "Both"
427     },
428     {   &CLSID_DfMarshal,
429         "DfMarshal",
430         NULL,
431         "ole32.dll",
432         "Both"
433     },
434     {   &CLSID_PSFactoryBuffer,
435         "PSFactoryBuffer",
436         NULL,
437         "ole32.dll",
438         "Both"
439     },
440     {   &CLSID_StdGlobalInterfaceTable,
441         "StdGlobalInterfaceTable",
442         NULL,
443         "ole32.dll",
444         "Apartment"
445     },
446     { NULL }                    /* list terminator */
447 };
448
449 /***********************************************************************
450  *              interface list
451  */
452
453 #define INTERFACE_ENTRY(interface, base, clsid32, clsid16) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), clsid16, clsid32 }
454 #define STD_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer, NULL)
455 #define LCL_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, NULL, NULL)
456
457 static const struct regsvr_interface interface_list[] = {
458     LCL_INTERFACE_ENTRY(IUnknown),
459     STD_INTERFACE_ENTRY(IClassFactory),
460     LCL_INTERFACE_ENTRY(IMalloc),
461     LCL_INTERFACE_ENTRY(IMarshal),
462     STD_INTERFACE_ENTRY(IStorage),
463     LCL_INTERFACE_ENTRY(IMessageFilter),
464     LCL_INTERFACE_ENTRY(IStdMarshalInfo),
465     LCL_INTERFACE_ENTRY(IExternalConnection),
466     LCL_INTERFACE_ENTRY(IMallocSpy),
467     LCL_INTERFACE_ENTRY(IMultiQI),
468     STD_INTERFACE_ENTRY(IStream),
469     STD_INTERFACE_ENTRY(IPersistStorage),
470     STD_INTERFACE_ENTRY(IDataObject),
471     STD_INTERFACE_ENTRY(IAdviseSink),
472     LCL_INTERFACE_ENTRY(IDataAdviseHolder),
473     LCL_INTERFACE_ENTRY(IOleAdviseHolder),
474     STD_INTERFACE_ENTRY(IOleObject),
475     STD_INTERFACE_ENTRY(IOleClientSite),
476     LCL_INTERFACE_ENTRY(IDropSource),
477     STD_INTERFACE_ENTRY(IRemUnknown),
478     LCL_INTERFACE_ENTRY(IClientSecurity),
479     LCL_INTERFACE_ENTRY(IServerSecurity),
480     { NULL }                    /* list terminator */
481 };
482
483 /***********************************************************************
484  *              DllRegisterServer (OLE32.@)
485  */
486 HRESULT WINAPI DllRegisterServer()
487 {
488     HRESULT hr;
489
490     TRACE("\n");
491
492     hr = register_coclasses(coclass_list);
493     if (SUCCEEDED(hr))
494         hr = register_interfaces(interface_list);
495     return hr;
496 }
497
498 /***********************************************************************
499  *              DllUnregisterServer (OLE32.@)
500  */
501 HRESULT WINAPI DllUnregisterServer()
502 {
503     HRESULT hr;
504
505     TRACE("\n");
506
507     hr = unregister_coclasses(coclass_list);
508     if (SUCCEEDED(hr))
509         hr = unregister_interfaces(interface_list);
510     return hr;
511 }