[STRMBASE]
[reactos.git] / reactos / lib / 3rdparty / strmbase / dllfunc.c
1 /*
2 * Strmbase DLL functions
3 *
4 * Copyright (C) 2005 Rolf Kalbermatter
5 * Copyright (C) 2010 Aric Stewart, CodeWeavers
6 *
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.
11 *
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.
16 *
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 St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "strmbase_private.h"
23
24 extern const int g_cTemplates;
25 extern const FactoryTemplate g_Templates[];
26
27 static HINSTANCE g_hInst = NULL;
28 static LONG server_locks = 0;
29
30 /*
31 * defines and constants
32 */
33 #define MAX_KEY_LEN 260
34
35 static const WCHAR clsid_keyname[] = {'C','L','S','I','D',0 };
36 static const WCHAR ips32_keyname[] = {'I','n','P','r','o','c','S','e','r','v','e','r','3','2',0};
37 static const WCHAR tmodel_keyname[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
38 static const WCHAR tmodel_both[] = {'B','o','t','h',0};
39
40 #ifdef __REACTOS__
41 static LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
42 {
43 LONG ret;
44 DWORD dwMaxSubkeyLen, dwMaxValueLen;
45 DWORD dwMaxLen, dwSize;
46 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
47 HKEY hSubKey = hKey;
48
49 TRACE("(hkey=%p,%p %s)\n", hKey, lpszSubKey, debugstr_w(lpszSubKey));
50
51 if(lpszSubKey)
52 {
53 ret = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
54 if (ret) return ret;
55 }
56
57 /* Get highest length for keys, values */
58 ret = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
59 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL);
60 if (ret) goto cleanup;
61
62 dwMaxSubkeyLen++;
63 dwMaxValueLen++;
64 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
65 if (dwMaxLen > sizeof(szNameBuf)/sizeof(WCHAR))
66 {
67 /* Name too big: alloc a buffer for it */
68 if (!(lpszName = HeapAlloc( GetProcessHeap(), 0, dwMaxLen*sizeof(WCHAR))))
69 {
70 ret = ERROR_NOT_ENOUGH_MEMORY;
71 goto cleanup;
72 }
73 }
74
75
76 /* Recursively delete all the subkeys */
77 while (TRUE)
78 {
79 dwSize = dwMaxLen;
80 if (RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL,
81 NULL, NULL, NULL)) break;
82
83 ret = RegDeleteTreeW(hSubKey, lpszName);
84 if (ret) goto cleanup;
85 }
86
87 if (lpszSubKey)
88 ret = RegDeleteKeyW(hKey, lpszSubKey);
89 else
90 while (TRUE)
91 {
92 dwSize = dwMaxLen;
93 if (RegEnumValueW(hKey, 0, lpszName, &dwSize,
94 NULL, NULL, NULL, NULL)) break;
95
96 ret = RegDeleteValueW(hKey, lpszName);
97 if (ret) goto cleanup;
98 }
99
100 cleanup:
101 /* Free buffer if allocated */
102 if (lpszName != szNameBuf)
103 HeapFree( GetProcessHeap(), 0, lpszName);
104 if(lpszSubKey)
105 RegCloseKey(hSubKey);
106 return ret;
107 }
108 #endif
109
110 /*
111 * SetupRegisterClass()
112 */
113 static HRESULT SetupRegisterClass(HKEY clsid, LPCWSTR szCLSID,
114 LPCWSTR szDescription,
115 LPCWSTR szFileName,
116 LPCWSTR szServerType,
117 LPCWSTR szThreadingModel)
118 {
119 HKEY hkey, hsubkey = NULL;
120 LONG ret = RegCreateKeyW(clsid, szCLSID, &hkey);
121 if (ERROR_SUCCESS != ret)
122 return HRESULT_FROM_WIN32(ret);
123
124 /* set description string */
125 ret = RegSetValueW(hkey, NULL, REG_SZ, szDescription,
126 sizeof(WCHAR) * (lstrlenW(szDescription) + 1));
127 if (ERROR_SUCCESS != ret)
128 goto err_out;
129
130 /* create CLSID\\{"CLSID"}\\"ServerType" key, using key to CLSID\\{"CLSID"}
131 passed back by last call to RegCreateKeyW(). */
132 ret = RegCreateKeyW(hkey, szServerType, &hsubkey);
133 if (ERROR_SUCCESS != ret)
134 goto err_out;
135
136 /* set server path */
137 ret = RegSetValueW(hsubkey, NULL, REG_SZ, szFileName,
138 sizeof(WCHAR) * (lstrlenW(szFileName) + 1));
139 if (ERROR_SUCCESS != ret)
140 goto err_out;
141
142 /* set threading model */
143 ret = RegSetValueExW(hsubkey, tmodel_keyname, 0L, REG_SZ,
144 (const BYTE*)szThreadingModel,
145 sizeof(WCHAR) * (lstrlenW(szThreadingModel) + 1));
146 err_out:
147 if (hsubkey)
148 RegCloseKey(hsubkey);
149 RegCloseKey(hkey);
150 return HRESULT_FROM_WIN32(ret);
151 }
152
153 /*
154 * RegisterAllClasses()
155 */
156 static HRESULT SetupRegisterAllClasses(const FactoryTemplate * pList, int num,
157 LPCWSTR szFileName, BOOL bRegister)
158 {
159 HRESULT hr = NOERROR;
160 HKEY hkey;
161 OLECHAR szCLSID[CHARS_IN_GUID];
162 LONG i, ret = RegCreateKeyW(HKEY_CLASSES_ROOT, clsid_keyname, &hkey);
163 if (ERROR_SUCCESS != ret)
164 return HRESULT_FROM_WIN32(ret);
165
166 for (i = 0; i < num; i++, pList++)
167 {
168 /* (un)register CLSID and InprocServer32 */
169 hr = StringFromGUID2(pList->m_ClsID, szCLSID, CHARS_IN_GUID);
170 if (SUCCEEDED(hr))
171 {
172 if (bRegister )
173 hr = SetupRegisterClass(hkey, szCLSID,
174 pList->m_Name, szFileName,
175 ips32_keyname, tmodel_both);
176 else
177 hr = RegDeleteTreeW(hkey, szCLSID);
178 }
179 }
180 RegCloseKey(hkey);
181 return hr;
182 }
183
184 HRESULT WINAPI AMovieSetupRegisterFilter2(const AMOVIESETUP_FILTER *pFilter, IFilterMapper2 *pIFM2, BOOL bRegister)
185 {
186 if (!pFilter)
187 return S_OK;
188
189 if (bRegister)
190 {
191 {
192 REGFILTER2 rf2;
193 rf2.dwVersion = 1;
194 rf2.dwMerit = pFilter->merit;
195 rf2.u.s1.cPins = pFilter->pins;
196 rf2.u.s1.rgPins = pFilter->pPin;
197
198 return IFilterMapper2_RegisterFilter(pIFM2, pFilter->clsid, pFilter->name, NULL, &CLSID_LegacyAmFilterCategory, NULL, &rf2);
199 }
200 }
201 else
202 return IFilterMapper2_UnregisterFilter(pIFM2, &CLSID_LegacyAmFilterCategory, NULL, pFilter->clsid);
203 }
204
205 HRESULT WINAPI AMovieDllRegisterServer2(BOOL bRegister)
206 {
207 HRESULT hr;
208 int i;
209 IFilterMapper2 *pIFM2 = NULL;
210 WCHAR szFileName[MAX_PATH];
211
212 if (!GetModuleFileNameW(g_hInst, szFileName, MAX_PATH))
213 {
214 ERR("Failed to get module file name for registration\n");
215 return E_FAIL;
216 }
217
218 if (bRegister)
219 hr = SetupRegisterAllClasses(g_Templates, g_cTemplates, szFileName, TRUE );
220
221 hr = CoInitialize(NULL);
222
223 TRACE("Getting IFilterMapper2\r\n");
224 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
225 &IID_IFilterMapper2, (void **)&pIFM2);
226
227 for (i = 0; SUCCEEDED(hr) && i < g_cTemplates; i++)
228 hr = AMovieSetupRegisterFilter2(g_Templates[i].m_pAMovieSetup_Filter, pIFM2, bRegister);
229
230 /* release interface */
231 if (pIFM2)
232 IFilterMapper2_Release(pIFM2);
233
234 /* and clear up */
235 CoFreeUnusedLibraries();
236 CoUninitialize();
237
238 /* if unregistering, unregister all OLE servers */
239 if (SUCCEEDED(hr) && !bRegister)
240 hr = SetupRegisterAllClasses(g_Templates, g_cTemplates, szFileName, FALSE);
241
242 return hr;
243 }
244
245 /****************************************************************************
246 * SetupInitializeServers
247 *
248 * This function is table driven using the static members of the
249 * CFactoryTemplate class defined in the Dll.
250 *
251 * It calls the initialize function for any class in CFactoryTemplate with
252 * one defined.
253 *
254 ****************************************************************************/
255 static void SetupInitializeServers(const FactoryTemplate * pList, int num,
256 BOOL bLoading)
257 {
258 int i;
259
260 for (i = 0; i < num; i++, pList++)
261 {
262 if (pList->m_lpfnInit)
263 pList->m_lpfnInit(bLoading, pList->m_ClsID);
264 }
265 }
266
267 BOOL WINAPI STRMBASE_DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
268 {
269 switch (fdwReason)
270 {
271 case DLL_PROCESS_ATTACH:
272 g_hInst = hInstDLL;
273 DisableThreadLibraryCalls(hInstDLL);
274 SetupInitializeServers(g_Templates, g_cTemplates, TRUE);
275 break;
276 case DLL_PROCESS_DETACH:
277 SetupInitializeServers(g_Templates, g_cTemplates, FALSE);
278 break;
279 }
280 return TRUE;
281 }
282
283 /******************************************************************************
284 * DLL ClassFactory
285 */
286 typedef struct {
287 IClassFactory IClassFactory_iface;
288 LONG ref;
289 LPFNNewCOMObject pfnCreateInstance;
290 } IClassFactoryImpl;
291
292 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
293 {
294 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
295 }
296
297 static HRESULT WINAPI DSCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
298 {
299 if (IsEqualGUID(riid, &IID_IUnknown) ||
300 IsEqualGUID(riid, &IID_IClassFactory))
301 {
302 IClassFactory_AddRef(iface);
303 *ppobj = iface;
304 return S_OK;
305 }
306
307 *ppobj = NULL;
308 WARN("(%p)->(%s,%p), not found\n", iface, debugstr_guid(riid), ppobj);
309 return E_NOINTERFACE;
310 }
311
312 static ULONG WINAPI DSCF_AddRef(IClassFactory *iface)
313 {
314 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
315 return InterlockedIncrement(&This->ref);
316 }
317
318 static ULONG WINAPI DSCF_Release(IClassFactory *iface)
319 {
320 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
321 ULONG ref = InterlockedDecrement(&This->ref);
322
323 if (ref == 0)
324 HeapFree(GetProcessHeap(), 0, This);
325
326 return ref;
327 }
328
329 static HRESULT WINAPI DSCF_CreateInstance(IClassFactory *iface, IUnknown *pOuter,
330 REFIID riid, void **ppobj)
331 {
332 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
333 HRESULT hres = ERROR_SUCCESS;
334 LPUNKNOWN punk;
335
336 TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj);
337
338 if (!ppobj)
339 return E_POINTER;
340
341 /* Enforce the normal OLE rules regarding interfaces and delegation */
342 if (pOuter && !IsEqualGUID(riid, &IID_IUnknown))
343 return E_NOINTERFACE;
344
345 *ppobj = NULL;
346 punk = This->pfnCreateInstance(pOuter, &hres);
347 if (!punk)
348 {
349 /* No object created, update error if it isn't done already and return */
350 if (SUCCEEDED(hres))
351 hres = E_OUTOFMEMORY;
352 return hres;
353 }
354
355 if (SUCCEEDED(hres))
356 {
357 hres = IUnknown_QueryInterface(punk, riid, ppobj);
358 }
359 /* Releasing the object. If everything was successful, QueryInterface
360 should have incremented the refcount once more, otherwise this will
361 purge the object. */
362 IUnknown_Release(punk);
363 return hres;
364 }
365
366 static HRESULT WINAPI DSCF_LockServer(IClassFactory *iface, BOOL dolock)
367 {
368 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
369 TRACE("(%p)->(%d)\n",This, dolock);
370
371 if (dolock)
372 InterlockedIncrement(&server_locks);
373 else
374 InterlockedDecrement(&server_locks);
375 return S_OK;
376 }
377
378 static const IClassFactoryVtbl DSCF_Vtbl =
379 {
380 DSCF_QueryInterface,
381 DSCF_AddRef,
382 DSCF_Release,
383 DSCF_CreateInstance,
384 DSCF_LockServer
385 };
386
387 /***********************************************************************
388 * DllGetClassObject
389 */
390 HRESULT WINAPI STRMBASE_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
391 {
392 const FactoryTemplate *pList = g_Templates;
393 IClassFactoryImpl *factory;
394 int i;
395
396 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
397
398 if (!ppv)
399 return E_POINTER;
400
401 *ppv = NULL;
402
403 if (!IsEqualGUID(&IID_IClassFactory, riid) &&
404 !IsEqualGUID(&IID_IUnknown, riid))
405 return E_NOINTERFACE;
406
407 for (i = 0; i < g_cTemplates; i++, pList++)
408 {
409 if (IsEqualGUID(pList->m_ClsID, rclsid))
410 break;
411 }
412
413 if (i == g_cTemplates)
414 {
415 char dllname[MAX_PATH];
416 if (!GetModuleFileNameA(g_hInst, dllname, sizeof(dllname)))
417 strcpy(dllname, "???");
418 ERR("%s: no class found in %s.\n", debugstr_guid(rclsid), dllname);
419 return CLASS_E_CLASSNOTAVAILABLE;
420 }
421 else if (!pList->m_lpfnNew)
422 {
423 FIXME("%s: class not implemented yet.\n", debugstr_guid(rclsid));
424 return CLASS_E_CLASSNOTAVAILABLE;
425 }
426
427 factory = HeapAlloc(GetProcessHeap(), 0, sizeof(IClassFactoryImpl));
428 if (!factory)
429 return E_OUTOFMEMORY;
430
431 factory->IClassFactory_iface.lpVtbl = &DSCF_Vtbl;
432 factory->ref = 1;
433
434 factory->pfnCreateInstance = pList->m_lpfnNew;
435
436 *ppv = &factory->IClassFactory_iface;
437 return S_OK;
438 }
439
440 /***********************************************************************
441 * DllCanUnloadNow
442 */
443 HRESULT WINAPI STRMBASE_DllCanUnloadNow(void)
444 {
445 TRACE("\n");
446
447 if (server_locks == 0)
448 return S_OK;
449 return S_FALSE;
450 }