// MediaDevMgr.cpp : Implementation of CMediaDevMgr #include "stdafx.h" #include "mswmdm.h" #include "loghelp.h" #include "MediaDevMgr.h" #include "WMDMDeviceEnum.h" #include "SCServer.h" #include "key.h" #define STRSAFE_NO_DEPRECATE #include "strsafe.h" #define SDK_VERSION 0x00080000 #define WMDM_REG_LOCATION _T("Software\\Microsoft\\Windows Media Device Manager") #define MDSP_REG_LOCATION _T("Software\\Microsoft\\Windows Media Device Manager\\Plugins\\SP") #define MDSCP_REG_LOCATION _T("Software\\Microsoft\\Windows Media Device Manager\\Plugins\\SCP") #define MSSCP_PROGID L"MsScp.MSSCP.1" #define MSSCP_KEYNAME _T("MSSCP") ///////////////////////////////////////////////////////////////////////////// // CMediaDevMgr CSPInfo **g_pSPs = NULL; WORD g_wSPCount = 0; CSCPInfo **g_pSCPs = NULL; WORD g_wSCPCount = 0; int g_nGlobalRefCount = 0; CComAutoCriticalSection csGlobal; CSecureChannelServer *g_pAppSCServer = NULL; // // This method is called by objects accessing the global SP, SCP arrays. // These objects will need to call GlobalAddRef, GlobalRelease so that we // know when we can unload the plugins. // void GlobalAddRef() { csGlobal.Lock(); g_nGlobalRefCount ++; csGlobal.Unlock(); } void GlobalRelease() { csGlobal.Lock(); g_nGlobalRefCount --; // Check if we can unload SP's, SCP's if( g_nGlobalRefCount == 0 ) { int iIndex; if( g_pSPs ) { for(iIndex=0;iIndexSetCertificate(SAC_CERT_V1, (BYTE*)g_abAppCert, sizeof(g_abAppCert), (BYTE*)g_abPriv, sizeof(g_abPriv)); } // Do we need to load SP's? csGlobal.Lock(); if( g_pSPs == NULL ) { hrLoadSPs(); } csGlobal.Unlock(); } CMediaDevMgr::~CMediaDevMgr() { // Decrease refcount to SPs, SCPs GlobalRelease(); } // Static helper function. The SCP's are loaded on first use for pref. HRESULT CMediaDevMgr::LoadSCPs() { HRESULT hr = S_OK; csGlobal.Lock(); if(g_pSCPs == NULL) { hr = hrLoadSCPs(); } csGlobal.Unlock(); return hr; } HRESULT CMediaDevMgr::hrLoadSPs() { USES_CONVERSION; HRESULT hr; HKEY hKey = NULL; HKEY hSubKey = NULL; LONG lRetVal; LONG lRetVal2; DWORD dwSubKeys; DWORD dwMaxNameLen; WORD wIndex = 0; LPTSTR ptszKeyName = NULL; DWORD dwKeyNameLen; DWORD dwType; BYTE pbData[512]; DWORD dwDataLen = 512; char szMessage[512+64]; lRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, MDSP_REG_LOCATION, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hKey); if (lRetVal != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal); goto exit; } // Get the count of Sub-Keys under SP lRetVal = RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwSubKeys, &dwMaxNameLen, NULL, NULL, NULL, NULL, NULL, NULL); if (lRetVal != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal); goto exit; } dwMaxNameLen++; // Allocate a buffer to hold the subkey names ptszKeyName = new TCHAR[dwMaxNameLen]; if (!ptszKeyName) { hr = E_OUTOFMEMORY; goto exit; } // Allocate the array of CSPInfo *'s g_pSPs = new CSPInfo *[dwSubKeys]; if (!g_pSPs) { hr = E_OUTOFMEMORY; goto exit; } // Loop through the sub-keys initializing a CSPInfo for each sub key lRetVal = ERROR_SUCCESS; while (lRetVal != ERROR_NO_MORE_ITEMS) { dwKeyNameLen = dwMaxNameLen; lRetVal = RegEnumKeyEx(hKey, wIndex, ptszKeyName, &dwKeyNameLen, NULL, NULL, NULL, NULL); if (lRetVal == ERROR_SUCCESS) { lRetVal2 = RegOpenKeyEx(hKey, ptszKeyName, NULL, KEY_QUERY_VALUE, &hSubKey); if (lRetVal2 != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal2); goto exit; } g_pSPs[g_wSPCount] = new CSPInfo; if (!g_pSPs[g_wSPCount]) { hr = E_OUTOFMEMORY; goto exit; } dwDataLen = sizeof(pbData); lRetVal2 = RegQueryValueEx(hSubKey, _T("ProgID"), NULL, &dwType, pbData, &dwDataLen); if (lRetVal2 != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal2); goto exit; } strcpy(szMessage, "Loading SP ProgID = "); hr = StringCbCat(szMessage, sizeof(szMessage), (LPTSTR)pbData); if(SUCCEEDED(hr) ) { hrLogString(szMessage, S_OK); } hr = g_pSPs[g_wSPCount]->hrInitialize(T2W((LPTSTR)pbData)); if (FAILED(hr)) { // If this SP didn't initialize then we just try the next one. delete g_pSPs[g_wSPCount]; } else { // We have added the CSPInfo to the array no inc the counter g_wSPCount++; } RegCloseKey(hSubKey); hSubKey = NULL; wIndex++; } else if (lRetVal != ERROR_NO_MORE_ITEMS) { hr = HRESULT_FROM_WIN32(lRetVal); goto exit; } } hr = S_OK; exit: if (hKey) RegCloseKey(hKey); if (hSubKey) RegCloseKey(hSubKey); if (ptszKeyName) delete [] ptszKeyName; hrLogDWORD("CMediaDevMgr::hrLoadSPs returned 0x%08lx", hr, hr); return hr; } HRESULT CMediaDevMgr::hrLoadSCPs() { USES_CONVERSION; HRESULT hr; HKEY hKey = NULL; HKEY hSubKey = NULL; LONG lRetVal; LONG lRetVal2; DWORD dwSubKeys; DWORD dwMaxNameLen; WORD wIndex = 0; LPTSTR ptszKeyName = NULL; DWORD dwKeyNameLen; DWORD dwType; BYTE pbData[512]; DWORD dwDataLen = 512; char szMessage[512]; lRetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE, MDSCP_REG_LOCATION, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hKey); if (lRetVal != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal); goto exit; } // Get the count of Sub-Keys under SP lRetVal = RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwSubKeys, &dwMaxNameLen, NULL, NULL, NULL, NULL, NULL, NULL); if (lRetVal != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal); goto exit; } dwMaxNameLen++; // Allocate a buffer to hold the subkey names ptszKeyName = new TCHAR[dwMaxNameLen]; if (!ptszKeyName) { hr = E_OUTOFMEMORY; goto exit; } // Allocate the array of CSPInfo *'s // Add one for our SCP in case someone deleted the reg key g_pSCPs = new CSCPInfo *[dwSubKeys + 1]; if (!g_pSCPs) { hr = E_OUTOFMEMORY; goto exit; } // WARNING: // We are hard coding the loading of the MSSCP as // the first SCP in the system. This will always load // as the first SCP in the array so that our SCP // will always get first dibs on WMA content g_pSCPs[g_wSCPCount] = new CSCPInfo; if (!g_pSCPs[g_wSCPCount]) { hr = E_OUTOFMEMORY; goto exit; } strcpy(szMessage, "Loading MSSCP"); hrLogString(szMessage, S_OK); hr = g_pSCPs[g_wSCPCount]->hrInitialize(MSSCP_PROGID); if (FAILED(hr)) { // If this SCP didn't initialize then we just try the next one. delete g_pSCPs[g_wSCPCount]; } else { // We have added the CSPInfo to the array no inc the counter g_wSCPCount++; } // Loop through the sub-keys initializing a CSPInfo for each sub key lRetVal = ERROR_SUCCESS; while (lRetVal != ERROR_NO_MORE_ITEMS) { dwKeyNameLen = dwMaxNameLen; lRetVal = RegEnumKeyEx(hKey, wIndex, ptszKeyName, &dwKeyNameLen, NULL, NULL, NULL, NULL); if (lRetVal == ERROR_SUCCESS) { lRetVal2 = RegOpenKeyEx(hKey, ptszKeyName, NULL, KEY_QUERY_VALUE, &hSubKey); if (lRetVal2 != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal2); goto exit; } // If this is the MSSCP then skip it because we already loaded it. if (_tcscmp(MSSCP_KEYNAME, ptszKeyName) == 0) { wIndex++; continue; } g_pSCPs[g_wSCPCount] = new CSCPInfo; if (!g_pSCPs[g_wSCPCount]) { hr = E_OUTOFMEMORY; goto exit; } dwDataLen = sizeof(pbData); lRetVal2 = RegQueryValueEx(hSubKey, _T("ProgID"), NULL, &dwType, pbData, &dwDataLen); if (lRetVal2 != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lRetVal2); goto exit; } strcpy(szMessage, "Loading SCP ProgID = "); hr = StringCbCat(szMessage, sizeof(szMessage), (LPTSTR)pbData); if(SUCCEEDED(hr)) { hrLogString(szMessage, S_OK); } hr = g_pSCPs[g_wSCPCount]->hrInitialize(T2W((LPTSTR)pbData)); if (FAILED(hr)) { // If this SCP didn't initialize then we just try the next one. delete g_pSCPs[g_wSCPCount]; } else { // We have added the CSPInfo to the array no inc the counter g_wSCPCount++; } RegCloseKey(hSubKey); hSubKey = NULL; wIndex++; } else if (lRetVal != ERROR_NO_MORE_ITEMS) { hr = HRESULT_FROM_WIN32(lRetVal); goto exit; } } hr = S_OK; exit: if (hKey) RegCloseKey(hKey); if (hSubKey) RegCloseKey(hSubKey); if (ptszKeyName) delete [] ptszKeyName; hrLogDWORD("CMediaDevMgr::hrLoadSCPs returned 0x%08lx", hr, hr); return hr; } // IWMDeviceManager Methods HRESULT CMediaDevMgr::GetRevision(DWORD *pdwRevision) { HRESULT hr; if (g_pAppSCServer) { if(!g_pAppSCServer->fIsAuthenticated()) { hr = WMDM_E_NOTCERTIFIED; goto exit; } } else { hr = E_FAIL; goto exit; } if (!pdwRevision) { hr = E_INVALIDARG; goto exit; } *pdwRevision = SDK_VERSION; hr = S_OK; exit: hrLogDWORD("IWMDeviceManager::GetRevision returned 0x%08lx", hr, hr); return hr; } HRESULT CMediaDevMgr::GetDeviceCount(DWORD *pdwCount) { HRESULT hr; DWORD dwTotalDevCount = 0; DWORD dwDevCount; IMDServiceProvider *pProv = NULL; WORD x; if (g_pAppSCServer) { if(!g_pAppSCServer->fIsAuthenticated()) { hr = WMDM_E_NOTCERTIFIED; goto exit; } } else { hr = E_FAIL; goto exit; } if (!pdwCount) { hr = E_INVALIDARG; goto exit; } for (x=0;xhrGetInterface(&pProv); if (FAILED(hr)) { goto exit; } hr = pProv->GetDeviceCount(&dwDevCount); if (FAILED(hr)) { goto exit; } dwTotalDevCount += dwDevCount; pProv->Release(); pProv = NULL; } *pdwCount = dwTotalDevCount; hr = S_OK; exit: if (pProv) pProv->Release(); hrLogDWORD("IWMDeviceManager::GetDeviceCount returned 0x%08lx", hr, hr); return hr; } HRESULT CMediaDevMgr::EnumDevices(IWMDMEnumDevice **ppEnumDevice) { HRESULT hr; CComObject *pEnumObj; if (g_pAppSCServer) { if(!g_pAppSCServer->fIsAuthenticated()) { hr = WMDM_E_NOTCERTIFIED; goto exit; } } else { hr = E_FAIL; goto exit; } if (!ppEnumDevice) { hr = E_INVALIDARG; goto exit; } hr = CComObject::CreateInstance(&pEnumObj); if (FAILED(hr)) { goto exit; } hr = pEnumObj->QueryInterface(IID_IWMDMEnumDevice, reinterpret_cast(ppEnumDevice)); if (FAILED(hr)) { delete pEnumObj; goto exit; } exit: hrLogDWORD("IWMDeviceManager::EnumDevices returned 0x%08lx", hr, hr); return hr; } // IWMDeviceManager2 Methods HRESULT CMediaDevMgr::GetDeviceFromPnPName( LPCWSTR pwszPnPName, IWMDMDevice** ppDevice ) { return E_NOTIMPL; } HRESULT CMediaDevMgr::SACAuth(DWORD dwProtocolID, DWORD dwPass, BYTE *pbDataIn, DWORD dwDataInLen, BYTE **ppbDataOut, DWORD *pdwDataOutLen) { HRESULT hr; if (g_pAppSCServer) hr = g_pAppSCServer->SACAuth(dwProtocolID, dwPass, pbDataIn, dwDataInLen, ppbDataOut, pdwDataOutLen); else hr = E_FAIL; hrLogDWORD("IComponentAuthenticate::SACAuth returned 0x%08lx", hr, hr); return hr; } HRESULT CMediaDevMgr::SACGetProtocols(DWORD **ppdwProtocols, DWORD *pdwProtocolCount) { HRESULT hr; if (g_pAppSCServer) hr = g_pAppSCServer->SACGetProtocols(ppdwProtocols, pdwProtocolCount); else hr = E_FAIL; hrLogDWORD("IComponentAuthenticate::SACGetProtocols returned 0x%08lx", hr, hr); return hr; } ///////////////////////////////////////////////////////////////////////////// // CMediaDevMgrClassFactory - // // Purpose : THis is used so that the Shell team can use WMDM in the "Both" // threading model while WMP uses us via the Free threading model. This // class factory implementation simply delagates and uses the old class factory // of MediaDevMgr ONLY IF the new CLSID was used to CoCreate WMDM. // STDMETHODIMP CMediaDevMgrClassFactory::CreateInstance(IUnknown * pUnkOuter, REFIID riid, void ** ppvObject) { HRESULT hr = S_OK; CComPtr spClassFactory; hr = _Module.GetClassObject( CLSID_MediaDevMgr, __uuidof(IClassFactory), (LPVOID *)&spClassFactory ); if( SUCCEEDED( hr ) ) { hr = spClassFactory->CreateInstance( pUnkOuter, riid, ppvObject ); } return( hr ); } STDMETHODIMP CMediaDevMgrClassFactory::LockServer(BOOL fLock) { fLock ? _Module.Lock() : _Module.Unlock(); return( S_OK ); }