You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
617 lines
15 KiB
617 lines
15 KiB
// 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;iIndex<g_wSPCount;iIndex++)
|
|
delete g_pSPs[iIndex];
|
|
delete g_pSPs;
|
|
g_pSPs = NULL;
|
|
g_wSPCount = 0;
|
|
}
|
|
if( g_pSCPs )
|
|
{
|
|
for(iIndex=0;iIndex<g_wSCPCount;iIndex++)
|
|
delete g_pSCPs[iIndex];
|
|
delete g_pSCPs;
|
|
g_pSCPs = NULL;
|
|
g_wSCPCount = 0;
|
|
}
|
|
if( g_pAppSCServer )
|
|
{
|
|
delete g_pAppSCServer;
|
|
g_pAppSCServer = NULL;
|
|
}
|
|
}
|
|
csGlobal.Unlock();
|
|
}
|
|
|
|
|
|
CMediaDevMgr::CMediaDevMgr()
|
|
{
|
|
// Add a refcount to SPs, SCPs
|
|
GlobalAddRef();
|
|
|
|
g_pAppSCServer = new CSecureChannelServer();
|
|
if (g_pAppSCServer)
|
|
{
|
|
g_pAppSCServer->SetCertificate(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;x<g_wSPCount;x++)
|
|
{
|
|
hr = g_pSPs[x]->hrGetInterface(&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<CWMDMDeviceEnum> *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<CWMDMDeviceEnum>::CreateInstance(&pEnumObj);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
hr = pEnumObj->QueryInterface(IID_IWMDMEnumDevice, reinterpret_cast<void**>(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<IClassFactory> 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 );
|
|
}
|