| /* |
| * DirectX DLL registration and unregistration |
| * |
| * Copyright (C) 2005 Rolf Kalbermatter |
| * |
| * 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 "winerror.h" |
| #include "winreg.h" |
| #include "objbase.h" |
| #include "uuids.h" |
| |
| #include "dllsetup.h" |
| |
| #include "wine/unicode.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(qcap); |
| |
| /* |
| * defines and constants |
| */ |
| #define MAX_KEY_LEN 260 |
| |
| static WCHAR const clsid_keyname[6] = |
| {'C','L','S','I','D',0 }; |
| static WCHAR const ips32_keyname[15] = |
| {'I','n','P','r','o','c','S','e','r','v','e','r','3','2',0}; |
| static WCHAR const tmodel_keyname[15] = |
| {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; |
| static WCHAR const tmodel_both[] = |
| {'B','o','t','h',0}; |
| |
| /* |
| * Delete a key and all its subkeys |
| */ |
| HRESULT DeleteEntireSubKey(HKEY hkey, LPWSTR strSubKey) |
| { |
| WCHAR buffer[MAX_KEY_LEN]; |
| DWORD dw = MAX_KEY_LEN; |
| FILETIME ft; |
| HKEY hk; |
| LONG ret = RegOpenKeyExW(hkey, strSubKey, 0, MAXIMUM_ALLOWED, &hk); |
| |
| if (ERROR_SUCCESS == ret) |
| { |
| /* Keep on enumerating the first key and deleting that */ |
| for( ; ; ) |
| { |
| dw = MAX_KEY_LEN; |
| |
| ret = RegEnumKeyExW(hk, 0, buffer, &dw, NULL, NULL, NULL, &ft); |
| |
| if (ERROR_SUCCESS == ret) |
| DeleteEntireSubKey(hk, buffer); |
| else |
| break; |
| } |
| RegCloseKey(hk); |
| RegDeleteKeyW(hkey, strSubKey); |
| } |
| return NOERROR; |
| } |
| |
| /* |
| * SetupRegisterClass() |
| */ |
| static HRESULT SetupRegisterClass(HKEY clsid, LPCWSTR szCLSID, |
| LPCWSTR szDescription, |
| LPCWSTR szFileName, |
| LPCWSTR szServerType, |
| LPCWSTR szThreadingModel) |
| { |
| HKEY hkey, hsubkey; |
| 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); |
| } |
| |
| /* |
| * SetupRegisterFilter through IFilterMapper2 |
| */ |
| static HRESULT SetupRegisterFilter2(const AMOVIESETUP_FILTER * const pSetup, |
| IFilterMapper2 * pIFM2, BOOL bRegister) |
| { |
| HRESULT hr; |
| |
| if (NULL == pSetup) |
| return S_FALSE; |
| |
| /* unregister filter */ |
| hr = IFilterMapper2_UnregisterFilter(pIFM2, 0, 0, pSetup->clsID); |
| |
| if (bRegister) |
| { |
| REGFILTER2 rf2; |
| rf2.dwVersion = 1; |
| rf2.dwMerit = pSetup->dwMerit; |
| rf2.u.s.cPins = pSetup->nPins; |
| rf2.u.s.rgPins = pSetup->lpPin; |
| |
| /* register filter */ |
| hr = IFilterMapper2_RegisterFilter(pIFM2, pSetup->clsID, |
| pSetup->strName, 0, 0, NULL, &rf2); |
| } |
| else |
| { |
| /* filter not found is ignored here, |
| but there is no #define for 0x80070002 */ |
| if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) |
| hr = NOERROR; |
| } |
| return hr; |
| } |
| |
| /* |
| * SetupRegisterFilter through IFilterMapper |
| */ |
| static HRESULT SetupRegisterFilter(const AMOVIESETUP_FILTER * const pSetup, |
| IFilterMapper * pIFM, BOOL bRegister) |
| { |
| HRESULT hr; |
| |
| if (NULL == pSetup) |
| return S_FALSE; |
| |
| /* unregister filter */ |
| hr = IFilterMapper_UnregisterFilter(pIFM, *pSetup->clsID); |
| |
| if (bRegister) |
| { |
| /* register filter */ |
| hr = IFilterMapper_RegisterFilter(pIFM, *pSetup->clsID, |
| pSetup->strName, pSetup->dwMerit); |
| if (SUCCEEDED(hr)) |
| { |
| const AMOVIESETUP_PIN *lpPin = pSetup->lpPin; |
| const AMOVIESETUP_MEDIATYPE *lpType; |
| UINT i, j; |
| |
| for (i = 0; i < pSetup->nPins; i++, lpPin++) |
| { |
| hr = IFilterMapper_RegisterPin(pIFM, *(pSetup->clsID), |
| lpPin->strName, |
| lpPin->bRendered, |
| lpPin->bOutput, |
| lpPin->bZero, |
| lpPin->bMany, |
| *(lpPin->clsConnectsToFilter), |
| lpPin->strConnectsToPin); |
| |
| if (SUCCEEDED(hr)) |
| { |
| lpType = lpPin->lpMediaType; |
| |
| /* and each pin's media types */ |
| for (j = 0; j < lpPin->nMediaTypes; j++, lpType++) |
| { |
| hr = IFilterMapper_RegisterPinType(pIFM, *(pSetup->clsID), |
| lpPin->strName, |
| *(lpType->clsMajorType), |
| *(lpType->clsMinorType)); |
| if (FAILED(hr)) break; |
| } |
| if (FAILED(hr)) break; |
| } |
| if (FAILED(hr)) break; |
| } |
| } |
| } |
| else |
| { |
| /* filter not registered is ignored here, there is no definition for 0x80070002 */ |
| if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) |
| hr = NOERROR; |
| } |
| return hr; |
| } |
| |
| /* |
| * RegisterAllClasses() |
| */ |
| static HRESULT SetupRegisterAllClasses(const CFactoryTemplate * 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 = DeleteEntireSubKey(hkey, szCLSID); |
| } |
| } |
| RegCloseKey(hkey); |
| return hr; |
| } |
| |
| |
| /**************************************************************************** |
| * SetupRegisterServers |
| * |
| * This function is table driven using the static members of the |
| * CFactoryTemplate class defined in the Dll. |
| * |
| * It registers the Dll as the InprocServer32 for all the classes in |
| * CFactoryTemplate |
| * |
| ****************************************************************************/ |
| HRESULT SetupRegisterServers(const CFactoryTemplate * pList, int num, |
| HINSTANCE hinst, BOOL bRegister) |
| { |
| HRESULT hr = NOERROR; |
| WCHAR szFileName[MAX_PATH]; |
| IFilterMapper2 *pIFM2 = NULL; |
| IFilterMapper *pIFM = NULL; |
| |
| /* Win95 wouldn't support the Unicode version of this API!! */ |
| if (!GetModuleFileNameW(hinst, szFileName, MAX_PATH)) |
| return HRESULT_FROM_WIN32(GetLastError()); |
| |
| /* first register all server classes, just to make sure */ |
| if (bRegister) |
| hr = SetupRegisterAllClasses(pList, num, szFileName, TRUE ); |
| |
| /* next, register/unregister all filters */ |
| if (SUCCEEDED(hr)) |
| { |
| hr = CoInitialize(NULL); |
| |
| TRACE("Getting IFilterMapper2\r\n"); |
| hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, |
| &IID_IFilterMapper2, (void **)&pIFM2); |
| if (FAILED(hr)) |
| { |
| TRACE("- trying IFilterMapper instead\r\n"); |
| |
| hr = CoCreateInstance(&CLSID_FilterMapper, NULL, CLSCTX_INPROC_SERVER, |
| &IID_IFilterMapper, (void **)&pIFM); |
| } |
| |
| if (SUCCEEDED(hr)) |
| { |
| int i; |
| |
| /* scan through array of CFactoryTemplates registering all filters */ |
| for (i = 0; i < num; i++, pList++) |
| { |
| if (NULL != pList->m_pAMovieSetup_Filter) |
| { |
| if (pIFM2) |
| hr = SetupRegisterFilter2(pList->m_pAMovieSetup_Filter, |
| pIFM2, bRegister); |
| else |
| hr = SetupRegisterFilter(pList->m_pAMovieSetup_Filter, |
| pIFM, bRegister); |
| } |
| |
| /* check final error for this pass and break loop if we failed */ |
| if (FAILED(hr)) |
| break; |
| } |
| |
| /* release interface */ |
| if (pIFM2) |
| IFilterMapper2_Release(pIFM2); |
| else |
| IFilterMapper_Release(pIFM); |
| } |
| |
| /* and clear up */ |
| CoFreeUnusedLibraries(); |
| CoUninitialize(); |
| } |
| |
| /* if unregistering, unregister all OLE servers */ |
| if (SUCCEEDED(hr) && !bRegister) |
| hr = SetupRegisterAllClasses(pList, num, 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 intialize function for any class in CFactoryTemplate with |
| * one defined. |
| * |
| ****************************************************************************/ |
| void SetupInitializeServers(const CFactoryTemplate * 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); |
| } |
| } |