winspool: Remove cross calls W->A for the "Printers" registry path.
[wine] / dlls / qcap / dllsetup.c
1 /*
2  * DirectX DLL registration and unregistration
3  *
4  * Copyright (C) 2005 Rolf Kalbermatter
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 #include "config.h"
21
22 #include <stdarg.h>
23 #include <assert.h>
24
25 #define COBJMACROS
26 #define NONAMELESSSTRUCT
27 #define NONAMELESSUNION
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "objbase.h"
34 #include "uuids.h"
35
36 #include "dllsetup.h"
37
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
42
43 /*
44  * defines and constants
45  */
46 #define MAX_KEY_LEN  260
47
48 static WCHAR const clsid_keyname[6] =
49 {'C','L','S','I','D',0 };
50 static WCHAR const ips32_keyname[15] =
51 {'I','n','P','r','o','c','S','e','r','v','e','r','3','2',0};
52 static WCHAR const tmodel_keyname[15] =
53 {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
54 static WCHAR const tmodel_both[] =
55 {'B','o','t','h',0};
56
57 /*
58  * Delete a key and all its subkeys
59  */
60 HRESULT DeleteEntireSubKey(HKEY hkey, LPWSTR strSubKey)
61 {
62     WCHAR buffer[MAX_KEY_LEN];
63     DWORD dw = MAX_KEY_LEN;
64     FILETIME ft;
65     HKEY hk;
66     LONG ret = RegOpenKeyExW(hkey, strSubKey, 0, MAXIMUM_ALLOWED, &hk);
67
68     if (ERROR_SUCCESS == ret)
69     {
70         /* Keep on enumerating the first key and deleting that */
71         for( ; ; )
72         {
73             dw = MAX_KEY_LEN;
74
75             ret = RegEnumKeyExW(hk, 0, buffer, &dw, NULL, NULL, NULL, &ft);
76
77             if (ERROR_SUCCESS == ret)
78                 DeleteEntireSubKey(hk, buffer);
79             else
80                 break;
81         }
82         RegCloseKey(hk);
83         RegDeleteKeyW(hkey, strSubKey);
84     }
85     return NOERROR;
86 }
87
88 /*
89  * SetupRegisterClass()
90  */
91 static HRESULT SetupRegisterClass(HKEY clsid, LPCWSTR szCLSID,
92                                   LPCWSTR szDescription,
93                                   LPCWSTR szFileName,
94                                   LPCWSTR szServerType,
95                                   LPCWSTR szThreadingModel)
96 {
97     HKEY hkey, hsubkey;
98     LONG ret = RegCreateKeyW(clsid, szCLSID, &hkey);
99     if (ERROR_SUCCESS != ret)
100         return HRESULT_FROM_WIN32(ret);
101
102     /* set description string */
103     ret = RegSetValueW(hkey, NULL, REG_SZ, szDescription,
104                        sizeof(WCHAR) * (lstrlenW(szDescription) + 1));
105     if (ERROR_SUCCESS != ret)
106         goto err_out;
107
108     /* create CLSID\\{"CLSID"}\\"ServerType" key, using key to CLSID\\{"CLSID"}
109        passed back by last call to RegCreateKeyW(). */
110     ret = RegCreateKeyW(hkey,  szServerType, &hsubkey);
111     if (ERROR_SUCCESS != ret)
112         goto err_out;
113
114     /* set server path */
115     ret = RegSetValueW(hsubkey, NULL, REG_SZ, szFileName,
116                        sizeof(WCHAR) * (lstrlenW(szFileName) + 1));
117     if (ERROR_SUCCESS != ret)
118         goto err_out;
119
120     /* set threading model */
121     ret = RegSetValueExW(hsubkey, tmodel_keyname, 0L, REG_SZ,
122                          (const BYTE*)szThreadingModel, 
123                          sizeof(WCHAR) * (lstrlenW(szThreadingModel) + 1));
124 err_out:
125     if (hsubkey)
126         RegCloseKey(hsubkey);
127     RegCloseKey(hkey);
128     return HRESULT_FROM_WIN32(ret);
129 }
130
131 /*
132  * SetupRegisterFilter through IFilterMapper2
133  */
134 static HRESULT SetupRegisterFilter2(const AMOVIESETUP_FILTER * const pSetup,
135                                     IFilterMapper2 * pIFM2, BOOL bRegister)
136 {
137     HRESULT hr;
138
139     if (NULL == pSetup)
140         return S_FALSE;
141
142     /* unregister filter */
143     hr = IFilterMapper2_UnregisterFilter(pIFM2, 0, 0, pSetup->clsID);
144
145     if (bRegister)
146     {
147         REGFILTER2 rf2;
148         rf2.dwVersion = 1;
149         rf2.dwMerit = pSetup->dwMerit;
150         rf2.u.s.cPins = pSetup->nPins;
151         rf2.u.s.rgPins = pSetup->lpPin;
152     
153         /* register filter */
154         hr = IFilterMapper2_RegisterFilter(pIFM2, pSetup->clsID,
155                                            pSetup->strName, 0, 0, NULL, &rf2);
156     }
157     else
158     {
159         /* filter not found is ignored here,
160            but there is no #define for 0x80070002  */
161         if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
162             hr = NOERROR;
163     }
164     return hr;
165 }
166
167 /*
168  * SetupRegisterFilter through IFilterMapper
169  */
170 static HRESULT SetupRegisterFilter(const AMOVIESETUP_FILTER * const pSetup,
171                                    IFilterMapper * pIFM, BOOL bRegister)
172 {
173     HRESULT hr;
174
175     if (NULL == pSetup)
176         return S_FALSE;
177
178     /* unregister filter */
179     hr = IFilterMapper_UnregisterFilter(pIFM, *pSetup->clsID);
180
181     if (bRegister)
182     {
183         /* register filter */
184         hr = IFilterMapper_RegisterFilter(pIFM, *pSetup->clsID,
185                                           pSetup->strName, pSetup->dwMerit);
186         if (SUCCEEDED(hr))
187         {
188             const AMOVIESETUP_PIN *lpPin = pSetup->lpPin;
189             const AMOVIESETUP_MEDIATYPE *lpType;
190             UINT i, j;
191
192             for (i = 0; i < pSetup->nPins; i++, lpPin++)
193             {
194                 hr = IFilterMapper_RegisterPin(pIFM, *(pSetup->clsID),
195                                                lpPin->strName,
196                                                lpPin->bRendered,
197                                                lpPin->bOutput,
198                                                lpPin->bZero,
199                                                lpPin->bMany,
200                                                *(lpPin->clsConnectsToFilter),
201                                                lpPin->strConnectsToPin);
202
203                 if (SUCCEEDED(hr))
204                 {
205                     lpType = lpPin->lpMediaType;
206
207                     /* and each pin's media types */
208                     for (j = 0; j < lpPin->nMediaTypes; j++, lpType++)
209                     {
210                         hr = IFilterMapper_RegisterPinType(pIFM, *(pSetup->clsID),
211                                                            lpPin->strName,
212                                                            *(lpType->clsMajorType),
213                                                            *(lpType->clsMinorType));
214                         if (FAILED(hr)) break;
215                     }
216                     if (FAILED(hr)) break;
217                 }
218                 if (FAILED(hr)) break;
219             }
220         }
221     }
222     else
223     {
224         /* filter not registered is ignored here, there is no definition for 0x80070002  */
225         if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
226            hr = NOERROR;
227     }
228     return hr;
229 }
230
231 /*
232  * RegisterAllClasses()
233  */
234 static HRESULT SetupRegisterAllClasses(const CFactoryTemplate * pList, int num,
235                                        LPCWSTR szFileName, BOOL bRegister)
236 {
237     HRESULT hr = NOERROR;
238     HKEY hkey;
239     OLECHAR szCLSID[CHARS_IN_GUID];
240     LONG i, ret = RegCreateKeyW(HKEY_CLASSES_ROOT, clsid_keyname, &hkey);
241     if (ERROR_SUCCESS != ret)
242         return HRESULT_FROM_WIN32(ret);
243
244     for (i = 0; i < num; i++, pList++)
245     {
246         /* (un)register CLSID and InprocServer32 */
247         hr = StringFromGUID2(pList->m_ClsID, szCLSID, CHARS_IN_GUID);
248         if (SUCCEEDED(hr))
249         {
250             if (bRegister )
251                 hr = SetupRegisterClass(hkey, szCLSID,
252                                         pList->m_Name, szFileName,
253                                         ips32_keyname, tmodel_both);
254             else
255                 hr = DeleteEntireSubKey(hkey, szCLSID);
256         }
257     }
258     RegCloseKey(hkey);
259     return hr;
260 }
261
262
263 /****************************************************************************
264  * SetupRegisterServers
265  *
266  * This function is table driven using the static members of the
267  * CFactoryTemplate class defined in the Dll.
268  *
269  * It registers the Dll as the InprocServer32 for all the classes in
270  * CFactoryTemplate
271  *
272  ****************************************************************************/
273 HRESULT SetupRegisterServers(const CFactoryTemplate * pList, int num,
274                              HINSTANCE hinst, BOOL bRegister)
275 {
276     HRESULT hr = NOERROR;
277     WCHAR szFileName[MAX_PATH];
278     IFilterMapper2 *pIFM2 = NULL;
279     IFilterMapper *pIFM = NULL;
280
281     /* Win95 wouldn't support the Unicode version of this API!! */
282     if (!GetModuleFileNameW(hinst, szFileName, MAX_PATH))
283         return HRESULT_FROM_WIN32(GetLastError());
284
285     /* first register all server classes, just to make sure */
286     if (bRegister)
287         hr = SetupRegisterAllClasses(pList, num, szFileName, TRUE );
288
289     /* next, register/unregister all filters */
290     if (SUCCEEDED(hr))
291     {
292         hr = CoInitialize(NULL);
293
294         TRACE("Getting IFilterMapper2\r\n");
295         hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
296                               &IID_IFilterMapper2, (void **)&pIFM2);
297         if (FAILED(hr))
298         {
299             TRACE("- trying IFilterMapper instead\r\n");
300
301             hr = CoCreateInstance(&CLSID_FilterMapper, NULL, CLSCTX_INPROC_SERVER,
302                                   &IID_IFilterMapper, (void **)&pIFM);
303         }
304
305         if (SUCCEEDED(hr))
306         {
307             int i;
308             
309             /* scan through array of CFactoryTemplates registering all filters */
310             for (i = 0; i < num; i++, pList++)
311             {
312                 if (NULL != pList->m_pAMovieSetup_Filter)
313                 {
314                     if (pIFM2)
315                         hr = SetupRegisterFilter2(pList->m_pAMovieSetup_Filter,
316                                                   pIFM2, bRegister);
317                     else
318                         hr = SetupRegisterFilter(pList->m_pAMovieSetup_Filter,
319                                                  pIFM, bRegister);
320                 }
321
322                 /* check final error for this pass and break loop if we failed */
323                 if (FAILED(hr))
324                     break;
325             }
326
327             /* release interface */
328             if (pIFM2)
329                 IFilterMapper2_Release(pIFM2);
330             else
331                 IFilterMapper_Release(pIFM);
332         }
333
334         /* and clear up */
335         CoFreeUnusedLibraries();
336         CoUninitialize();
337     }
338
339     /* if unregistering, unregister all OLE servers */
340     if (SUCCEEDED(hr) && !bRegister)
341         hr = SetupRegisterAllClasses(pList, num, szFileName, FALSE);
342     return hr;
343 }
344
345 /****************************************************************************
346  * SetupInitializeServers
347  *
348  * This function is table driven using the static members of the
349  * CFactoryTemplate class defined in the Dll.
350  *
351  * It calls the intialize function for any class in CFactoryTemplate with
352  * one defined.
353  *
354  ****************************************************************************/
355 void SetupInitializeServers(const CFactoryTemplate * pList, int num,
356                             BOOL bLoading)
357 {
358     int i;
359
360     for (i = 0; i < num; i++, pList++)
361     {
362         if (pList->m_lpfnInit)
363             pList->m_lpfnInit(bLoading, pList->m_ClsID);
364     }
365 }