// MstscMhst.cpp : Implementation of CMstscMhst // Multi host control for TS activeX control. // contains multiple instances of the activeX control. Used by the MMC control // Copyright(C) Microsoft Corporation 2000 // nadima #include "stdafx.h" #include "multihst.h" //Pos/width of sessions that are not active #define X_POS_DISABLED -10 #define Y_POS_DISABLED -10 #define X_WIDTH_DISABLED 5 #define Y_WIDTH_DISABLED 5 ///////////////////////////////////////////////////////////////////////////// // CMstscMhst /* *Function Name:Add * *Parameters: (out) ppMstsc pointer to newly added TS control * *Description: Add's a new TS ActiveX control to the multihost * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::Add(IMsRdpClient** ppMstsc) { if (::IsWindow(m_hWnd)) { CAxWindow* pAxWnd = new CAxWindow(); ATLASSERT(pAxWnd); if (!pAxWnd) { return E_OUTOFMEMORY; } RECT rc; GetClientRect(&rc); // // Window is created invisible and disabled... // Must be made with active client for it to become enabled and visible // if (!pAxWnd->Create( m_hWnd, rc, MSTSC_CONTROL_GUID, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0)) { delete pAxWnd; return E_FAIL; } CComPtr tsClientPtr; if (FAILED(pAxWnd->QueryControl( &tsClientPtr))) { delete pAxWnd; return E_FAIL; } // // Store the pointer to the control // m_coll.push_back( pAxWnd); //If no MSTSC windows are active then make this first //one the active window if (!m_pActiveWindow) { SwitchCurrentActiveClient( pAxWnd); } if (ppMstsc) { // // return the pointer, Detach does not decrement the ref count // so we still hold a reference to the control from the QueryControl // that is the +1 refcount needed to pass the pointer as an out // parameter. // *ppMstsc = (IMsRdpClient*)tsClientPtr.Detach(); } return S_OK; } else { return E_FAIL; } } /* *Function Name:get_Item * *Parameters: (in) Index (index of the item to return) * (out) ppMstsc pointer to the TS control returned * *Description: returns the TS control at a particular index * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::get_Item(long Index, IMsRdpClient** ppMstsc) { if (Index <0 || Index >= m_coll.size()) { ATLASSERT(Index > 0 && Index < m_coll.size()); return E_INVALIDARG; } if (!ppMstsc) { return E_INVALIDARG; } //Return the interface pointer associated //with the AxWindow container CAxWindow* pAxWnd = m_coll[Index]; if (!pAxWnd) { return E_FAIL; } CComPtr tsClientPtr; if (FAILED(pAxWnd->QueryControl( &tsClientPtr))) { delete pAxWnd; return E_FAIL; } // // Return the pointer to the ts control. Detach does not // decrement the AddRef from QueryControl so the refcount is // correctly incremented by one for the out parameter // *ppMstsc = (IMsRdpClient*)tsClientPtr.Detach(); return S_OK; } /* *Function Name:get_Count * *Parameters: (out) pCount * *Description: returns number of items in the collection * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::get_Count(long* pCount) { if (!pCount) { return E_INVALIDARG; } *pCount = m_coll.size(); return S_OK; } /* *Function Name:put_ActiveClientIndex * *Parameters: (in) ClientIndex * *Description: sets the active client by Index * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::put_ActiveClientIndex(long ClientIndex) { if (ClientIndex < 0 || ClientIndex >= m_coll.size()) { return E_INVALIDARG; } CAxWindow* pNewClientWnd = m_coll[ClientIndex]; if (!pNewClientWnd) { return E_FAIL; } if (SwitchCurrentActiveClient(pNewClientWnd)) { m_ActiveClientIndex = ClientIndex; return S_OK; } else { return E_FAIL; } } /* *Function Name:get_ActiveClient * *Parameters: (out) ppMstsc pointer to active client * *Description: returns the ActiveClient * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::get_ActiveClient(IMsRdpClient** ppMstsc) { if (!ppMstsc) { return E_INVALIDARG; } if (!m_pActiveWindow) { *ppMstsc = NULL; return S_OK; } CComPtr tsClientPtr; if (FAILED(m_pActiveWindow->QueryControl( &tsClientPtr))) { return E_FAIL; } // // Detach keeps the +1 ref from QueryControl // *ppMstsc = (IMsRdpClient*)tsClientPtr.Detach(); return S_OK; } /* *Function Name:put_ActiveClient * *Parameters: ppMstsc * *Description: sets the active client given a pointer to * to the client instance * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::put_ActiveClient(IMsRdpClient* ppMstsc) { CAxWindow* pAxWnd = NULL; //find AxWindow that hosts this client //in the collection std::vector::iterator iter; for (iter = m_coll.begin(); iter != m_coll.end(); iter++) { CComPtr tsClientPtr; HRESULT hr = (*iter)->QueryControl( &tsClientPtr); if (FAILED(hr)) { return hr; } if (tsClientPtr == ppMstsc) { pAxWnd = *iter; break; } } if (!pAxWnd) { //We were given a control reference that could not be found return E_INVALIDARG; } if (!SwitchCurrentActiveClient(pAxWnd)) { return E_FAIL; } return S_OK; } /* *Function Name:SwitchCurrentActiveClient * *Parameters: (in) newHostWindow - AxWindow that will become * the active window * *Description: sets the active client given a pointer to * to the client instance * *Returns: success flag * */ BOOL CMstscMhst::SwitchCurrentActiveClient(CAxWindow* newHostWindow) { //Switch the current active client window if (!newHostWindow) { return FALSE; } m_pActiveWindow = newHostWindow; // // Make sure the window is sized properly // RECT rcClient; GetClientRect(&rcClient); m_pActiveWindow->MoveWindow(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); m_pActiveWindow->SetFocus(); // // This window is made the active child window by brining // it to the top of the Z-order of child windows // newHostWindow->BringWindowToTop(); return TRUE; } /* *Function Name:RemoveIndex * *Parameters: ClientIndex * *Description: removes a client by index * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::RemoveIndex(long ClientIndex) { HRESULT hr; CComPtr tsClientPtr; hr = get_Item(ClientIndex, (IMsRdpClient**) (&tsClientPtr)); if (FAILED(hr)) { return hr; } //Pass in interface pointer without addref'ing hr = Remove( (IMsRdpClient*)tsClientPtr); return hr; } /* *Function Name:Remove * *Parameters: (in) ppMsts client to remove * *Description: removes a client from the collection * *Returns: HRESULT * */ STDMETHODIMP CMstscMhst::Remove(IMsRdpClient* ppMstsc) { //Look for the ax window container and if found delete it //also, remove the entry from the collection //find AxWindow that hosts this client CAxWindow* pAxWnd = NULL; std::vector::iterator iter; for (iter = m_coll.begin(); iter != m_coll.end(); iter++) { CComPtr tsClientPtr; HRESULT hr = (*iter)->QueryControl( &tsClientPtr); if (FAILED(hr)) { return hr; } if (tsClientPtr == ppMstsc) { pAxWnd = *iter; break; } } if (!pAxWnd) { //We were given a control reference that could not be found return E_INVALIDARG; } m_coll.erase(iter); return DeleteAxContainerWnd(pAxWnd); } /* *Function Name:DeleteAxContainerWnd * *Parameters: (in) pAxWnd CAxWindow to delete * *Description: deletes an activeX container window * *Returns: HRESULT * */ HRESULT CMstscMhst::DeleteAxContainerWnd(CAxWindow* pAxWnd) { if (!pAxWnd) { return E_FAIL; } if (m_pActiveWindow == pAxWnd) { m_pActiveWindow = NULL; } if (!pAxWnd->DestroyWindow()) { return E_FAIL; } delete pAxWnd; return S_OK; } // // OnCreate Handler // LRESULT CMstscMhst::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ::SetWindowLong(m_hWnd, GWL_STYLE, ::GetWindowLong(m_hWnd, GWL_STYLE) | WS_CLIPCHILDREN); if (!AtlAxWinInit()) { return -1; } return 0; } /* *Function Name:OnDestroy * *Parameters: * *Description: handler for WM_DESTROY * *Returns: * */ LRESULT CMstscMhst::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { m_pActiveWindow = NULL; if (!AtlAxWinTerm()) { return -1; } // // Delete everything in the collection // std::vector::iterator iter; for (iter = m_coll.begin(); iter != m_coll.end(); iter++) { // // This frees any remaining controls // DeleteAxContainerWnd(*iter); } // // Erase the CAxWindow items in the collection // m_coll.erase(m_coll.begin(), m_coll.end()); return 0; } /**PROC+*********************************************************************/ /* Name: OnFrameWindowActivate */ /* */ /* Purpose: Override IOleInPlaceActiveObject::OnFrameWindowActivate */ /* to set the focus on the core container window when the control */ /* gets activated */ /* */ /**PROC-*********************************************************************/ STDMETHODIMP CMstscMhst::OnFrameWindowActivate(BOOL fActivate ) { if (fActivate && IsWindow() && m_pActiveWindow) { m_pActiveWindow->SetFocus(); } return S_OK; } LRESULT CMstscMhst::OnGotFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ATLTRACE("CMstscMhst::OnGotFocus"); if (m_pActiveWindow) { m_pActiveWindow->SetFocus(); } return 0; } LRESULT CMstscMhst::OnLostFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ATLTRACE("CMstscMhst::OnLostFocus"); return 0; } LRESULT CMstscMhst::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { RECT rcClient; if (m_pActiveWindow) { GetClientRect(&rcClient); m_pActiveWindow->MoveWindow(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); } return 0; }