| /* |
| * Strmbase DLL functions |
| * |
| * Copyright (C) 2005 Rolf Kalbermatter |
| * Copyright (C) 2010 Aric Stewart, CodeWeavers |
| * |
| * 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 |
| */ |
| #include "config.h" |
| |
| #include <stdarg.h> |
| #include <assert.h> |
| |
| #define COBJMACROS |
| #define NONAMELESSSTRUCT |
| #define NONAMELESSUNION |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winerror.h" |
| #include "winreg.h" |
| #include "objbase.h" |
| #include "uuids.h" |
| #include "strmif.h" |
| |
| #include "wine/unicode.h" |
| #include "wine/debug.h" |
| #include "wine/strmbase.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(strmbase); |
| |
| extern const int g_cTemplates; |
| extern const FactoryTemplate g_Templates[]; |
| |
| static HINSTANCE g_hInst = NULL; |
| static LONG server_locks = 0; |
| |
| /* |
| * defines and constants |
| */ |
| |
| static const WCHAR clsid_keyname[] = {'C','L','S','I','D',0 }; |
| static const WCHAR ips32_keyname[] = {'I','n','P','r','o','c','S','e','r','v','e','r','3','2',0}; |
| static const WCHAR tmodel_keyname[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; |
| static const WCHAR tmodel_both[] = {'B','o','t','h',0}; |
| |
| /* |
| * SetupRegisterClass() |
| */ |
| static HRESULT SetupRegisterClass(HKEY clsid, LPCWSTR szCLSID, |
| LPCWSTR szDescription, |
| LPCWSTR szFileName, |
| LPCWSTR szServerType, |
| LPCWSTR szThreadingModel) |
| { |
| HKEY hkey, hsubkey = NULL; |
| LONG ret = RegCreateKeyW(clsid, szCLSID, &hkey); |
| if (ERROR_SUCCESS != ret) |
| return HRESULT_FROM_WIN32(ret); |
| |
| /* set description string */ |
| ret = RegSetValueW(hkey, NULL, REG_SZ, szDescription, |
| sizeof(WCHAR) * (lstrlenW(szDescription) + 1)); |
| if (ERROR_SUCCESS != ret) |
| goto err_out; |
| |
| /* create CLSID\\{"CLSID"}\\"ServerType" key, using key to CLSID\\{"CLSID"} |
| passed back by last call to RegCreateKeyW(). */ |
| ret = RegCreateKeyW(hkey, szServerType, &hsubkey); |
| if (ERROR_SUCCESS != ret) |
| goto err_out; |
| |
| /* set server path */ |
| ret = RegSetValueW(hsubkey, NULL, REG_SZ, szFileName, |
| sizeof(WCHAR) * (lstrlenW(szFileName) + 1)); |
| if (ERROR_SUCCESS != ret) |
| goto err_out; |
| |
| /* set threading model */ |
| ret = RegSetValueExW(hsubkey, tmodel_keyname, 0L, REG_SZ, |
| (const BYTE*)szThreadingModel, |
| sizeof(WCHAR) * (lstrlenW(szThreadingModel) + 1)); |
| err_out: |
| if (hsubkey) |
| RegCloseKey(hsubkey); |
| RegCloseKey(hkey); |
| return HRESULT_FROM_WIN32(ret); |
| } |
| |
| /* |
| * RegisterAllClasses() |
| */ |
| static HRESULT SetupRegisterAllClasses(const FactoryTemplate * pList, int num, |
| LPCWSTR szFileName, BOOL bRegister) |
| { |
| HRESULT hr = NOERROR; |
| HKEY hkey; |
| OLECHAR szCLSID[CHARS_IN_GUID]; |
| LONG i, ret = RegCreateKeyW(HKEY_CLASSES_ROOT, clsid_keyname, &hkey); |
| if (ERROR_SUCCESS != ret) |
| return HRESULT_FROM_WIN32(ret); |
| |
| for (i = 0; i < num; i++, pList++) |
| { |
| /* (un)register CLSID and InprocServer32 */ |
| hr = StringFromGUID2(pList->m_ClsID, szCLSID, CHARS_IN_GUID); |
| if (SUCCEEDED(hr)) |
| { |
| if (bRegister ) |
| hr = SetupRegisterClass(hkey, szCLSID, |
| pList->m_Name, szFileName, |
| ips32_keyname, tmodel_both); |
| else |
| hr = RegDeleteTreeW(hkey, szCLSID); |
| } |
| } |
| RegCloseKey(hkey); |
| return hr; |
| } |
| |
| HRESULT WINAPI AMovieSetupRegisterFilter2(const AMOVIESETUP_FILTER *pFilter, IFilterMapper2 *pIFM2, BOOL bRegister) |
| { |
| if (!pFilter) |
| return S_OK; |
| |
| if (bRegister) |
| { |
| { |
| REGFILTER2 rf2; |
| rf2.dwVersion = 1; |
| rf2.dwMerit = pFilter->merit; |
| rf2.u.s1.cPins = pFilter->pins; |
| rf2.u.s1.rgPins = pFilter->pPin; |
| |
| return IFilterMapper2_RegisterFilter(pIFM2, pFilter->clsid, pFilter->name, NULL, &CLSID_LegacyAmFilterCategory, NULL, &rf2); |
| } |
| } |
| else |
| return IFilterMapper2_UnregisterFilter(pIFM2, &CLSID_LegacyAmFilterCategory, NULL, pFilter->clsid); |
| } |
| |
| HRESULT WINAPI AMovieDllRegisterServer2(BOOL bRegister) |
| { |
| HRESULT hr; |
| int i; |
| IFilterMapper2 *pIFM2 = NULL; |
| WCHAR szFileName[MAX_PATH]; |
| |
| if (!GetModuleFileNameW(g_hInst, szFileName, MAX_PATH)) |
| { |
| ERR("Failed to get module file name for registration\n"); |
| return E_FAIL; |
| } |
| |
| if (bRegister) |
| hr = SetupRegisterAllClasses(g_Templates, g_cTemplates, szFileName, TRUE ); |
| |
| CoInitialize(NULL); |
| |
| TRACE("Getting IFilterMapper2\r\n"); |
| hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, |
| &IID_IFilterMapper2, (void **)&pIFM2); |
| |
| for (i = 0; SUCCEEDED(hr) && i < g_cTemplates; i++) |
| hr = AMovieSetupRegisterFilter2(g_Templates[i].m_pAMovieSetup_Filter, pIFM2, bRegister); |
| |
| /* release interface */ |
| if (pIFM2) |
| IFilterMapper2_Release(pIFM2); |
| |
| /* and clear up */ |
| CoFreeUnusedLibraries(); |
| CoUninitialize(); |
| |
| /* if unregistering, unregister all OLE servers */ |
| if (SUCCEEDED(hr) && !bRegister) |
| hr = SetupRegisterAllClasses(g_Templates, g_cTemplates, szFileName, FALSE); |
| |
| return hr; |
| } |
| |
| /**************************************************************************** |
| * SetupInitializeServers |
| * |
| * This function is table driven using the static members of the |
| * CFactoryTemplate class defined in the Dll. |
| * |
| * It calls the initialize function for any class in CFactoryTemplate with |
| * one defined. |
| * |
| ****************************************************************************/ |
| static void SetupInitializeServers(const FactoryTemplate * pList, int num, |
| BOOL bLoading) |
| { |
| int i; |
| |
| for (i = 0; i < num; i++, pList++) |
| { |
| if (pList->m_lpfnInit) |
| pList->m_lpfnInit(bLoading, pList->m_ClsID); |
| } |
| } |
| |
| BOOL WINAPI STRMBASE_DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) |
| { |
| switch (fdwReason) |
| { |
| case DLL_PROCESS_ATTACH: |
| g_hInst = hInstDLL; |
| DisableThreadLibraryCalls(hInstDLL); |
| SetupInitializeServers(g_Templates, g_cTemplates, TRUE); |
| break; |
| case DLL_PROCESS_DETACH: |
| SetupInitializeServers(g_Templates, g_cTemplates, FALSE); |
| break; |
| } |
| return TRUE; |
| } |
| |
| /****************************************************************************** |
| * DLL ClassFactory |
| */ |
| typedef struct { |
| IClassFactory IClassFactory_iface; |
| LONG ref; |
| LPFNNewCOMObject pfnCreateInstance; |
| } IClassFactoryImpl; |
| |
| static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) |
| { |
| return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); |
| } |
| |
| static HRESULT WINAPI DSCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj) |
| { |
| if (IsEqualGUID(riid, &IID_IUnknown) || |
| IsEqualGUID(riid, &IID_IClassFactory)) |
| { |
| IClassFactory_AddRef(iface); |
| *ppobj = iface; |
| return S_OK; |
| } |
| |
| *ppobj = NULL; |
| WARN("(%p)->(%s,%p), not found\n", iface, debugstr_guid(riid), ppobj); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI DSCF_AddRef(IClassFactory *iface) |
| { |
| IClassFactoryImpl *This = impl_from_IClassFactory(iface); |
| return InterlockedIncrement(&This->ref); |
| } |
| |
| static ULONG WINAPI DSCF_Release(IClassFactory *iface) |
| { |
| IClassFactoryImpl *This = impl_from_IClassFactory(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| if (ref == 0) |
| HeapFree(GetProcessHeap(), 0, This); |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI DSCF_CreateInstance(IClassFactory *iface, IUnknown *pOuter, |
| REFIID riid, void **ppobj) |
| { |
| IClassFactoryImpl *This = impl_from_IClassFactory(iface); |
| HRESULT hres = ERROR_SUCCESS; |
| LPUNKNOWN punk; |
| |
| TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj); |
| |
| if (!ppobj) |
| return E_POINTER; |
| |
| /* Enforce the normal OLE rules regarding interfaces and delegation */ |
| if (pOuter && !IsEqualGUID(riid, &IID_IUnknown)) |
| return E_NOINTERFACE; |
| |
| *ppobj = NULL; |
| punk = This->pfnCreateInstance(pOuter, &hres); |
| if (!punk) |
| { |
| /* No object created, update error if it isn't done already and return */ |
| if (SUCCEEDED(hres)) |
| hres = E_OUTOFMEMORY; |
| return hres; |
| } |
| |
| if (SUCCEEDED(hres)) |
| { |
| hres = IUnknown_QueryInterface(punk, riid, ppobj); |
| } |
| /* Releasing the object. If everything was successful, QueryInterface |
| should have incremented the refcount once more, otherwise this will |
| purge the object. */ |
| IUnknown_Release(punk); |
| return hres; |
| } |
| |
| static HRESULT WINAPI DSCF_LockServer(IClassFactory *iface, BOOL dolock) |
| { |
| IClassFactoryImpl *This = impl_from_IClassFactory(iface); |
| TRACE("(%p)->(%d)\n",This, dolock); |
| |
| if (dolock) |
| InterlockedIncrement(&server_locks); |
| else |
| InterlockedDecrement(&server_locks); |
| return S_OK; |
| } |
| |
| static const IClassFactoryVtbl DSCF_Vtbl = |
| { |
| DSCF_QueryInterface, |
| DSCF_AddRef, |
| DSCF_Release, |
| DSCF_CreateInstance, |
| DSCF_LockServer |
| }; |
| |
| /*********************************************************************** |
| * DllGetClassObject |
| */ |
| HRESULT WINAPI STRMBASE_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) |
| { |
| const FactoryTemplate *pList = g_Templates; |
| IClassFactoryImpl *factory; |
| int i; |
| |
| TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); |
| |
| if (!ppv) |
| return E_POINTER; |
| |
| *ppv = NULL; |
| |
| if (!IsEqualGUID(&IID_IClassFactory, riid) && |
| !IsEqualGUID(&IID_IUnknown, riid)) |
| return E_NOINTERFACE; |
| |
| for (i = 0; i < g_cTemplates; i++, pList++) |
| { |
| if (IsEqualGUID(pList->m_ClsID, rclsid)) |
| break; |
| } |
| |
| if (i == g_cTemplates) |
| { |
| char dllname[MAX_PATH]; |
| if (!GetModuleFileNameA(g_hInst, dllname, sizeof(dllname))) |
| strcpy(dllname, "???"); |
| ERR("%s: no class found in %s.\n", debugstr_guid(rclsid), dllname); |
| return CLASS_E_CLASSNOTAVAILABLE; |
| } |
| else if (!pList->m_lpfnNew) |
| { |
| FIXME("%s: class not implemented yet.\n", debugstr_guid(rclsid)); |
| return CLASS_E_CLASSNOTAVAILABLE; |
| } |
| |
| factory = HeapAlloc(GetProcessHeap(), 0, sizeof(IClassFactoryImpl)); |
| if (!factory) |
| return E_OUTOFMEMORY; |
| |
| factory->IClassFactory_iface.lpVtbl = &DSCF_Vtbl; |
| factory->ref = 1; |
| |
| factory->pfnCreateInstance = pList->m_lpfnNew; |
| |
| *ppv = &factory->IClassFactory_iface; |
| return S_OK; |
| } |
| |
| /*********************************************************************** |
| * DllCanUnloadNow |
| */ |
| HRESULT WINAPI STRMBASE_DllCanUnloadNow(void) |
| { |
| TRACE("\n"); |
| |
| if (server_locks == 0) |
| return S_OK; |
| return S_FALSE; |
| } |