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.
534 lines
12 KiB
534 lines
12 KiB
// 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<IMsRdpClient> 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<IMsRdpClient> 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<IMsRdpClient> 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<CAxWindow*>::iterator iter;
|
|
for (iter = m_coll.begin(); iter != m_coll.end(); iter++)
|
|
{
|
|
CComPtr<IMsRdpClient> 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<IMsRdpClient> 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<CAxWindow*>::iterator iter;
|
|
for (iter = m_coll.begin(); iter != m_coll.end(); iter++)
|
|
{
|
|
CComPtr<IMsRdpClient> 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<CAxWindow*>::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;
|
|
}
|