|
|
/********************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name: Channel.cpp
Abstract: This is implementation of IChannel object
Revision History: Steve Shih created 07/15/99
Davide Massarenti rewrote 12/05/2000
********************************************************************/
#include "stdafx.h"
////////////////////////////////////////////////////////////////////////////////
CSAFChannelRecord::CSAFChannelRecord() { }
HRESULT CSAFChannelRecord::GetField( /*[in]*/ SAFREG_Field field, /*[out]*/ BSTR *pVal ) { LPCWSTR szText; WCHAR rgLCID[64];
switch(field) { case SAFREG_SKU : szText = m_ths.GetSKU (); break; case SAFREG_Language : szText = rgLCID; _ltow( m_ths.GetLanguage(), rgLCID, 10 ); break;
case SAFREG_VendorID : szText = m_bstrVendorID; break; case SAFREG_ProductID : szText = m_bstrProductID; break;
case SAFREG_VendorName : szText = m_bstrVendorName; break; case SAFREG_ProductName : szText = m_bstrProductName; break; case SAFREG_ProductDescription: szText = m_bstrDescription; break;
case SAFREG_VendorIcon : szText = m_bstrIcon; break; case SAFREG_SupportUrl : szText = m_bstrURL; break; break; case SAFREG_PublicKey : szText = m_bstrPublicKey; break; case SAFREG_UserAccount : szText = m_bstrUserAccount; break;
case SAFREG_Security : szText = m_bstrSecurity; break; case SAFREG_Notification : szText = m_bstrNotification; break;
default: return E_INVALIDARG; }
return MPC::GetBSTR( szText, pVal ); }
HRESULT CSAFChannelRecord::SetField( /*[in]*/ SAFREG_Field field, /*[in]*/ BSTR newVal ) { CComBSTR* pbstr = NULL;
SANITIZEWSTR( newVal );
switch(field) { case SAFREG_SKU : m_ths.m_strSKU = newVal ; break; case SAFREG_Language : m_ths.m_lLCID = _wtol( newVal ) ; break; case SAFREG_VendorID : pbstr = (CComBSTR*)&m_bstrVendorID ; break; case SAFREG_ProductID : pbstr = (CComBSTR*)&m_bstrProductID ; break; case SAFREG_VendorName : pbstr = (CComBSTR*)&m_bstrVendorName ; break; case SAFREG_ProductName : pbstr = (CComBSTR*)&m_bstrProductName ; break; case SAFREG_ProductDescription: pbstr = (CComBSTR*)&m_bstrDescription ; break; case SAFREG_VendorIcon : pbstr = (CComBSTR*)&m_bstrIcon ; break; case SAFREG_SupportUrl : pbstr = (CComBSTR*)&m_bstrURL ; break; case SAFREG_PublicKey : pbstr = (CComBSTR*)&m_bstrPublicKey ; break; case SAFREG_UserAccount : pbstr = (CComBSTR*)&m_bstrUserAccount ; break; case SAFREG_Security : pbstr = (CComBSTR*)&m_bstrSecurity ; break; case SAFREG_Notification : pbstr = (CComBSTR*)&m_bstrNotification; break;
default: return E_INVALIDARG; }
return pbstr ? MPC::PutBSTR( *pbstr, newVal ) : S_OK; }
////////////////////////////////////////////////////////////////////////////////
CSAFChannel::CSAFChannel() { __HCP_FUNC_ENTRY( "CSAFChannel::CSAFChannel" );
// CSAFChannelRecord m_data;
// CComPtr<IPCHSecurityDescriptor> m_Security;
// List m_lstIncidentItems;
}
void CSAFChannel::FinalRelease() { __HCP_FUNC_ENTRY( "CSAFChannel::FinalRelease" );
Passivate(); }
void CSAFChannel::Passivate() { __HCP_FUNC_ENTRY( "CSAFChannel::Passivate" );
m_Security.Release();
MPC::ReleaseAll( m_lstIncidentItems ); }
/////////////////////////////////////////////////////////////////////////////
HRESULT CSAFChannel::OpenIncidentStore( /*[out]*/ CIncidentStore*& pIStore ) { __HCP_FUNC_ENTRY( "CSAFChannel::OpenIncidentStore" );
HRESULT hr;
__MPC_EXIT_IF_ALLOC_FAILS(hr, pIStore, new CIncidentStore());
__MPC_EXIT_IF_METHOD_FAILS(hr, pIStore->Load());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT CSAFChannel::CloseIncidentStore( /*[out]*/ CIncidentStore*& pIStore ) { __HCP_FUNC_ENTRY( "CSAFChannel::CloseIncidentStore" );
HRESULT hr;
if(pIStore) { (void)pIStore->Save();
delete pIStore; pIStore = NULL; }
hr = S_OK;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
HRESULT CSAFChannel::Init( /*[in]*/ const CSAFChannelRecord& cr ) { __HCP_FUNC_ENTRY( "CSAFChannel::Init" );
HRESULT hr; CIncidentStore* pIStore = NULL;
m_data = cr;
__MPC_EXIT_IF_METHOD_FAILS(hr, OpenIncidentStore( pIStore )); __MPC_EXIT_IF_METHOD_FAILS(hr, pIStore->OpenChannel( this ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
(void)CloseIncidentStore( pIStore );
__HCP_FUNC_EXIT(hr); }
HRESULT CSAFChannel::Import( /*[in]*/ const CSAFIncidentRecord& increc , /*[out]*/ CSAFIncidentItem* *ppItem ) { __HCP_FUNC_ENTRY( "CSAFChannel::Import" );
HRESULT hr; CComObject<CSAFIncidentItem>* pItem = NULL;
__MPC_EXIT_IF_METHOD_FAILS(hr, CreateChild( this, &pItem ));
__MPC_EXIT_IF_METHOD_FAILS(hr, pItem->Import( increc ));
if(ppItem) { (*ppItem = pItem)->AddRef(); }
m_lstIncidentItems.push_back( pItem ); pItem = NULL;
hr = S_OK;
__HCP_FUNC_CLEANUP;
MPC::Release( pItem );
__HCP_FUNC_EXIT(hr); }
HRESULT CSAFChannel::Create( /*[in]*/ BSTR bstrDesc , /*[in]*/ BSTR bstrURL , /*[in]*/ BSTR bstrProgress , /*[in]*/ BSTR bstrXMLDataFile , /*[in]*/ BSTR bstrXMLBlob , /*[out]*/ CSAFIncidentItem* *pVal ) { __HCP_FUNC_ENTRY( "CSAFChannel::Create" );
HRESULT hr; CIncidentStore* pIStore = NULL; CComBSTR bstrOwner;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END();
__MPC_EXIT_IF_METHOD_FAILS(hr, OpenIncidentStore( pIStore ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetCallerPrincipal( /*fImpersonate*/true, bstrOwner ));
__MPC_EXIT_IF_METHOD_FAILS(hr, pIStore->AddRec( this, bstrOwner, bstrDesc, bstrURL, bstrProgress, bstrXMLDataFile, bstrXMLBlob, pVal ));
// Fire an event to the Notification Object (onIncidentAdded)
__MPC_EXIT_IF_METHOD_FAILS(hr, Fire_NotificationEvent( EVENT_INCIDENTADDED, GetSizeIncidentList(), this, *pVal, 0 ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
(void)CloseIncidentStore( pIStore );
__HCP_FUNC_EXIT(hr); }
CSAFChannel::IterConst CSAFChannel::Find( /*[in]*/ BSTR bstrURL ) { IterConst it;
//
// Release all the items.
//
for(it = m_lstIncidentItems.begin(); it != m_lstIncidentItems.end(); it++) { if((*it)->GetURL() == bstrURL) break; }
return it; }
CSAFChannel::IterConst CSAFChannel::Find( /*[in]*/ DWORD dwIndex ) { IterConst it;
//
// Release all the items.
//
for(it = m_lstIncidentItems.begin(); it != m_lstIncidentItems.end(); it++) { if((*it)->GetRecIndex() == dwIndex) break; }
return it; }
/////////////////////////////////////////////////////////////////////////////
// Custom interfaces
STDMETHODIMP CSAFChannel::get_VendorID( /*[out, retval]*/ BSTR *pVal ) { MPC::SmartLock<_ThreadModel> lock( this );
return m_data.GetField( CSAFChannelRecord::SAFREG_VendorID, pVal ); }
STDMETHODIMP CSAFChannel::get_ProductID( /*[out, retval]*/ BSTR *pVal ) { MPC::SmartLock<_ThreadModel> lock( this );
return m_data.GetField( CSAFChannelRecord::SAFREG_ProductID, pVal ); }
STDMETHODIMP CSAFChannel::get_VendorName( /*[out, retval]*/ BSTR *pVal ) { MPC::SmartLock<_ThreadModel> lock( this );
return m_data.GetField( CSAFChannelRecord::SAFREG_VendorName, pVal ); }
STDMETHODIMP CSAFChannel::get_ProductName( /*[out, retval]*/ BSTR *pVal ) { MPC::SmartLock<_ThreadModel> lock( this );
return m_data.GetField( CSAFChannelRecord::SAFREG_ProductName, pVal ); }
STDMETHODIMP CSAFChannel::get_Description( /*[out, retval]*/ BSTR *pVal ) { MPC::SmartLock<_ThreadModel> lock( this );
return m_data.GetField( CSAFChannelRecord::SAFREG_ProductDescription, pVal ); }
STDMETHODIMP CSAFChannel::get_VendorDirectory( /*[out, retval]*/ BSTR *pVal ) { __HCP_FUNC_ENTRY( "CSAFChannel::get_VendorDirectory" );
HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); MPC::wstring strRoot; Taxonomy::LockingHandle handle; Taxonomy::InstalledInstanceIter it; bool fFound;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END();
if(m_data.m_bstrVendorID.Length() == 0) { __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
__MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->GrabControl( handle )); __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->SKU_Find ( m_data.m_ths, fFound, it )); if(!fFound) { __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
strRoot = it->m_inst.m_strSystem; strRoot += HC_HELPSET_SUB_VENDORS L"\\"; MPC::SubstituteEnvVariables( strRoot ); strRoot += m_data.m_bstrVendorID;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetBSTR( strRoot.c_str(), pVal ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CSAFChannel::get_Security( /*[out, retval]*/ IPCHSecurityDescriptor* *pVal ) { __HCP_FUNC_ENTRY( "CSAFChannel::get_Security" );
HRESULT hr;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END();
if(m_data.m_bstrSecurity.Length()) { if(m_Security == NULL) { CPCHSecurityDescriptorDirect sdd;
__MPC_EXIT_IF_METHOD_FAILS(hr, sdd.ConvertFromString( m_data.m_bstrSecurity ));
__MPC_EXIT_IF_METHOD_FAILS(hr, CPCHSecurity::s_GLOBAL->CreateObject_SecurityDescriptor( &m_Security ));
__MPC_EXIT_IF_METHOD_FAILS(hr, sdd.ConvertSDToCOM( m_Security )); }
__MPC_EXIT_IF_METHOD_FAILS(hr, m_Security.CopyTo( pVal )); }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
STDMETHODIMP CSAFChannel::put_Security( /*[in]*/ IPCHSecurityDescriptor* newVal ) { __HCP_FUNC_ENTRY( "CSAFChannel::put_Security" );
HRESULT hr;
m_data.m_bstrSecurity.Empty (); m_Security .Release();
if(newVal) { CPCHSecurityDescriptorDirect sdd;
__MPC_EXIT_IF_METHOD_FAILS(hr, sdd.ConvertSDFromCOM( newVal ));
__MPC_EXIT_IF_METHOD_FAILS(hr, sdd.ConvertToString( &m_data.m_bstrSecurity )); }
//
// Update the SAF store...
//
__MPC_EXIT_IF_METHOD_FAILS(hr, CSAFReg::s_GLOBAL->UpdateField( m_data, CSAFChannelRecord::SAFREG_Security ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CSAFChannel::get_Notification( /*[out, retval]*/ BSTR *pVal ) { MPC::SmartLock<_ThreadModel> lock( this );
return m_data.GetField( CSAFChannelRecord::SAFREG_Notification, pVal ); }
STDMETHODIMP CSAFChannel::put_Notification( /*[in]*/ BSTR newVal ) { __HCP_FUNC_ENTRY( "CSAFChannel::get_Notification" );
HRESULT hr; CLSID clsID; MPC::SmartLock<_ThreadModel> lock( this );
// Lets see if the CLSID is valid, if not return error
if(FAILED(hr = ::CLSIDFromString( newVal, &clsID ))) { DebugLog(L"Not a valid GUID!\r\n"); __MPC_FUNC_LEAVE; }
// Set the CSAFChannel object member
m_data.m_bstrNotification = newVal;
// Place the Notification GUID into the XML SAFReg
__MPC_EXIT_IF_METHOD_FAILS(hr, CSAFReg::s_GLOBAL->UpdateField( m_data, CSAFChannelRecord::SAFREG_Notification ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CSAFChannel::Incidents( /*[in]*/ IncidentCollectionOptionEnum opt , /*[out, retval]*/ IPCHCollection* *ppC ) { __HCP_FUNC_ENTRY( "CSAFChannel::get_Incidents" );
HRESULT hr; IterConst it; CComPtr<CPCHCollection> pColl; MPC::SmartLock<_ThreadModel> lock( this );
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(ppC,NULL); __MPC_PARAMCHECK_END();
// Check the value of "opt" if other than 0,1,2 flag an error
switch(opt) { case pchAllIncidents : break; case pchOpenIncidents : break; case pchClosedIncidents: break; default : __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);// Not a valid Option. Set the error.
}
//
// Create the Enumerator and fill it with items.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pColl ));
for(it = m_lstIncidentItems.begin(); it != m_lstIncidentItems.end(); it++) { CSAFIncidentItem* item = *it;
if(item->MatchEnumOption( opt )) { __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->AddItem( item )); } }
__MPC_EXIT_IF_METHOD_FAILS(hr, pColl.QueryInterface( ppC ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
// The following method needs to be in the IncidentItem ideally.
// First take it out from here.
STDMETHODIMP CSAFChannel::RecordIncident( /*[in]*/ BSTR bstrDisplay , /*[in]*/ BSTR bstrURL , /*[in]*/ VARIANT vProgress , /*[in]*/ VARIANT vXMLDataFile , /*[in]*/ VARIANT vXMLBlob , /*[out]*/ ISAFIncidentItem* *pVal ) { __HCP_FUNC_ENTRY( "CSAFChannel::RecordIncident" );
HRESULT hr; CComPtr<CSAFIncidentItem> pItem; MPC::SmartLock<_ThreadModel> lock( this ); BSTR bstrProgress = (vProgress.vt == VT_BSTR ? vProgress .bstrVal : NULL); BSTR bstrXMLDataFile = (vXMLDataFile.vt == VT_BSTR ? vXMLDataFile.bstrVal : NULL); BSTR bstrXMLBlob = (vXMLBlob.vt == VT_BSTR ? vXMLBlob .bstrVal : NULL);
__MPC_EXIT_IF_METHOD_FAILS(hr, Create( bstrDisplay, bstrURL, bstrProgress, bstrXMLDataFile, bstrXMLBlob, &pItem ));
__MPC_EXIT_IF_METHOD_FAILS(hr, pItem.QueryInterface( pVal ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT CSAFChannel::RemoveIncidentFromList( /*[in]*/ CSAFIncidentItem* pVal ) { __HCP_FUNC_ENTRY( "CSAFChannel::RemoveIncidentFromList" );
HRESULT hr; IterConst it; MPC::SmartLock<_ThreadModel> lock( this );
// Fire an event to the Notification Object (onIncidentAdded)
__MPC_EXIT_IF_METHOD_FAILS(hr, Fire_NotificationEvent( EVENT_INCIDENTREMOVED, GetSizeIncidentList(), this, pVal, 0 ));
it = Find( pVal->GetRecIndex() ); if(it != m_lstIncidentItems.end()) { (*it)->Release();
m_lstIncidentItems.erase( it ); }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
/*
Function CSAFChannel::Fire_Notification
Description This function is used to fire a notification event on the registered notification object. If there is no notification object, this will do nothing.
Parameters:
Depending on the type of Event you want to fire, different parameters must be filled out. The following table shows which are the valid parameters for the call. If a parameter is not valid, it MUST be set to NULL.
iEventType - EVENT_INCIDENTADDED
Valid parameters: - iCountIncidentInChannel - pC - pI
- EVENT_INCIDENTREMOVED
Valid parameters: - iCountIncidentInChannel - pC - pI
- EVENT_INCIDENTUPDATED
Valid parameters: - iCountIncidentInChannel - pC - pI
- EVENT_CHANNELUPDATED
Valid parameters: - iCountIncidentInChannel - pC - dwCode
*/
HRESULT CSAFChannel::Fire_NotificationEvent( int iEventType , int iCountIncidentInChannel , ISAFChannel* pC , ISAFIncidentItem* pI , DWORD dwCode ) { __HCP_FUNC_ENTRY( "CSAFChannel::Fire_NotificationEvent" );
HRESULT hr; PWTS_SESSION_INFO pSessionInfo = NULL; DWORD dwSessions = 0; DWORD dwValidSessions = 0; DWORD dwRetSize = 0;
WINSTATIONINFORMATIONW WSInfo;
CComBSTR bstrCaller;
PSID pSID = NULL; LPCWSTR szDomain = NULL; LPCWSTR szLogin = NULL;
CLSID clsID; ULONG ulRet;
// Check to see if we have a registered Notification Object
if(!m_data.m_bstrNotification || FAILED(::CLSIDFromString( m_data.m_bstrNotification, &clsID ))) { __MPC_SET_ERROR_AND_EXIT(hr, S_OK); }
//
// First lets get the callers Domain and Name by impersonating the caller and grabbing them
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetCallerPrincipal( true, bstrCaller ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SecurityDescriptor::ConvertPrincipalToSID( bstrCaller, pSID ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SecurityDescriptor::ConvertSIDToPrincipal( pSID, &szLogin, &szDomain ));
// Enumerate all sessions on this machine
// -------------------------------------------
// Use WTSEnumerateSessions
// Then find active ones
// Then make the calls to ISAFChannelNotifyIncident
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::WTSEnumerateSessions( WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwSessions ))
// Find the active ones and mark them only if they are the correct user
for(DWORD i = 0; i < dwSessions; i++) { if(pSessionInfo[i].State == WTSActive) // Got an active session
{ CComPtr<IPCHSlaveProcess> sp; CComPtr<IUnknown> unk; CComPtr<ISAFChannelNotifyIncident> chNot;
// Now mark it if the Username and Domain match that of the user
// we are calling for.
memset( &WSInfo, 0, sizeof(WSInfo) );
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::WinStationQueryInformationW( SERVERNAME_CURRENT , pSessionInfo[i].SessionId , WinStationInformation , &WSInfo , sizeof(WSInfo) , &dwRetSize ));
// Now we can fish the userid and domain out of the WSInfo.Domain and WSInfo.UserName
// Now we are ready to compare the domain and username
if((wcscmp( WSInfo.Domain , szDomain ) == 0) && (wcscmp( WSInfo.UserName, szLogin ) == 0) ) { WINSTATIONUSERTOKEN WsUserToken;
// We found the correct sessions, make the calls to ISAFChannelNotifyIncident
WsUserToken.ProcessId = LongToHandle( GetCurrentProcessId() ); WsUserToken.ThreadId = LongToHandle( GetCurrentThreadId () );
// Grab token from SessionID
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::WinStationQueryInformationW( WTS_CURRENT_SERVER_HANDLE , pSessionInfo[i].SessionId , WinStationUserToken , &WsUserToken , sizeof(WsUserToken) , &ulRet ));
// Create the notification object in the session (using the hToken
{ CPCHUserProcess::UserEntry ue;
__MPC_EXIT_IF_METHOD_FAILS(hr, ue.InitializeForImpersonation( WsUserToken.UserToken ));
__MPC_EXIT_IF_METHOD_FAILS(hr, CPCHUserProcess::s_GLOBAL->Connect( ue, &sp )); }
//
// Discard all the failures from the remote objects.
//
////////////////////////////////////////////////////////////////////////////////
// Use the Slave Process to Create the object which CLSID clsID.
if(FAILED(hr = sp->CreateInstance( clsID, NULL, &unk ))) { continue; }
// Grab a pointer to the correct interface
if(FAILED(hr = unk.QueryInterface( &chNot ))) { continue; }
// Depending on the type of notification, call the correct event callback
switch(iEventType) { case EVENT_INCIDENTADDED : hr = chNot->onIncidentAdded ( pC, pI , iCountIncidentInChannel ); break; case EVENT_INCIDENTREMOVED: hr = chNot->onIncidentRemoved( pC, pI , iCountIncidentInChannel ); break; case EVENT_INCIDENTUPDATED: hr = chNot->onIncidentUpdated( pC, pI , iCountIncidentInChannel ); break; case EVENT_CHANNELUPDATED : hr = chNot->onChannelUpdated ( pC, dwCode, iCountIncidentInChannel ); break; } if(FAILED(hr)) { continue; } } } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
MPC::SecurityDescriptor::ReleaseMemory( (void *&)pSID ); MPC::SecurityDescriptor::ReleaseMemory( (void *&)szLogin ); MPC::SecurityDescriptor::ReleaseMemory( (void *&)szDomain );
__HCP_FUNC_EXIT(hr); }
|