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.
3941 lines
120 KiB
3941 lines
120 KiB
/**MOD+**********************************************************************/
|
|
/* Module: mstscax.cpp */
|
|
/* */
|
|
/* Class : CMsTscAx */
|
|
/* */
|
|
/* Purpose: RDP ActiveX control */
|
|
/* */
|
|
/* Copyright(C) Microsoft Corporation 1999-2001 */
|
|
/* */
|
|
/* Author : Nadim Abdo (nadima) */
|
|
/****************************************************************************/
|
|
#include "stdafx.h"
|
|
#include "atlwarn.h"
|
|
|
|
//Header generated from IDL
|
|
#include "mstsax.h"
|
|
|
|
#include "mstscax.h"
|
|
#include "vchannel.h"
|
|
#include "cleanup.h"
|
|
|
|
//
|
|
// TS Disconnection errors
|
|
//
|
|
#include "tscerrs.h"
|
|
|
|
//Advanced settings object
|
|
#include "advset.h"
|
|
//Debugger object
|
|
#include "tsdbg.h"
|
|
//Secured settings object
|
|
#include "securedset.h"
|
|
|
|
#include "securdlg.h"
|
|
#include "arcmgr.h"
|
|
|
|
//
|
|
// Version number (property returns this)
|
|
//
|
|
#ifndef OS_WINCE
|
|
#include "ntverp.h"
|
|
#endif
|
|
|
|
#ifdef OS_WINCE
|
|
extern "C" HWND ghwndClip;
|
|
#endif
|
|
|
|
#define TRC_GROUP TRC_GROUP_UI
|
|
#define TRC_FILE "mstscax"
|
|
#include <atrcapi.h>
|
|
|
|
//5 min timeout (it's this long mainly for stress)
|
|
#define CORE_INIT_TIMEOUT 300000
|
|
|
|
int g_lockCount = 0;
|
|
DWORD g_dwControlDbgStatus = 0;
|
|
|
|
#define CONTROL_DBG_COREINIT_TIMEOUT 0x1
|
|
#define CONTROL_DBG_COREINIT_ERROR 0x2
|
|
|
|
//
|
|
// Global pointer exposed to make debugging easier
|
|
// DO NOT USE for anything else
|
|
//
|
|
CMsTscAx* g_pMsTscAx = NULL;
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: CMsTscAx::CMsTscAx */
|
|
/* */
|
|
/* Purpose: Constructor */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
CMsTscAx::CMsTscAx()
|
|
{
|
|
g_pMsTscAx = this;
|
|
|
|
m_bWindowOnly = TRUE;
|
|
m_bPendConReq = FALSE;
|
|
_ConnectionState = tscNotConnected;
|
|
|
|
m_bStartConnected = FALSE;
|
|
ResetNonPortablePassword();
|
|
ResetPortablePassword();
|
|
|
|
//
|
|
// Client width and height default to 0 which means get the size
|
|
// from the control container.
|
|
//
|
|
m_DesktopWidth = 0;
|
|
m_DesktopHeight = 0;
|
|
|
|
m_fRequestFullScreen = FALSE;
|
|
|
|
//
|
|
// This allocation is checked in FinalConstruct
|
|
//
|
|
m_pUI = new CUI();
|
|
if(m_pUI) {
|
|
m_pUI->UI_ResetState();
|
|
}
|
|
else {
|
|
ATLTRACE("Mem alloc for m_pUI failed");
|
|
}
|
|
|
|
memset(m_szDisconnectedText,0,sizeof(m_szDisconnectedText));
|
|
memset(m_szConnectingText,0,sizeof(m_szConnectingText));
|
|
memset(m_szConnectedText,0,sizeof(m_szConnectedText));
|
|
|
|
#ifdef DC_DEBUG
|
|
//
|
|
// Initial value of status messages ONLY used in debug
|
|
// builds. Don't need to localize
|
|
//
|
|
StringCchCopy(m_szDisconnectedText, SIZE_TCHARS(m_szDisconnectedText),
|
|
_T("Server Disconnected...."));
|
|
StringCchCopy(m_szConnectingText, SIZE_TCHARS(m_szConnectingText),
|
|
_T("Connecting to Server...."));
|
|
StringCchCopy(m_szConnectedText, SIZE_TCHARS(m_szConnectedText),
|
|
_T("Connected to Server."));
|
|
#endif
|
|
|
|
m_lpStatusDisplay = m_szDisconnectedText;
|
|
|
|
_arcManager.SetParent(this);
|
|
|
|
m_pAdvancedSettingsObj = NULL;
|
|
m_pDebuggerObj = NULL;
|
|
m_pSecuredSettingsObj = NULL;
|
|
m_bCoreInit = FALSE;
|
|
m_fInControlLock = FALSE;
|
|
m_iDestroyCount = 0;
|
|
m_IsLongPassword = FALSE;
|
|
|
|
m_ConnectionMode = CONNECTIONMODE_INITIATE;
|
|
m_SalemConnectedSocket = INVALID_SOCKET;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: Destructor */
|
|
/* */
|
|
/* Purpose: Close the active session, if any , is existing. */
|
|
/* being activated. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
CMsTscAx::~CMsTscAx()
|
|
{
|
|
//Lifetime of the Advanced settings object is coupled to the control
|
|
if(m_pAdvancedSettingsObj)
|
|
{
|
|
m_pAdvancedSettingsObj->Release();
|
|
}
|
|
|
|
if(m_pDebuggerObj)
|
|
{
|
|
m_pDebuggerObj->Release();
|
|
}
|
|
|
|
if(m_pSecuredSettingsObj)
|
|
{
|
|
m_pSecuredSettingsObj->Release();
|
|
}
|
|
|
|
_arcManager.SetParent(NULL);
|
|
|
|
m_pAdvancedSettingsObj = NULL;
|
|
m_pDebuggerObj = NULL;
|
|
m_pSecuredSettingsObj = NULL;
|
|
delete m_pUI;
|
|
}
|
|
|
|
//
|
|
// Final construct handler
|
|
//
|
|
// Called just before control is fully constructed.
|
|
//
|
|
// Do error checking here that we can't do in the ctor
|
|
//
|
|
HRESULT
|
|
CMsTscAx::FinalConstruct()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DC_BEGIN_FN("FinalConstruct");
|
|
|
|
if (NULL == m_pUI) {
|
|
TRC_ERR((TB,_T("m_pUI allocation failed, fail finalconstruct")));
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: put_Server */
|
|
/* */
|
|
/* Purpose: Server property input function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::put_Server(BSTR newVal)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
BOOL fServerNameChanged = FALSE;
|
|
HRESULT hr;
|
|
DC_BEGIN_FN("put_Server");
|
|
|
|
if (!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Error, property call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
#ifdef ECP_TIMEBOMB
|
|
if(!CheckTimeBomb())
|
|
{
|
|
//
|
|
// Timebomb failed, bail out with an error message
|
|
//
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
#endif
|
|
|
|
if (newVal)
|
|
{
|
|
//
|
|
// Server name is always ansi
|
|
//
|
|
LPTSTR serverName = (LPTSTR)(newVal);
|
|
|
|
//
|
|
// Allow null server names to be set
|
|
// because environments like VB will initialise
|
|
// the property to NULL at load time from the
|
|
// peristence info. We validate again at connect time
|
|
// and that ensures that the user doesn't connect
|
|
// with a null server name.
|
|
//
|
|
if (*serverName)
|
|
{
|
|
//
|
|
// Validate server name
|
|
//
|
|
if(!CUT::ValidateServerName(serverName,
|
|
FALSE)) //don't accept [:port]
|
|
{
|
|
TRC_ERR((TB,_T("Invalid server name")));
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
if(_tcslen(serverName) < UT_MAX_ADDRESS_LENGTH)
|
|
{
|
|
//
|
|
// If the server we are setting is different
|
|
// than the previous one then nuke any autoreconnect
|
|
// information.
|
|
//
|
|
TCHAR szPrevServer[UT_MAX_ADDRESS_LENGTH];
|
|
hr = m_pUI->UI_GetServerName(szPrevServer,
|
|
SIZE_TCHARS(szPrevServer));
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
if (_tcscmp(serverName, szPrevServer)) {
|
|
fServerNameChanged = TRUE;
|
|
}
|
|
hr = m_pUI->UI_SetServerName(serverName);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
}
|
|
else {
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pUI->UI_SetServerName( _T(""));
|
|
fServerNameChanged = TRUE;
|
|
}
|
|
|
|
if (fServerNameChanged) {
|
|
//We are setting a new server name
|
|
//clear and free autoreconnect cookies
|
|
m_pUI->UI_SetAutoReconnectCookie(NULL, 0);
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_Server */
|
|
/* */
|
|
/* Purpose: Server property get function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_Server(BSTR* pServer)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pServer);
|
|
if(!pServer)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
OLECHAR* wszServer = (OLECHAR*)m_pUI->_UI.strAddress;
|
|
*pServer = SysAllocString(wszServer);
|
|
if(!*pServer) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: put_Domain */
|
|
/* */
|
|
/* Purpose: Domain property input function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::put_Domain(BSTR newVal)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
USES_CONVERSION;
|
|
DC_BEGIN_FN("put_Domain");
|
|
|
|
if(!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Error, property call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (newVal)
|
|
{
|
|
PDCWCHAR wszDomain = (PDCWCHAR)(newVal);
|
|
if (wcslen(wszDomain) < UI_MAX_DOMAIN_LENGTH) {
|
|
hr = m_pUI->UI_SetDomain(wszDomain);
|
|
DC_QUIT;
|
|
}
|
|
else {
|
|
hr = E_INVALIDARG;
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pUI->UI_SetDomain(L"");
|
|
hr = S_OK;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
DC_EXIT_POINT:
|
|
return hr;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_Domain */
|
|
/* */
|
|
/* Purpose: Domain property get function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_Domain(BSTR* pDomain)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pDomain);
|
|
if(!pDomain)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pDomain = SysAllocString(m_pUI->_UI.Domain);
|
|
if(!*pDomain)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: put_UserName */
|
|
/* */
|
|
/* Purpose: UserName property input function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::put_UserName(BSTR newVal)
|
|
{
|
|
USES_CONVERSION;
|
|
DC_BEGIN_FN("put_UserName");
|
|
|
|
if (!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Error, property call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
if (newVal)
|
|
{
|
|
PDCWCHAR szUserName = OLE2W(newVal);
|
|
if(!szUserName)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if(wcslen(szUserName) < UI_MAX_USERNAME_LENGTH)
|
|
{
|
|
m_pUI->UI_SetUserName(szUserName);
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pUI->UI_SetUserName(L"");
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_UserName */
|
|
/* */
|
|
/* Purpose: UserName property get function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_UserName(BSTR* pUserName)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pUserName);
|
|
if(!pUserName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pUserName = SysAllocString(m_pUI->_UI.UserName);
|
|
if(!*pUserName)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Properties for disconnected status text
|
|
//
|
|
STDMETHODIMP CMsTscAx::put_DisconnectedText(/*[in]*/ BSTR newVal)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
if (newVal) {
|
|
LPTSTR szDisc = OLE2T(newVal);
|
|
|
|
if (szDisc) {
|
|
|
|
hr = CUT::StringPropPut(
|
|
m_szDisconnectedText,
|
|
SIZE_TCHARS(m_szDisconnectedText),
|
|
szDisc);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
UpdateStatusText(m_lpStatusDisplay);
|
|
return S_OK;
|
|
}
|
|
else {
|
|
return hr;
|
|
}
|
|
}
|
|
else {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
}
|
|
else {
|
|
m_szDisconnectedText[0] = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CMsTscAx::get_DisconnectedText(/*[out]*/BSTR* pDisconnectedText)
|
|
{
|
|
USES_CONVERSION;
|
|
if(pDisconnectedText)
|
|
{
|
|
OLECHAR* wszDiscon = (OLECHAR*)m_szDisconnectedText;
|
|
if (wszDiscon)
|
|
{
|
|
*pDisconnectedText = SysAllocString(wszDiscon);
|
|
if (*pDisconnectedText) {
|
|
return S_OK;
|
|
}
|
|
else {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else {
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Properties for connecting status text
|
|
//
|
|
|
|
STDMETHODIMP CMsTscAx::put_ConnectingText(/*[in]*/ BSTR newVal)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
if (newVal) {
|
|
LPTSTR szConnecting = OLE2T(newVal);
|
|
if(szConnecting) {
|
|
hr = CUT::StringPropPut(
|
|
m_szConnectingText,
|
|
SIZE_TCHARS(m_szConnectingText),
|
|
szConnecting);
|
|
if (SUCCEEDED(hr)) {
|
|
UpdateStatusText(m_lpStatusDisplay);
|
|
return S_OK;
|
|
}
|
|
else {
|
|
return hr;
|
|
}
|
|
}
|
|
else {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_szConnectingText[0] = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CMsTscAx::get_ConnectingText(/*[out]*/BSTR* pConnectingText)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pConnectingText);
|
|
if(pConnectingText)
|
|
{
|
|
OLECHAR* wszCon = (OLECHAR*)m_szConnectingText;
|
|
if(wszCon)
|
|
{
|
|
*pConnectingText = SysAllocString(wszCon);
|
|
if(*pConnectingText)
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//
|
|
// put_ConnectedStatusText - set text for connected display
|
|
//
|
|
STDMETHODIMP CMsTscAx::put_ConnectedStatusText(/*[in]*/ BSTR newVal)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
if(newVal)
|
|
{
|
|
LPTSTR szText = OLE2T(newVal);
|
|
if(szText) {
|
|
hr = CUT::StringPropPut(
|
|
m_szConnectedText,
|
|
SIZE_TCHARS(m_szConnectedText),
|
|
szText);
|
|
if (SUCCEEDED(hr)) {
|
|
UpdateStatusText(m_lpStatusDisplay);
|
|
return S_OK;
|
|
}
|
|
else {
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_szConnectedText[0] = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// get_ConnectedStatusText - get text for connected display
|
|
//
|
|
STDMETHODIMP CMsTscAx::get_ConnectedStatusText(/*[out]*/BSTR* pConnectedText)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pConnectedText);
|
|
if(pConnectedText)
|
|
{
|
|
OLECHAR* wszCon = (OLECHAR*)m_szConnectedText;
|
|
if(wszCon)
|
|
{
|
|
*pConnectedText = SysAllocString(wszCon);
|
|
if(*pConnectedText)
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: internal_PutStartProgram */
|
|
/* */
|
|
/* Purpose: Alternate shell property input function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::internal_PutStartProgram(BSTR newVal)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
DC_BEGIN_FN("internal_PutStartProgram");
|
|
|
|
if(!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Error, property call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (newVal) {
|
|
PDCWCHAR szStartProg = OLE2W(newVal);
|
|
if(!szStartProg) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (wcslen(szStartProg) < MAX_PATH) {
|
|
hr = m_pUI->UI_SetAlternateShell(szStartProg);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
}
|
|
else {
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
else {
|
|
m_pUI->UI_SetAlternateShell(L"");
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: internal_GetStartProgram */
|
|
/* */
|
|
/* Purpose: StartProgram property get function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::internal_GetStartProgram(BSTR* pStartProgram)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pStartProgram);
|
|
if(!pStartProgram)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pStartProgram = SysAllocString(m_pUI->_UI.AlternateShell);
|
|
if(!*pStartProgram)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: internal_PutWorkDir */
|
|
/* */
|
|
/* Purpose: Working Directory property input function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::internal_PutWorkDir(BSTR newVal)
|
|
{
|
|
HRESULT hr;
|
|
USES_CONVERSION;
|
|
DC_BEGIN_FN("internal_PutWorkDir");
|
|
|
|
if(!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Error, property call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (newVal)
|
|
{
|
|
PDCWCHAR szWorkDir = OLE2W(newVal);
|
|
if(!szWorkDir)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if(wcslen(szWorkDir) < MAX_PATH)
|
|
{
|
|
hr = m_pUI->UI_SetWorkingDir(szWorkDir);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pUI->UI_SetWorkingDir(L"");
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: internal_GetWorkDir */
|
|
/* */
|
|
/* Purpose: Working Directory property get function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::internal_GetWorkDir(BSTR* pWorkDir)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pWorkDir);
|
|
if(!pWorkDir)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pWorkDir = SysAllocString(m_pUI->_UI.WorkingDir);
|
|
if(!*pWorkDir)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: CreateVirtualChannels */
|
|
/* */
|
|
/* Purpose: Define virtual channels that will be created given a CSV list */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
#define MAX_CHANNEL_LIST_LEN (30*10)
|
|
STDMETHODIMP CMsTscAx::CreateVirtualChannels(/*[in]*/ BSTR newChanList)
|
|
{
|
|
DC_BEGIN_FN("CreateVirtualChannels");
|
|
|
|
USES_CONVERSION;
|
|
char* pszaChannelNames = NULL;
|
|
char* pszaChannelNamesCopy= NULL;
|
|
PDCACHAR token;
|
|
DCUINT uChanCount = 0;
|
|
HRESULT hr = E_FAIL;
|
|
UINT cbChannelNames;
|
|
|
|
if (!IsControlDisconnected()) {
|
|
TRC_ERR((TB,_T("Can't call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(m_pUI->_UI.hwndMain || !newChanList)
|
|
{
|
|
//
|
|
// Error, can only Setup virtual channels before UI is initialised
|
|
//
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (_VChans._ChanCount) {
|
|
//
|
|
// Error can only setup channels once
|
|
//
|
|
TRC_ERR((TB,_T("Error channels already setup: 0x%x"),
|
|
_VChans._ChanCount));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Protect ourselves by refusing to process channel lists that
|
|
// are too long
|
|
//
|
|
if (_tcslen(newChanList) >= MAX_CHANNEL_LIST_LEN) {
|
|
TRC_ERR((TB,_T("Channel list too long")));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Channel names have to be ANSI. Do the conversion safely guarded
|
|
// by a try/except block.
|
|
//
|
|
__try {
|
|
pszaChannelNames = OLE2A(newChanList);
|
|
}
|
|
__except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH) {
|
|
_resetstkoflw();
|
|
pszaChannelNames = NULL;
|
|
}
|
|
|
|
if(!pszaChannelNames)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
cbChannelNames = DC_ASTRLEN(pszaChannelNames) + 1;
|
|
pszaChannelNamesCopy = new DCACHAR[cbChannelNames];
|
|
if (!pszaChannelNamesCopy)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
hr = StringCbCopyA(pszaChannelNamesCopy, cbChannelNames, pszaChannelNames);
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB,_T("StringCchCopyA for chan names failed: 0x%x"), hr));
|
|
DC_QUIT;
|
|
}
|
|
|
|
|
|
//
|
|
// Two passes through the channel names
|
|
// 1) to validate and count the number of channels
|
|
// 2) to create a CHANINFO data structure for each channel
|
|
//
|
|
|
|
token = DC_ASTRTOK( pszaChannelNamesCopy, ",");
|
|
//
|
|
// Get comma separated channel names
|
|
//
|
|
while (token)
|
|
{
|
|
uChanCount++;
|
|
token = DC_ASTRTOK(NULL, ",");
|
|
if(token && (strlen(token) > CHANNEL_NAME_LEN))
|
|
{
|
|
#ifdef UNICODE
|
|
TRC_ERR((TB,_T("Channel name too long: %S"),token));
|
|
#else
|
|
TRC_ERR((TB,_T("Channel name too long: %s"),token));
|
|
#endif
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
if(!uChanCount)
|
|
{
|
|
//
|
|
// No channels specified
|
|
//
|
|
hr = E_INVALIDARG;
|
|
DC_QUIT;
|
|
}
|
|
|
|
_VChans._pChanInfo = (PCHANINFO) LocalAlloc(LPTR,
|
|
sizeof(CHANINFO) * uChanCount);
|
|
if (_VChans._pChanInfo == NULL) {
|
|
TRC_DBG((TB,_T("mstscax: LocalAlloc failed\n")));
|
|
hr = E_OUTOFMEMORY;
|
|
DC_QUIT;
|
|
}
|
|
_VChans._ChanCount = uChanCount;
|
|
|
|
//
|
|
// Initialize the chan info data structures
|
|
//
|
|
int i = 0;
|
|
token = DC_ASTRTOK( pszaChannelNames, ",");
|
|
while (token)
|
|
{
|
|
hr = StringCbCopyA(_VChans._pChanInfo[i].chanName,
|
|
sizeof(_VChans._pChanInfo[i].chanName),
|
|
token);
|
|
if (SUCCEEDED(hr)) {
|
|
_VChans._pChanInfo[i].dwOpenHandle = 0;
|
|
|
|
_VChans._pChanInfo[i].CurrentlyReceivingData.chanDataState =
|
|
dataIncompleteAssemblingChunks;
|
|
_VChans._pChanInfo[i].CurrentlyReceivingData.dwDataLen = 0;
|
|
_VChans._pChanInfo[i].CurrentlyReceivingData.pData = NULL;
|
|
_VChans._pChanInfo[i].fIsValidChannel = FALSE;
|
|
_VChans._pChanInfo[i].channelOptions = 0;
|
|
|
|
_VChans._pChanInfo[i].fIsOpen = FALSE;
|
|
token = DC_ASTRTOK(NULL, ",");
|
|
i++;
|
|
}
|
|
else {
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
if (FAILED(hr)) {
|
|
if (_VChans._pChanInfo) {
|
|
LocalFree(_VChans._pChanInfo);
|
|
_VChans._pChanInfo = NULL;
|
|
}
|
|
_VChans._ChanCount = 0;
|
|
}
|
|
|
|
if (pszaChannelNamesCopy) {
|
|
delete [] pszaChannelNamesCopy;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: SendOnVirtualChannel */
|
|
/* */
|
|
/* Purpose: SendData on a virtual channel */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::SendOnVirtualChannel(/*[in]*/ BSTR ChanName,/*[in]*/ BSTR sendData)
|
|
{
|
|
USES_CONVERSION;
|
|
DCUINT chanIndex = -1;
|
|
HRESULT hr = S_OK;
|
|
LPVOID pData;
|
|
DWORD dataLength;
|
|
LPSTR pszaChanName = NULL;
|
|
|
|
DC_BEGIN_FN("SendOnVirtualChannel");
|
|
|
|
if(!ChanName || !sendData)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Validate against channel names that are too long
|
|
//
|
|
if (_tcslen(ChanName) > CHANNEL_NAME_LEN) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// Channel names have to be ANSI. Do the conversion safely guarded
|
|
// by a try/except block.
|
|
//
|
|
__try {
|
|
pszaChanName = OLE2A(ChanName);
|
|
}
|
|
__except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH) {
|
|
_resetstkoflw();
|
|
pszaChanName = NULL;
|
|
}
|
|
|
|
TRC_ASSERT((pszaChanName), (TB,_T("pszaChanName is NULL")));
|
|
if (!pszaChanName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
chanIndex = _VChans.ChannelIndexFromName(pszaChanName);
|
|
|
|
if (chanIndex >= _VChans._ChanCount)
|
|
{
|
|
TRC_DBG((TB,_T("chanIndex out of range\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
// Allocate send data buffer. Send buffer will be freed by SendDataOnChannel
|
|
dataLength = SysStringByteLen(sendData);
|
|
pData = LocalAlloc(LPTR, dataLength);
|
|
|
|
if(!pData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
DC_MEMCPY(pData, sendData, dataLength);
|
|
|
|
//
|
|
// Send the data on of the web control's virtual channels
|
|
//
|
|
if(!_VChans.SendDataOnChannel( chanIndex, pData, dataLength))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: SetVirtualChannelOptions */
|
|
/* */
|
|
/* Purpose: Sets virtual channel options */
|
|
/* Should be called after the CreateVirtualChannels call and */
|
|
/* before a connection is established */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::SetVirtualChannelOptions(/*[in]*/ BSTR ChanName,
|
|
/*[in]*/ LONG chanOptions)
|
|
{
|
|
USES_CONVERSION;
|
|
UINT chanIndex = -1;
|
|
LPSTR pszaChanName = NULL;
|
|
|
|
DC_BEGIN_FN("SetVirtualChannelOptions");
|
|
|
|
|
|
if(!ChanName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if(!IsControlDisconnected())
|
|
{
|
|
//Can't call while connected
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(_VChans.HasEntryBeenCalled())
|
|
{
|
|
TRC_ERR((TB,_T("Can't set VC options after VC's have been initialized")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Validate against channel names that are too long
|
|
//
|
|
if (_tcslen(ChanName) > CHANNEL_NAME_LEN) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Channel names have to be ANSI. Do the conversion safely guarded
|
|
// by a try/except block.
|
|
//
|
|
__try {
|
|
pszaChanName = OLE2A(ChanName);
|
|
}
|
|
__except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH) {
|
|
_resetstkoflw();
|
|
pszaChanName = NULL;
|
|
}
|
|
|
|
|
|
TRC_ASSERT((pszaChanName), (TB,_T("pszaChanName is NULL")));
|
|
if(!pszaChanName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
chanIndex = _VChans.ChannelIndexFromName(pszaChanName);
|
|
if (chanIndex >= _VChans._ChanCount)
|
|
{
|
|
TRC_DBG((TB,_T("chanIndex out of range %d\n"), chanIndex));
|
|
return E_FAIL;
|
|
}
|
|
|
|
_VChans._pChanInfo[chanIndex].channelOptions = chanOptions;
|
|
TRC_NRM((TB,_T("Set VC options to %d"),
|
|
_VChans._pChanInfo[chanIndex].channelOptions));
|
|
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: GetVirtualChannelOptions */
|
|
/* */
|
|
/* Purpose: retreives virtual channel options */
|
|
/* Should be called after the CreateVirtualChannels call for */
|
|
/* the channel in question. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::GetVirtualChannelOptions(/*[in]*/ BSTR ChanName,
|
|
/*[out]*/LONG* pChanOptions)
|
|
{
|
|
USES_CONVERSION;
|
|
UINT chanIndex = -1;
|
|
LPSTR pszaChanName = NULL;
|
|
|
|
DC_BEGIN_FN("SetVirtualChannelOptions");
|
|
|
|
|
|
if(!ChanName || !pChanOptions)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Validate against channel names that are too long
|
|
//
|
|
if (_tcslen(ChanName) > CHANNEL_NAME_LEN) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Channel names have to be ANSI. Do the conversion safely guarded
|
|
// by a try/except block.
|
|
//
|
|
__try {
|
|
pszaChanName = OLE2A(ChanName);
|
|
}
|
|
__except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH) {
|
|
_resetstkoflw();
|
|
pszaChanName = NULL;
|
|
}
|
|
|
|
TRC_ASSERT((pszaChanName), (TB,_T("pszaChanName is NULL")));
|
|
if(!pszaChanName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
chanIndex = _VChans.ChannelIndexFromName(pszaChanName);
|
|
if (chanIndex >= _VChans._ChanCount)
|
|
{
|
|
TRC_DBG((TB,_T("chanIndex out of range %d\n"), chanIndex));
|
|
return E_FAIL;
|
|
}
|
|
|
|
*pChanOptions = _VChans._pChanInfo[chanIndex].channelOptions;
|
|
|
|
TRC_NRM((TB,_T("Retreived VC options for chan %S = %d"),
|
|
pszaChanName,
|
|
_VChans._pChanInfo[chanIndex].channelOptions));
|
|
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// Request a graceful shutdown of the control and correspondingly
|
|
// the user's session (this does _NOT_ shutdown the server).
|
|
//
|
|
// Params: pCloseStatus (OUT parameter)
|
|
//
|
|
// controlCloseCanProceed - container can go ahead with close immediately
|
|
// happens if we're not connected
|
|
// controlCloseWaitForEvents- container should wait for events as described
|
|
// below
|
|
//
|
|
// OnDisconnected:
|
|
// App can proceed with the close by destroying all windows (DestroyWindow)
|
|
//
|
|
// OnConfirmClose:
|
|
// In the case where the user has a logged in session the
|
|
// control will fire OnConfirmClose in which case the container
|
|
// can pop UI asking the user if they really want to close the application
|
|
// if they say the app can then DestoryAllWindows
|
|
//
|
|
// NOTE: this method exists so a shell can present the same behaviour as
|
|
// the 2195 client (because internally the client sends a
|
|
// shutdownrequest PDU in this case).
|
|
//
|
|
// Returns success hr flag if the close request was successfully
|
|
// dispatched
|
|
//
|
|
//
|
|
STDMETHODIMP CMsTscAx::RequestClose(ControlCloseStatus* pCloseStatus)
|
|
{
|
|
DC_BEGIN_FN("RequestClose");
|
|
|
|
if(pCloseStatus)
|
|
{
|
|
if(m_bCoreInit && !IsControlDisconnected() && m_pUI)
|
|
{
|
|
//
|
|
// Dispatch a close request to the core
|
|
//
|
|
if(m_pUI->UI_UserRequestedClose())
|
|
{
|
|
*pCloseStatus = controlCloseWaitForEvents;
|
|
}
|
|
else
|
|
{
|
|
*pCloseStatus = controlCloseCanProceed;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
TRC_NRM((TB,
|
|
_T("Immediate close OK:%d Connected:%d, pUI:%p hwnd:%p"),
|
|
m_bCoreInit, _ConnectionState, m_pUI,
|
|
m_pUI ? m_pUI->_UI.hwndMain : (HWND)-1));
|
|
*pCloseStatus = controlCloseCanProceed;
|
|
return S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
// Name: NotifyRedirectDeviceChange
|
|
//
|
|
// Purpose: Send the WM_DEVICECHANGE notification to the control
|
|
// The control can then notify the server for the device change
|
|
//
|
|
/****************************************************************************/
|
|
STDMETHODIMP CMsTscAx::NotifyRedirectDeviceChange(/*[in]*/ WPARAM wParam,
|
|
/*[in]*/LPARAM lParam)
|
|
{
|
|
DC_BEGIN_FN("NotifyRedirectDeviceChange");
|
|
|
|
m_pUI->UI_OnDeviceChange(wParam, lParam);
|
|
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: put_DesktopWidth */
|
|
/* */
|
|
/* Purpose: client width property input function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::put_DesktopWidth(LONG newVal)
|
|
{
|
|
DC_BEGIN_FN("put_DesktopWidth");
|
|
|
|
if(!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Can't call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// 0 is valid and means size to container
|
|
//
|
|
if(newVal && (newVal < MIN_DESKTOP_WIDTH || newVal > MAX_DESKTOP_WIDTH))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
m_DesktopWidth = (DCUINT)newVal;
|
|
|
|
DC_END_FN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_DesktopWidth */
|
|
/* */
|
|
/* Purpose: client width property get function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_DesktopWidth(LONG* pVal)
|
|
{
|
|
if(!pVal)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
*pVal = m_DesktopWidth;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: put_DesktopHeight */
|
|
/* */
|
|
/* Purpose: client Height property input function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::put_DesktopHeight(LONG newVal)
|
|
{
|
|
DC_BEGIN_FN("put_DesktopHeight");
|
|
|
|
if(!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Can't call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// 0 is valid and means size to container
|
|
//
|
|
if(newVal && (newVal < MIN_DESKTOP_HEIGHT || newVal > MAX_DESKTOP_HEIGHT))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
m_DesktopHeight = (DCUINT)newVal;
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_DesktopHeight */
|
|
/* */
|
|
/* Purpose: client Height property get function. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_DesktopHeight(LONG* pVal)
|
|
{
|
|
if(!pVal)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
*pVal = m_DesktopHeight;
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: internal_PutFullScreen
|
|
/*
|
|
/* Purpose: Set fullscreen (and switches mode)
|
|
/* This function is NOT exposed directly to the interface
|
|
/*
|
|
/* Params:
|
|
/* fFullScreen - TRUE to go fullscreen, FALSE to leave
|
|
/* fForceToggle - do an immediate toggle of the state
|
|
/* regardless of w/not we are disconnected.
|
|
/* default is FALSE for this param
|
|
/*
|
|
/* Remarks:
|
|
/* Normal behaviour is to not toggle the window state when
|
|
/* disconnected. Instead a flag is set that will take effect
|
|
/* at the next connection. There are of course cases where
|
|
/* that needs to be overriden and that's what fForceTogle is for.
|
|
/* Example, on disconnected we need to leave fullscreen immediately
|
|
/* in containers that don't handle fullscreen mode themselves
|
|
/* otherwise they would be stuck with a toplevel fullscreen wnd.
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::internal_PutFullScreen(BOOL fFullScreen,
|
|
BOOL fForceToggle)
|
|
{
|
|
ATLASSERT(m_pUI);
|
|
if(!m_pUI)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
DCBOOL fPrevFullScreen = m_pUI->UI_IsFullScreen();
|
|
|
|
//no, these lines of code are not as bad as they look
|
|
//vb's true is 0xFFFFFFF so don't just blindy assign
|
|
if (!IsControlDisconnected() || fForceToggle)
|
|
{
|
|
if(fPrevFullScreen == (DCBOOL)(fFullScreen != 0))
|
|
{
|
|
//we are already in the requested state
|
|
return S_OK;
|
|
}
|
|
|
|
if(fFullScreen)
|
|
{
|
|
m_pUI->UI_GoFullScreen();
|
|
}
|
|
else
|
|
{
|
|
m_pUI->UI_LeaveFullScreen();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Save the request to go fullscreen
|
|
// it will take effect on connection as we can't
|
|
// ask the core to take us fullscreen until the
|
|
// first time UI_Init is called
|
|
//
|
|
m_pUI->UI_SetStartFullScreen( fFullScreen != 0 );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: internal_GetFullScreen
|
|
/*
|
|
/* Purpose: get FullScreen mode
|
|
/* This function is NOT exposed directly to the interface
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::internal_GetFullScreen(BOOL* pfFullScreen)
|
|
{
|
|
ATLASSERT(pfFullScreen);
|
|
ATLASSERT(m_pUI);
|
|
if(!m_pUI || !pfFullScreen)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(!pfFullScreen)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pfFullScreen = (m_pUI->UI_IsFullScreen() ? VB_TRUE : VB_FALSE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: put_StartConnected
|
|
/*
|
|
/* Purpose: property that indicates if the client should autoconnect
|
|
/* on startup with the current set of connection params
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::put_StartConnected(BOOL fStartConnected)
|
|
{
|
|
DC_BEGIN_FN("put_StartConnected");
|
|
ATLASSERT(m_pUI);
|
|
if(!m_pUI)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(!IsControlDisconnected())
|
|
{
|
|
TRC_ERR((TB,_T("Can't call while connected\n")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//no, these lines of code are not as bad as they look
|
|
//vb's true is 0xFFFFFFF so don't just blindy assign
|
|
if(fStartConnected != 0)
|
|
{
|
|
m_bStartConnected = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_bStartConnected = FALSE;
|
|
}
|
|
|
|
//m_bPendConReq gets reset which is why we keep
|
|
//the property in m_bStartConnected
|
|
m_bPendConReq = m_bStartConnected;
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_StartConnected
|
|
/*
|
|
/* Purpose: get start connected property
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_StartConnected(BOOL* pfStartConnected)
|
|
{
|
|
ATLASSERT(pfStartConnected);
|
|
|
|
if(!pfStartConnected)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pfStartConnected = m_bStartConnected;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_Connected
|
|
/*
|
|
/* Purpose: Property, returns connection state
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_Connected(short* pIsConnected)
|
|
{
|
|
ATLASSERT(pIsConnected);
|
|
if(!pIsConnected)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pIsConnected = (short)_ConnectionState;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_CipherStrength
|
|
/*
|
|
/* Purpose: Property, returns cipher strength in bits
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_CipherStrength(LONG* pCipherStrength)
|
|
{
|
|
ATLASSERT(pCipherStrength);
|
|
if(!pCipherStrength)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Return cipher strength of the control
|
|
//
|
|
|
|
//Always 128-bit capable
|
|
*pCipherStrength = 128;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_Version
|
|
/*
|
|
/* Purpose: Property, returns version number as string form
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_Version(BSTR* pVersion)
|
|
{
|
|
USES_CONVERSION;
|
|
ATLASSERT(pVersion);
|
|
OLECHAR* pVer = NULL;
|
|
if(!pVersion)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
__try {
|
|
pVer = A2OLE(VER_PRODUCTVERSION_STR);
|
|
}
|
|
__except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH) {
|
|
_resetstkoflw();
|
|
pVer = NULL;
|
|
}
|
|
#else
|
|
pVer = (OLECHAR*)(VER_PRODUCTVERSION_STR);
|
|
#endif
|
|
|
|
if (!pVer)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*pVersion = SysAllocString(pVer);
|
|
if(!*pVersion)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: GetControlHostUrl
|
|
/*
|
|
/* Purpose: returns the URL of the hosting page in ppszHostUrl
|
|
/* CALLER MUST CoTaskMemFree the returned string
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
HRESULT CMsTscAx::GetControlHostUrl(LPOLESTR* ppszHostUrl)
|
|
{
|
|
DC_BEGIN_FN("GetControlHostUrl");
|
|
|
|
if (m_spClientSite && ppszHostUrl)
|
|
{
|
|
// Obtain URL from container moniker.
|
|
CComPtr<IMoniker> spmk;
|
|
|
|
if (SUCCEEDED(m_spClientSite->GetMoniker(
|
|
OLEGETMONIKER_TEMPFORUSER,
|
|
OLEWHICHMK_CONTAINER,
|
|
&spmk)))
|
|
{
|
|
if (SUCCEEDED(spmk->GetDisplayName(
|
|
NULL, NULL, ppszHostUrl)))
|
|
{
|
|
if (*ppszHostUrl)
|
|
{
|
|
USES_CONVERSION;
|
|
TRC_NRM((TB,_T("The current URL is %s\n"),
|
|
OLE2T(*ppszHostUrl)));
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TRC_ERR((TB,(_T("GetControlHostUrl failed\n"))));
|
|
|
|
DC_END_FN();
|
|
|
|
*ppszHostUrl = NULL;
|
|
return E_FAIL;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_SecuredSettingsEnabled
|
|
/*
|
|
/* Purpose: Property, returns TRUE if we are in an IE zone where
|
|
/* we enable the SecuredSettings interface
|
|
/* return FALSE otherwise.
|
|
/*
|
|
/* Function returns failure HRESULT if we can't make the determination
|
|
/* e.g if we are not hosted in IE.
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_SecuredSettingsEnabled(BOOL* pSecuredSettingsEnabled)
|
|
{
|
|
//
|
|
// This function uses the IE security manager
|
|
// to query the zone for the URL that is hosting this control
|
|
//
|
|
DC_BEGIN_FN("get_SecuredSettingsEnabled");
|
|
|
|
if(pSecuredSettingsEnabled)
|
|
{
|
|
#if ((!defined (OS_WINCE)) || (!defined(WINCE_SDKBUILD)) )
|
|
if((INTERFACESAFE_FOR_UNTRUSTED_CALLER & m_dwCurrentSafety) == 0)
|
|
#endif
|
|
{
|
|
//
|
|
// We're don't need to be safe for an untrusted caller (script)
|
|
// so enable the secured settings object
|
|
//
|
|
*pSecuredSettingsEnabled = VB_TRUE;
|
|
return S_OK;
|
|
}
|
|
#if ((!defined (OS_WINCE)) || (!defined(WINCE_SDKBUILD)) )
|
|
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<IInternetSecurityManager> spSecurityManager;
|
|
hr = CoCreateInstance(CLSID_InternetSecurityManager,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IInternetSecurityManager,
|
|
(void**)&spSecurityManager);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
LPOLESTR pszHostUrl;
|
|
hr = GetControlHostUrl(&pszHostUrl);
|
|
if(SUCCEEDED(hr) && *pszHostUrl)
|
|
{
|
|
DWORD dwZone; // IE zone index for this URL
|
|
hr = spSecurityManager->MapUrlToZone( pszHostUrl, &dwZone, 0);
|
|
|
|
//We're done with the URL string, free it
|
|
CoTaskMemFree(pszHostUrl);
|
|
pszHostUrl = NULL;
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
TRC_NRM((TB,
|
|
_T("get_SecuredSettingsEnabled retreived zone: %d\n"),
|
|
dwZone));
|
|
*pSecuredSettingsEnabled =
|
|
(dwZone <= MAX_TRUSTED_ZONE_INDEX) ?
|
|
VB_TRUE : VB_FALSE;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,
|
|
(_T("CoCreateInstance for IID_IInternetSecurityManager failed\n"))));
|
|
return hr;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_SecuredSettings
|
|
/*
|
|
/* Purpose: Property,
|
|
/* Checks the security zone in IE and returns (and on-demand
|
|
/* creates if needed) the secured settings object.
|
|
/* Returns an E_FAIL if the security settings do not allow
|
|
/* the operation.
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_SecuredSettings(/*out*/
|
|
IMsTscSecuredSettings** ppSecuredSettings)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DC_BEGIN_FN("get_SecuredSettings");
|
|
|
|
if(!ppSecuredSettings)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
BOOL bSecurityAllowsSecuredSettings;
|
|
hr = get_SecuredSettingsEnabled(&bSecurityAllowsSecuredSettings);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if(VB_FALSE == bSecurityAllowsSecuredSettings)
|
|
{
|
|
TRC_ERR((TB,_T("IE zone cant retreive IMsTscSecuredSettings\n")));
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
|
|
if(!m_pSecuredSettingsObj) {
|
|
//On demand creation of the secured settings COM object
|
|
hr = CComObject<CMsTscSecuredSettings>::CreateInstance(
|
|
&m_pSecuredSettingsObj);
|
|
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB,_T("Failed to CreateInstance SecuredSettings: 0x%x"),hr));
|
|
return hr;
|
|
}
|
|
|
|
if (!((CMsTscSecuredSettings*)m_pSecuredSettingsObj)->SetParent(this)) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (!((CMsTscSecuredSettings*)m_pSecuredSettingsObj)->SetUI(m_pUI)) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
//We want to use this thru script clients
|
|
//so we will manage the lifetime of the advanced settings object
|
|
m_pSecuredSettingsObj->AddRef();
|
|
}
|
|
|
|
//Object should be created by this point
|
|
ATLASSERT( m_pSecuredSettingsObj);
|
|
if(!m_pSecuredSettingsObj) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
//Object was previously created just return an interface
|
|
hr = m_pSecuredSettingsObj->QueryInterface( IID_IMsTscSecuredSettings,
|
|
(void**)ppSecuredSettings);
|
|
|
|
DC_END_FN();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Return v2 Secured settings interface
|
|
// delegate the work to the v1 interface accessor
|
|
// it does all the security checking
|
|
//
|
|
STDMETHODIMP CMsTscAx::get_SecuredSettings2(/*out*/
|
|
IMsRdpClientSecuredSettings** ppSecuredSettings2)
|
|
{
|
|
DC_BEGIN_FN("get_SecuredSettings2");
|
|
|
|
HRESULT hr = E_FAIL;
|
|
if (!ppSecuredSettings2)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
IMsTscSecuredSettings* pOldSecSettings = NULL;
|
|
hr = get_SecuredSettings( &pOldSecSettings);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pOldSecSettings->QueryInterface(
|
|
IID_IMsRdpClientSecuredSettings,
|
|
(void**)ppSecuredSettings2);
|
|
pOldSecSettings->Release();
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_AdvancedSettings
|
|
/*
|
|
/* Purpose: Property, returns (and on-demand creates if needed) the advanced
|
|
/* settings object
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_AdvancedSettings(IMsTscAdvancedSettings** ppAdvSettings)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DC_BEGIN_FN("get_AdvancedSettings");
|
|
|
|
if(!ppAdvSettings)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (!m_pAdvancedSettingsObj)
|
|
{
|
|
//On demand creation of the advanced settings COM object
|
|
hr = CComObject<CMstscAdvSettings>::CreateInstance(&m_pAdvancedSettingsObj);
|
|
|
|
if(FAILED(hr)) {
|
|
TRC_ERR((TB,_T("Failed to create advsettings obj: 0x%x"),hr));
|
|
return hr;
|
|
}
|
|
if(!m_pAdvancedSettingsObj) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(!((CMstscAdvSettings*)m_pAdvancedSettingsObj)->SetUI(m_pUI)) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Give the child object a backreference
|
|
//
|
|
((CMstscAdvSettings*)m_pAdvancedSettingsObj)->SetAxCtl( this );
|
|
|
|
//Tell the advanced setting object if it should be safe for scripting
|
|
//or not (default is safe). m_dwCurrentSafety is set by ATL's
|
|
//IObjectSafetyImpl
|
|
#if ((!defined (OS_WINCE)) || (!defined(WINCE_SDKBUILD)) )
|
|
m_pAdvancedSettingsObj->SetSafeForScripting(
|
|
INTERFACESAFE_FOR_UNTRUSTED_CALLER & m_dwCurrentSafety);
|
|
#else
|
|
m_pAdvancedSettingsObj->SetSafeForScripting(FALSE);
|
|
#endif
|
|
|
|
//We want to use this thru script clients
|
|
//so we will manage the lifetime of the advanced settings object
|
|
m_pAdvancedSettingsObj->AddRef();
|
|
}
|
|
|
|
//Object should be created by this point
|
|
ATLASSERT( m_pAdvancedSettingsObj);
|
|
if(!m_pAdvancedSettingsObj)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
//Object was previously created just return an interface
|
|
hr = m_pAdvancedSettingsObj->QueryInterface( IID_IMsTscAdvancedSettings,
|
|
(void**) ppAdvSettings);
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: internal_GetDebugger
|
|
/*
|
|
/* Purpose: Property, returns (and on-demand creates if needed) the debugger
|
|
/* object
|
|
/*
|
|
/* Does no security access checks
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::internal_GetDebugger(IMsTscDebug** ppDebugger)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DC_BEGIN_FN("get_Debugger");
|
|
|
|
if(!ppDebugger)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if(!m_pDebuggerObj)
|
|
{
|
|
//On demand creation of the advanced settings COM object
|
|
hr = CComObject<CMsTscDebugger>::CreateInstance(&m_pDebuggerObj);
|
|
|
|
if(FAILED(hr)) {
|
|
TRC_ERR((TB,_T("Failed to create debugger obj: 0x%x"),hr));
|
|
return hr;
|
|
}
|
|
|
|
if(!((CMsTscDebugger*)m_pDebuggerObj)->SetUI(m_pUI)) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
//We want to use this thru script clients
|
|
//so we will manage the lifetime of the debugger object
|
|
m_pDebuggerObj->AddRef();
|
|
}
|
|
|
|
//Object should be created by this point
|
|
ATLASSERT( m_pDebuggerObj);
|
|
if(!m_pDebuggerObj) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
//Object was previously created just return an interface
|
|
hr = m_pDebuggerObj->QueryInterface( IID_IMsTscDebug, (void**) ppDebugger);
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// get_Debugger (IMsTscAx::get_Debugger)
|
|
//
|
|
// Purpose:
|
|
// Scriptable access to the debugger interface. For security reasons,
|
|
// only allows access if the AllowDebugInterface reg key is set.
|
|
// Params:
|
|
// OUT ppDebugger - receives debugger interface
|
|
// Returns:
|
|
// HRESULT
|
|
//
|
|
STDMETHODIMP CMsTscAx::get_Debugger(IMsTscDebug** ppDebugger)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwAllowDebugInterface = 0;
|
|
CUT ut;
|
|
|
|
//
|
|
// Security! If we're SFS then only return this interface if a
|
|
// special reg key is set
|
|
//
|
|
if (INTERFACESAFE_FOR_UNTRUSTED_CALLER & m_dwCurrentSafety) {
|
|
//
|
|
// ONLY allow this interface to be returned if the debugging reg
|
|
// key is set
|
|
//
|
|
dwAllowDebugInterface =
|
|
ut.UT_ReadRegistryInt(
|
|
UTREG_SECTION,
|
|
UTREG_DEBUG_ALLOWDEBUGIFACE,
|
|
UTREG_DEBUG_ALLOWDEBUGIFACE_DFLT
|
|
);
|
|
|
|
if (!dwAllowDebugInterface) {
|
|
return E_ACCESSDENIED;
|
|
}
|
|
}
|
|
|
|
hr = internal_GetDebugger(ppDebugger);
|
|
return hr;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_HorizontalScrollBarVisible
|
|
/*
|
|
/* Purpose: Property, returns true if HScroll visible
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_HorizontalScrollBarVisible(BOOL* pfHScrollVisible)
|
|
{
|
|
if (!pfHScrollVisible) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
ATLASSERT(m_pUI);
|
|
if (!m_pUI) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
*pfHScrollVisible = m_pUI->_UI.fHorizontalScrollBarVisible;
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: get_VerticalScrollBarVisible
|
|
/*
|
|
/* Purpose: Property, returns true if VScroll visible
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::get_VerticalScrollBarVisible(BOOL* pfVScrollVisible)
|
|
{
|
|
if(!pfVScrollVisible)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
ATLASSERT(m_pUI);
|
|
if(!m_pUI)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
*pfVScrollVisible = m_pUI->_UI.fVerticalScrollBarVisible;
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: put_FullScreenTitle
|
|
/*
|
|
/* Purpose: Set's title of the main window (used when the control goes
|
|
/* full screen as that becomes the window title you see)
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::put_FullScreenTitle(BSTR fullScreenTitle)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
if(!fullScreenTitle)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
LPTSTR pszTitle = OLE2T(fullScreenTitle);
|
|
if(!pszTitle)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(::IsWindow(m_pUI->_UI.hwndMain))
|
|
{
|
|
if(!::SetWindowText( m_pUI->_UI.hwndMain, pszTitle))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Window not created yet, set text for later creation
|
|
hr = StringCchCopy(m_pUI->_UI.szFullScreenTitle,
|
|
SIZE_TCHARS(m_pUI->_UI.szFullScreenTitle),
|
|
pszTitle);
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: Connect */
|
|
/* */
|
|
/* Purpose: Connects to Hydra Server. */
|
|
/* This call is asynchronous, only the initial portion of */
|
|
/* connecting is blocking */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::Connect()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
#ifdef ECP_TIMEBOMB
|
|
if(!CheckTimeBomb())
|
|
{
|
|
//
|
|
// Timebomb failed, bail out with an error message
|
|
//
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
#endif
|
|
|
|
if (IsControlDisconnected())
|
|
{
|
|
if (::IsWindow(m_hWnd))
|
|
{
|
|
hr = StartConnect();
|
|
}
|
|
else
|
|
{
|
|
// Connection requested even before control window creation.
|
|
// mark it as pending and process it after control created.
|
|
m_bPendConReq = TRUE;
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: Disconnect */
|
|
/* */
|
|
/* Purpose: Disconnects from server (asynchronous). */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
STDMETHODIMP CMsTscAx::Disconnect()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DC_BEGIN_FN("Disconnect");
|
|
if (m_bCoreInit && !IsControlDisconnected() && m_pUI)
|
|
{
|
|
m_pUI->UI_UserInitiatedDisconnect(NL_DISCONNECT_LOCAL);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Fail to disconnect can happen if the core
|
|
// has been destroyed without a disconnection
|
|
//
|
|
TRC_ERR((TB,
|
|
_T("Not disconnecting. CoreInit:%d Connected:%d, pUI:%p hwnd:%p"),
|
|
m_bCoreInit, _ConnectionState, m_pUI,
|
|
m_pUI ? m_pUI->_UI.hwndMain : (HWND)-1));
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnDraw */
|
|
/* */
|
|
/* Purpose: Handler for WM_PAINT */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
HRESULT CMsTscAx::OnDraw(ATL_DRAWINFO& di)
|
|
{
|
|
#ifndef OS_WINCE
|
|
HFONT hOldFont;
|
|
#endif
|
|
RECT& rc = *(RECT*)di.prcBounds;
|
|
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
|
|
|
|
#ifndef OS_WINCE
|
|
hOldFont = (HFONT)SelectObject(di.hdcDraw,
|
|
GetStockObject(DEFAULT_GUI_FONT));
|
|
#endif
|
|
|
|
DrawText(di.hdcDraw, m_lpStatusDisplay, -1, &rc,
|
|
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
|
|
|
#ifndef OS_WINCE
|
|
SelectObject( di.hdcDraw, hOldFont);
|
|
#endif
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnFrameWindowActivate */
|
|
/* */
|
|
/* Purpose: Override IOleInPlaceActiveObject::OnFrameWindowActivate */
|
|
/* to set the focus on the core container window when the control */
|
|
/* gets activated */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
|
|
STDMETHODIMP CMsTscAx::OnFrameWindowActivate(BOOL fActivate )
|
|
{
|
|
DC_BEGIN_FN("OnFrameWindowActivate");
|
|
|
|
if(fActivate && IsWindow())
|
|
{
|
|
if(m_pUI && m_pUI->_UI.hwndContainer)
|
|
{
|
|
::SetFocus( m_pUI->_UI.hwndContainer);
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: UpdateStatusText */
|
|
/* */
|
|
/* Purpose: Updates the status message for control. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
DCBOOL CMsTscAx::UpdateStatusText(const PDCTCHAR lpStatus)
|
|
{
|
|
m_lpStatusDisplay = lpStatus;
|
|
|
|
//
|
|
// Make sure the window contents are updated
|
|
//
|
|
if(::IsWindow(m_hWnd))
|
|
{
|
|
Invalidate(TRUE);
|
|
UpdateWindow();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: SetConnectedStatus */
|
|
/* */
|
|
/* Purpose: Updates the connected status of the control. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
DCVOID CMsTscAx::SetConnectedStatus(TSCConnectState conState)
|
|
{
|
|
DC_BEGIN_FN("SetConnectedStatus");
|
|
TRC_NRM((TB,_T("Connection status from %d to %d"),
|
|
_ConnectionState, conState));
|
|
|
|
_ConnectionState = conState;
|
|
|
|
//
|
|
// while connected lock the Advanced settings/Debugger IFace's
|
|
// for writing...can't modify props the core is relying on
|
|
//
|
|
BOOL fLockInterfaces = (_ConnectionState != tscNotConnected);
|
|
|
|
if( (CMstscAdvSettings*)m_pAdvancedSettingsObj )
|
|
{
|
|
((CMstscAdvSettings*)m_pAdvancedSettingsObj)->SetInterfaceLockedForWrite(fLockInterfaces);
|
|
}
|
|
|
|
if( (CMsTscDebugger*)m_pDebuggerObj )
|
|
{
|
|
((CMsTscDebugger*)m_pDebuggerObj)->SetInterfaceLockedForWrite(fLockInterfaces);
|
|
}
|
|
|
|
if( (CMsTscSecuredSettings*)m_pSecuredSettingsObj )
|
|
{
|
|
((CMsTscSecuredSettings*)m_pSecuredSettingsObj)->SetInterfaceLockedForWrite(fLockInterfaces);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnCreate */
|
|
/* */
|
|
/* Purpose: Handler for WM_CREATE. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnCreate(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
//
|
|
// If the memory allocation failed for the core root object
|
|
// bail out now by returning -1 and failing the create
|
|
//
|
|
if (NULL == m_pUI) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Reset the destroy counter (we only allow one destroy per create)
|
|
//
|
|
m_iDestroyCount = 0;
|
|
|
|
::SetWindowLong(m_hWnd, GWL_STYLE,
|
|
::GetWindowLong(m_hWnd, GWL_STYLE) | WS_CLIPCHILDREN);
|
|
|
|
UpdateStatusText(m_szDisconnectedText);
|
|
|
|
if (m_bPendConReq)
|
|
{
|
|
m_bPendConReq = FALSE;
|
|
Connect();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnSize */
|
|
/* */
|
|
/* Purpose: Handler for WM_SIZE . */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnSize(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
//
|
|
// Resize the TS client window to match the resize of the active control
|
|
// container window.
|
|
//
|
|
// Do not do this if we are running fullscreen while the core is handling
|
|
// fullscreen mode as in that case the hwndMain is no longer a child of
|
|
// the ActiveX control and so it's sizing should not be coupled to it.
|
|
//
|
|
if(m_pUI &&
|
|
!(m_pUI->UI_IsFullScreen() &&
|
|
!m_pUI->UI_GetContainerHandledFullScreen())) {
|
|
|
|
int width = LOWORD(lParam);
|
|
int height = HIWORD(lParam);
|
|
::MoveWindow( m_pUI->_UI.hwndMain,0, 0, width, height, TRUE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnPaletteChanged */
|
|
/* */
|
|
/* Purpose: Handler for WM_PALETTECHANGED. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnPaletteChanged(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
//Propagate the change notification to the core (only if core is initialised)
|
|
if(m_bCoreInit && m_pUI)
|
|
{
|
|
::SendMessage( m_pUI->_UI.hwndMain, uMsg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnQueryNewPalette */
|
|
/* */
|
|
/* Purpose: Handler for WM_QUERYNEWPALETTE. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnQueryNewPalette(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
//Propagate the change notification to the core
|
|
if(m_bCoreInit && m_pUI)
|
|
{
|
|
return ::SendMessage( m_pUI->_UI.hwndMain, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// OnSysColorChange
|
|
// Handler for WM_SYSCOLORCHANGE
|
|
//
|
|
LRESULT CMsTscAx::OnSysColorChange(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
//Propagate the change notification to the core
|
|
if (m_bCoreInit && m_pUI)
|
|
{
|
|
return ::SendMessage( m_pUI->_UI.hwndMain, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnGotFocus */
|
|
/* */
|
|
/* Purpose: Handler for WM_SETFOCUS . */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnGotFocus( UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
#ifdef OS_WINCE
|
|
if (CountClipboardFormats() > 0)
|
|
::PostMessage(ghwndClip, WM_DRAWCLIPBOARD, 0, 0L);
|
|
#endif
|
|
|
|
if(m_pUI && m_pUI->_UI.hwndContainer)
|
|
{
|
|
::SetFocus( m_pUI->_UI.hwndContainer);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: StartConnect */
|
|
/* */
|
|
/* Initiate a connection with the current params */
|
|
/* Do a blocking defered INIT of the core (UI_Init) */
|
|
/* */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
HRESULT CMsTscAx::StartConnect()
|
|
{
|
|
DC_BEGIN_FN("StartConnect");
|
|
|
|
HRESULT hr;
|
|
|
|
if( CONNECTIONMODE_CONNECTEDENDPOINT == m_ConnectionMode )
|
|
{
|
|
_ASSERTE( m_SalemConnectedSocket != INVALID_SOCKET );
|
|
|
|
if( m_SalemConnectedSocket == INVALID_SOCKET )
|
|
{
|
|
hr = E_HANDLE;
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
hr = StartEstablishConnection( m_ConnectionMode );
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: StartEstablishConnection */
|
|
/* */
|
|
/* Initiate a connection with the current params */
|
|
/* Do a blocking defered INIT of the core (UI_Init) */
|
|
/* */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
HRESULT CMsTscAx::StartEstablishConnection( CONNECTIONMODE connectMode )
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
IUnknown* pUnk;
|
|
|
|
DC_BEGIN_FN("StartEstablishConnection");
|
|
|
|
_ASSERTE(IsControlDisconnected());
|
|
ATLASSERT(m_pUI);
|
|
if(!m_pUI)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
UpdateStatusText(m_szConnectingText);
|
|
|
|
//Save control instance (used by virtual channel addins)
|
|
hr = QueryInterface(IID_IUnknown, (VOID**)&pUnk);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
m_pUI->UI_SetControlInstance(pUnk);
|
|
pUnk->Release();
|
|
pUnk = NULL;
|
|
}
|
|
else {
|
|
return hr;
|
|
}
|
|
|
|
m_pUI->_UI.hWndCntrl = m_hWnd;
|
|
//
|
|
// Expose window handle so vchannel can notify when data arrives
|
|
//
|
|
_VChans._hwndControl = m_hWnd;
|
|
|
|
if( CONNECTIONMODE_INITIATE == connectMode )
|
|
{
|
|
if(!CUT::ValidateServerName(m_pUI->_UI.strAddress,
|
|
FALSE)) //don't accept [:port]
|
|
{
|
|
TRC_ERR((TB,_T("Invalid server name at connect time")));
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set control size so that client can position the main window at an
|
|
// appropriate position.
|
|
|
|
//
|
|
// If the client width/height properties were set then use those.
|
|
// Otherwise get the width/height from the container size
|
|
// The client/width height are specifically set in the MMC control
|
|
//
|
|
|
|
if (m_DesktopWidth && m_DesktopHeight)
|
|
{
|
|
m_pUI->_UI.controlSize.width = m_DesktopWidth;
|
|
m_pUI->_UI.controlSize.height = m_DesktopHeight;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// size properties were not set so go with the size
|
|
// of the control (this is what is usually used in the
|
|
// web case
|
|
//
|
|
|
|
RECT rc;
|
|
GetClientRect(&rc);
|
|
|
|
m_pUI->_UI.controlSize.width = rc.right - rc.left;
|
|
m_pUI->_UI.controlSize.height = rc.bottom - rc.top;
|
|
}
|
|
|
|
//
|
|
// client width MUST be a multiple of four pixels so snap down to nearest
|
|
// multiple of 4. This really comes up when the control is asked to size
|
|
// itself as a percentage of page width in IE, or to size itself to mmc
|
|
// result pane
|
|
//
|
|
|
|
if(m_pUI->_UI.controlSize.width % 4)
|
|
{
|
|
m_pUI->_UI.controlSize.width -= (m_pUI->_UI.controlSize.width % 4);
|
|
}
|
|
|
|
ATLASSERT(!(m_pUI->_UI.controlSize.width % 4));
|
|
|
|
|
|
|
|
// Now validate the control width/height
|
|
// this is done in put_Desktop* but if it
|
|
// was left unchanged we get the sizes from the
|
|
// container
|
|
// clamp to MIN/MAX
|
|
//
|
|
if(m_pUI->_UI.controlSize.width < MIN_DESKTOP_WIDTH)
|
|
{
|
|
m_pUI->_UI.controlSize.width = MIN_DESKTOP_WIDTH;
|
|
}
|
|
else if(m_pUI->_UI.controlSize.width > MAX_DESKTOP_WIDTH)
|
|
{
|
|
m_pUI->_UI.controlSize.width = MAX_DESKTOP_WIDTH;
|
|
}
|
|
|
|
if(m_pUI->_UI.controlSize.height < MIN_DESKTOP_HEIGHT)
|
|
{
|
|
m_pUI->_UI.controlSize.height = MIN_DESKTOP_HEIGHT;
|
|
}
|
|
else if(m_pUI->_UI.controlSize.height > MAX_DESKTOP_HEIGHT)
|
|
{
|
|
m_pUI->_UI.controlSize.height = MAX_DESKTOP_HEIGHT;
|
|
}
|
|
|
|
//
|
|
// Set window placement.
|
|
//
|
|
m_pUI->_UI.windowPlacement.flags = 0;
|
|
m_pUI->_UI.windowPlacement.showCmd = SW_SHOW;
|
|
m_pUI->_UI.windowPlacement.rcNormalPosition.left = 0;
|
|
m_pUI->_UI.windowPlacement.rcNormalPosition.top = 0;
|
|
m_pUI->_UI.windowPlacement.rcNormalPosition.right =
|
|
m_pUI->_UI.controlSize.width;
|
|
m_pUI->_UI.windowPlacement.rcNormalPosition.bottom =
|
|
m_pUI->_UI.controlSize.height;
|
|
|
|
//
|
|
// Set desktop size.
|
|
//
|
|
m_pUI->_UI.uiSizeTable[0] = m_pUI->_UI.controlSize.width;
|
|
m_pUI->_UI.uiSizeTable[1] = m_pUI->_UI.controlSize.height;
|
|
|
|
//
|
|
// Set autoconnect parameters.
|
|
//
|
|
if (DC_TSTRCMP(m_pUI->_UI.strAddress,_T("")))
|
|
{
|
|
m_pUI->_UI.autoConnectEnabled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_pUI->_UI.autoConnectEnabled = FALSE;
|
|
}
|
|
|
|
//
|
|
// Set autologon parameters.
|
|
//
|
|
|
|
//
|
|
// If a username/password is specified use autologon (don't need a
|
|
// domain since some people logon to home machines etc...with no domain)
|
|
//
|
|
if (DC_WSTRCMP(m_pUI->_UI.UserName,L"") &&
|
|
IsNonPortablePassSet() &&
|
|
IsNonPortableSaltSet())
|
|
{
|
|
m_pUI->_UI.fAutoLogon = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_pUI->_UI.fAutoLogon = FALSE;
|
|
}
|
|
|
|
m_pUI->UI_SetPassword(m_NonPortablePassword);
|
|
m_pUI->UI_SetSalt(m_NonPortableSalt);
|
|
|
|
#ifdef REDIST_CONTROL
|
|
|
|
//
|
|
// Security popup UI to allow user to opt-in redirecting
|
|
// of drives and smart cards.
|
|
// Only appears if object needs to be safe for an untrusted caller.
|
|
//
|
|
// Only do this if we're not autoreconnecting.
|
|
//
|
|
if (!_arcManager.IsAutoReconnecting() &&
|
|
(INTERFACESAFE_FOR_UNTRUSTED_CALLER & m_dwCurrentSafety) &&
|
|
(m_pUI->UI_GetDriveRedirectionEnabled() ||
|
|
m_pUI->UI_GetPortRedirectionEnabled() ||
|
|
(m_pUI->UI_GetSCardRedirectionEnabled() && CUT::IsSCardReaderInstalled())))
|
|
{
|
|
INT retVal = 0;
|
|
//
|
|
// Need to pop security UI in web control case
|
|
//
|
|
HMODULE hModRc = _Module.GetResourceInstance();
|
|
|
|
CSecurDlg securDlg( m_hWnd, hModRc);
|
|
securDlg.SetRedirDrives(m_pUI->UI_GetDriveRedirectionEnabled());
|
|
securDlg.SetRedirPorts(m_pUI->UI_GetPortRedirectionEnabled());
|
|
securDlg.SetRedirSCard(m_pUI->UI_GetSCardRedirectionEnabled());
|
|
retVal = securDlg.DoModal();
|
|
if (IDOK == retVal)
|
|
{
|
|
TRC_NRM((TB,_T("Changing drive,scard based on UI")));
|
|
m_pUI->UI_SetDriveRedirectionEnabled( securDlg.GetRedirDrives() );
|
|
m_pUI->UI_SetPortRedirectionEnabled( securDlg.GetRedirPorts() );
|
|
m_pUI->UI_SetSCardRedirectionEnabled( securDlg.GetRedirSCard() );
|
|
}
|
|
else if(IDCANCEL == retVal)
|
|
{
|
|
TRC_NRM((TB,_T("User canceld out of security dialog")));
|
|
//
|
|
// Abort connection
|
|
//
|
|
BOOL bHandled=FALSE;
|
|
OnNotifyDisconnected( 0, (LONG)disconnectReasonLocalNotError,
|
|
0L, bHandled );
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Security dialog failed to initialize abort connection
|
|
//
|
|
TRC_ERR((TB,_T("Security dialog returned an error")));
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (m_bCoreInit) {
|
|
// Core has initialized just ask for a connect
|
|
hr = m_pUI->SetConnectWithEndpoint( m_SalemConnectedSocket );
|
|
if( FAILED(hr) )
|
|
{
|
|
TRC_ERR((TB,_T("SetConnectWithEndpoint (init) failed: %x"), hr));
|
|
return hr;
|
|
}
|
|
|
|
hr = m_pUI->UI_Connect( connectMode );
|
|
if(FAILED(hr))
|
|
{
|
|
TRC_ERR((TB,_T("UI_Connect (init precomplete) failed: %d"), hr));
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HINSTANCE hres = _Module.GetResourceInstance();
|
|
HINSTANCE hinst = _Module.GetModuleInstance();
|
|
|
|
//
|
|
// Core hasn't been initialized
|
|
// initialize the core (synchronously)
|
|
//
|
|
HANDLE hEvtCoreInit = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if(hEvtCoreInit)
|
|
{
|
|
TRC_NRM((TB,_T("Initializing core...")));
|
|
hr = m_pUI->UI_Init( hinst, NULL, hres,
|
|
hEvtCoreInit);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Async core init has begun. Block and wait for it to complete
|
|
// this will usually be very quick. It is crucial
|
|
// not to allow other core operations to happen until either
|
|
// the core has completed INIT or has failed to initialize.
|
|
//
|
|
TRC_NRM((TB,_T("Block waiting for core init to complete...")));
|
|
|
|
DWORD dwWaitResult = WaitForSingleObject(hEvtCoreInit,
|
|
CORE_INIT_TIMEOUT);
|
|
if(WAIT_TIMEOUT == dwWaitResult)
|
|
{
|
|
g_dwControlDbgStatus |= CONTROL_DBG_COREINIT_TIMEOUT;
|
|
TRC_ERR((TB,_T("Core init has timed out")));
|
|
BOOL fb;
|
|
OnNotifyFatalError(0,
|
|
DC_ERR_COREINITFAILED,
|
|
0,fb);
|
|
CloseHandle(hEvtCoreInit);
|
|
return E_FAIL;
|
|
}
|
|
else if (WAIT_OBJECT_0 != dwWaitResult)
|
|
{
|
|
TRC_ERR((TB,_T("Wait for core init event failed: %d"),
|
|
dwWaitResult));
|
|
g_dwControlDbgStatus |= CONTROL_DBG_COREINIT_ERROR;
|
|
|
|
BOOL fb;
|
|
CloseHandle(hEvtCoreInit);
|
|
OnNotifyFatalError(0,
|
|
DC_ERR_COREINITFAILED,
|
|
0,fb);
|
|
return E_FAIL;
|
|
}
|
|
|
|
CloseHandle(hEvtCoreInit);
|
|
|
|
TRC_NRM((TB,_T("Core init complete...")));
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Core init has failed with code %d"), hr));
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
TRC_ERR((TB,_T("Failed to create core notify event %d"), hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Core init is only done once on initialization
|
|
//
|
|
m_bCoreInit = TRUE;
|
|
|
|
hr = m_pUI->SetConnectWithEndpoint( m_SalemConnectedSocket );
|
|
if( FAILED(hr) )
|
|
{
|
|
TRC_ERR((TB,_T("SetConnectWithEndpoint failed: %x"), hr));
|
|
return hr;
|
|
}
|
|
|
|
//Kick off the connection
|
|
hr = m_pUI->UI_Connect( connectMode );
|
|
if(FAILED(hr))
|
|
{
|
|
TRC_ERR((TB, _T("UI_Connect failed: %d"), hr));
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
SetConnectedStatus(tscConnecting);
|
|
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnTerminateTsc */
|
|
/* */
|
|
/* Purpose: Handler for WM_TERMTSC user defined Message. Terminates a */
|
|
/* connection with Terminal server. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnTerminateTsc(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
//
|
|
// Notify of a user initiated disconnection
|
|
//
|
|
OnNotifyDisconnected( 0, (LONG)disconnectReasonLocalNotError,
|
|
0L, bHandled );
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnDestroy */
|
|
/* */
|
|
/* Purpose: Handler for WM_DESTROY. Disconnect active connections, if any.*/
|
|
/* being activated. */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnDestroy(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
DC_BEGIN_FN("OnDestroy");
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
#ifndef OS_WINCE
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
#else
|
|
bHandled = FALSE;
|
|
#endif
|
|
|
|
g_lockCount++;
|
|
|
|
//
|
|
// Don't allow multiple closes
|
|
//
|
|
if(m_iDestroyCount != 0)
|
|
{
|
|
#ifndef OS_WINCE
|
|
bHandled = TRUE;
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
m_iDestroyCount++;
|
|
|
|
//
|
|
// If the UI object was not allocated, e.g on
|
|
// memory allocation failure in the ctor then
|
|
// bail out now.
|
|
//
|
|
if(!m_pUI)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_pUI && ::IsWindow(m_pUI->_UI.hwndMain))
|
|
{
|
|
CCleanUp cleanup;
|
|
HWND hwndCleanup = cleanup.Start();
|
|
if(!hwndCleanup)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_pUI->_UI.hWndCntrl = hwndCleanup;
|
|
|
|
m_pUI->UI_UserRequestedClose();
|
|
// Wait for the close to complete
|
|
// This blocks (pumps msgs) until the appropriate messages
|
|
// are received from the core
|
|
//
|
|
cleanup.End();
|
|
|
|
UpdateStatusText(m_szDisconnectedText);
|
|
|
|
//
|
|
// The disconnect has completed, hide the main and container
|
|
// windows, the core only hides them for a server initiated
|
|
// disconnection
|
|
//
|
|
|
|
// We do ShowWindow twice for the main window because the first
|
|
// call can be ignored if the main window was maximized.
|
|
::ShowWindow(m_pUI->_UI.hwndContainer, SW_HIDE);
|
|
::ShowWindow(m_pUI->_UI.hwndMain, SW_HIDE);
|
|
::ShowWindow(m_pUI->_UI.hwndMain, SW_HIDE);
|
|
}
|
|
|
|
if(m_pUI->UI_IsCoreInitialized())
|
|
{
|
|
m_pUI->UI_Term();
|
|
m_bCoreInit = FALSE;
|
|
}
|
|
|
|
g_lockCount--;
|
|
|
|
DC_END_FN();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyConnecting
|
|
/*
|
|
/* Purpose: Handler for WM_TS_CONNECTING
|
|
/* Notifys container that core has started connection process
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyConnecting(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
//Fire the event
|
|
AddRef();
|
|
Fire_Connecting();
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyConnected
|
|
/*
|
|
/* Purpose: Handler for WM_TS_CONNECTED
|
|
/* Notifys container that core has connected
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyConnected(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
BOOL fWasAutoreconnect = FALSE;
|
|
DC_BEGIN_FN("OnNotifyConnected");
|
|
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
UpdateStatusText(m_szConnectedText);
|
|
|
|
fWasAutoreconnect = _arcManager.IsAutoReconnecting();
|
|
_arcManager.ResetArcAttempts();
|
|
|
|
SetConnectedStatus(tscConnected);
|
|
|
|
//
|
|
// Don't fire the notification if it' an automatic autoreconnect
|
|
// as the container should not receive any disconnected/connected
|
|
// notifications.
|
|
//
|
|
if (!(fWasAutoreconnect && _arcManager.IsAutomaticArc())) {
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_Connected();
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
}
|
|
|
|
|
|
DC_END_FN();
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyLoginComplete
|
|
/*
|
|
/* Purpose: Handler for WM_TS_LOGINCOMPLETE
|
|
/* Notifys container that login was successful
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyLoginComplete(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_LoginComplete();
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyDisconnected
|
|
/*
|
|
/* Purpose: Handler for WM_TS_DISCONNECTED
|
|
/* Notifys container that core has disconnected
|
|
/* wParam contains the disconnect reason
|
|
/*
|
|
/*
|
|
/* Returns TRUE if caller should continue processing
|
|
/* FALSE to bail out immediately
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyDisconnected(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
HRESULT hr;
|
|
LRESULT rc = FALSE;
|
|
ExtendedDisconnectReasonCode exReason;
|
|
LONG disconnectReason = (long) wParam;
|
|
BOOL fContinue = FALSE;
|
|
|
|
DC_BEGIN_FN("OnNotifyDisconnected");
|
|
|
|
UpdateStatusText(m_szDisconnectedText);
|
|
SetConnectedStatus(tscNotConnected);
|
|
|
|
|
|
//
|
|
// Remember the fullscreen setting for the next connection
|
|
//
|
|
m_pUI->UI_SetStartFullScreen(m_pUI->UI_IsFullScreen());
|
|
|
|
|
|
hr = get_ExtendedDisconnectReason(&exReason);
|
|
if (FAILED(hr)) {
|
|
exReason = exDiscReasonNoInfo;
|
|
}
|
|
|
|
//
|
|
// Give autoreconnection a chance
|
|
//
|
|
_arcManager.OnNotifyDisconnected(disconnectReason,
|
|
exReason,
|
|
&fContinue);
|
|
|
|
if (!fContinue) {
|
|
TRC_NRM((TB,_T("OnNotifyDisconnected bailing out due to arc")));
|
|
rc = TRUE;
|
|
goto bail_out;
|
|
}
|
|
|
|
//
|
|
// This is a real disconnection and we've passed all attempts
|
|
// to autoreconnect so clear the autoreconnect cookie
|
|
//
|
|
m_pUI->UI_SetAutoReconnectCookie(NULL, 0);
|
|
|
|
//
|
|
// Notify the core that autoreconnect has ended
|
|
//
|
|
m_pUI->UI_OnAutoReconnectStopped();
|
|
|
|
//
|
|
// Ensure the attempt count is reset for next time
|
|
//
|
|
_arcManager.ResetArcAttempts();
|
|
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_Disconnected( disconnectReason);
|
|
|
|
if (0 == Release()) {
|
|
|
|
//
|
|
// We got deleted on return from the event
|
|
// i.e. the container released it's last ref to us
|
|
// in the event handler. Bail out now
|
|
//
|
|
|
|
//
|
|
// Return code set to 0 indicates caller should not
|
|
// touch any instance data
|
|
//
|
|
rc = FALSE;
|
|
goto bail_out;
|
|
}
|
|
|
|
if (!m_pUI->UI_GetContainerHandledFullScreen())
|
|
{
|
|
//
|
|
// If it's not a container handled fullscreen
|
|
// then leave fullscreen mode on disconected
|
|
//
|
|
// The reasoning is that containers like the web pages
|
|
// and the MMC snapin, won't have to reimplement this code
|
|
// as a listen for the event followed by leave fullscreen.
|
|
//
|
|
// More sophisticated containers like clshell will want
|
|
// fine grained control over this
|
|
//
|
|
|
|
internal_PutFullScreen(FALSE, //leave fullscreen
|
|
TRUE //Force a toggle
|
|
);
|
|
}
|
|
|
|
m_ConnectionMode = CONNECTIONMODE_INITIATE;
|
|
m_SalemConnectedSocket = INVALID_SOCKET; // let core close this handle
|
|
|
|
SetInControlLock(FALSE);
|
|
|
|
rc = TRUE;
|
|
|
|
bail_out:
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyGoneFullScreen
|
|
/*
|
|
/* Purpose: Handler for WM_TS_DISCONNECTED
|
|
/* Notifys container that core has disconnected
|
|
/* wParam contains the disconnect reason
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyGoneFullScreen(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_EnterFullScreenMode();
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyLeftFullScreen
|
|
/*
|
|
/* Purpose: Handler for WM_TS_DISCONNECTED
|
|
/* Notifys container that core has disconnected
|
|
/* wParam contains the disconnect reason
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyLeftFullScreen(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_LeaveFullScreenMode();
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyRequestFullScreen
|
|
/*
|
|
/* Purpose: Handler for WM_TS_REQUESTFULLSCREEN
|
|
/* Notifys container that core has requested to go to/from
|
|
/* fullscreen.
|
|
/* Only sent if user set ContainerHandledFullScreen in
|
|
/* the advanced settings
|
|
/*
|
|
/* wParam is 1 if GO full screen is requested
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyRequestFullScreen(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
if (wParam)
|
|
{
|
|
AddRef();
|
|
Fire_RequestGoFullScreen();
|
|
Release();
|
|
}
|
|
else
|
|
{
|
|
AddRef();
|
|
Fire_RequestLeaveFullScreen();
|
|
Release();
|
|
}
|
|
SetInControlLock(FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyFatalError
|
|
/*
|
|
/* Purpose: Handler for WM_TS_FATALERROR
|
|
/* Notifys container that fatal error has occured
|
|
/*
|
|
/* wParam is contains the error code
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyFatalError(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_FatalError((LONG)wParam);
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyWarning
|
|
/*
|
|
/* Purpose: Handler for WM_TS_WARNING
|
|
/* Notifys container that a warning has been issued from core
|
|
/* e.g if bitmap cache on disk becomes corrupted...these are
|
|
/* non-fatal errors
|
|
/*
|
|
/* wParam is contains the warning code
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyWarning(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_Warning((LONG)wParam);
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyDesktopSizeChange
|
|
/*
|
|
/* Purpose: Handler for WM_TS_DESKTOPSIZECHANGE
|
|
/* Notifys container that desktop size has changed due to a shadow
|
|
/*
|
|
/* wParam - new width
|
|
// lParam - new height
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyDesktopSizeChange(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_RemoteDesktopSizeChange((LONG)wParam, (LONG)lParam);
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyIdleTimeout
|
|
/*
|
|
/* Purpose: Handler for WM_TS_IDLETIMEOUTNOTIFICATION
|
|
/* Notifys container that idle timeout has elapsed with no input
|
|
/*
|
|
/*
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyIdleTimeout(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_IdleTimeout();
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyRequestMinimize
|
|
/*
|
|
/* Purpose: Handler for WM_TS_REQUESTMINIMIZE
|
|
/* Notifys container that a minimize is requested
|
|
/* (e.g. from the BBar)
|
|
/*
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyRequestMinimize(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
if(m_pUI && m_pUI->UI_IsFullScreen())
|
|
{
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
|
|
Fire_RequestContainerMinimize();
|
|
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Handler for WM_TS_ASKCONFIRMCLOSE
|
|
//
|
|
// Fire an event to the container requesting if it's ok to proceed
|
|
// with an end session or not (typically the container will pop UI
|
|
// for this to the user).
|
|
//
|
|
// Params:
|
|
// [IN/OUT] wParam - pointer to bool that TRUE == close ok
|
|
//
|
|
//
|
|
LRESULT CMsTscAx::OnAskConfirmClose(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
BOOL fAllowCloseToProceed = VB_TRUE;
|
|
HRESULT hr = E_FAIL;
|
|
PBOOL pfClose = (PBOOL)wParam;
|
|
|
|
hr = Fire_OnConfirmClose( &fAllowCloseToProceed );
|
|
if (FAILED(hr))
|
|
{
|
|
// On fail always assume it's ok to close
|
|
// to prevent app hanging (E.g container may not
|
|
// handle this event)
|
|
fAllowCloseToProceed = TRUE;
|
|
}
|
|
|
|
if(pfClose)
|
|
{
|
|
*pfClose = (fAllowCloseToProceed != 0);
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyReceivedPublicKey
|
|
/*
|
|
/* Purpose: Handler for WM_TS_RECEIVEDPUBLICKEY
|
|
/*
|
|
/* Parameter: wParam : Length of TS public key.
|
|
/* lParam : Pointer to TS public key.
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyReceivedPublicKey(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
VARIANT_BOOL fContinueLogon = VARIANT_TRUE;
|
|
BSTR bstrTSPublicKey = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
//
|
|
// Do not fire this notification in the redist control as it is not
|
|
// needed
|
|
//
|
|
#ifndef REDIST_CONTROL
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
|
|
bstrTSPublicKey = ::SysAllocStringByteLen( (LPCSTR)lParam,
|
|
wParam);
|
|
//
|
|
// If we failed to allocate memory, return FALSE to stop
|
|
// logon process so we don't have a security issue.
|
|
//
|
|
if( bstrTSPublicKey )
|
|
{
|
|
Fire_OnReceivedPublicKey(bstrTSPublicKey, &fContinueLogon);
|
|
SysFreeString( bstrTSPublicKey );
|
|
}
|
|
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
#endif
|
|
|
|
|
|
// Return 1 for continue logon, return 0 for stop logon
|
|
return (fContinueLogon != 0) ? 1 : 0;
|
|
}
|
|
|
|
/**PROC+*********************************************************************/
|
|
/* Name: OnNotifyChanDataReceived */
|
|
/* */
|
|
/* Purpose: Handler for WM_VCHANNEL_DATARECEIVED. */
|
|
/* Notifys container that virtual channel data was received */
|
|
/* wParam contains chanel index */
|
|
/* lParam contains received data in BSTR form */
|
|
/* */
|
|
/**PROC-*********************************************************************/
|
|
LRESULT CMsTscAx::OnNotifyChanDataReceived(UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
UNREFERENCED_PARAMETER(bHandled);
|
|
|
|
USES_CONVERSION;
|
|
|
|
OLECHAR* pOleName = NULL;
|
|
DC_BEGIN_FN("OnNotifyChanDataReceived");
|
|
DCUINT chanIndex = (DCINT) wParam;
|
|
TRC_ASSERT((chanIndex < _VChans._ChanCount),
|
|
(TB,_T("chanIndex out of range!!!")));
|
|
|
|
if (chanIndex >= _VChans._ChanCount)
|
|
{
|
|
TRC_DBG((TB,_T("chanIndex out of range\n")));
|
|
return 0;
|
|
}
|
|
|
|
__try {
|
|
pOleName = A2OLE(_VChans._pChanInfo[chanIndex].chanName);
|
|
}
|
|
__except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH) {
|
|
_resetstkoflw();
|
|
pOleName = NULL;
|
|
}
|
|
|
|
if (!pOleName) {
|
|
TRC_DBG((TB,_T("Out of memory on A2OLE")));
|
|
return 0;
|
|
}
|
|
BSTR chanName = SysAllocString(pOleName);
|
|
BSTR chanData = (BSTR) lParam;
|
|
ATLASSERT(chanData && chanName);
|
|
if(chanData && chanName)
|
|
{
|
|
//
|
|
// Notify the container
|
|
//
|
|
SetInControlLock(TRUE);
|
|
AddRef();
|
|
Fire_ChannelReceivedData(chanName, chanData);
|
|
Release();
|
|
SetInControlLock(FALSE);
|
|
|
|
SysFreeString(chanData);
|
|
SysFreeString(chanName);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DC_END_FN();
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Checks that the rentry lock is not held
|
|
// making it ok to enter this function
|
|
//
|
|
BOOL CMsTscAx::CheckReentryLock()
|
|
{
|
|
BOOL fReentryLockHeld = GetInControlLock();
|
|
|
|
//
|
|
// Assert that the lock is NOT held
|
|
// note, the lock does not need to be thread safe
|
|
// as the interface is only ever accessed from the STA thread.
|
|
//
|
|
// The main purpose of this lock is to ensure we don't reenter
|
|
// certain critical methods while the lock is held.
|
|
//
|
|
ATLASSERT(!fReentryLockHeld);
|
|
return fReentryLockHeld;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Implementation of IMsRdpClient methods
|
|
// (this extends IMsTscAx for new functionality)
|
|
// it is the new default interface for the control
|
|
//
|
|
|
|
//
|
|
// ColorDepth property
|
|
// Sets the colordepth in bpp
|
|
//
|
|
STDMETHODIMP CMsTscAx::put_ColorDepth(LONG colorDepth)
|
|
{
|
|
DC_BEGIN_FN("put_ColorDepth");
|
|
if(!IsControlDisconnected())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
LONG colorDepthID = CO_BITSPERPEL8 ;
|
|
// Convert bpp colordepth to colordepthID
|
|
//
|
|
switch (colorDepth)
|
|
{
|
|
case 8:
|
|
{
|
|
colorDepthID = CO_BITSPERPEL8;
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
{
|
|
colorDepthID = CO_BITSPERPEL15;
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
{
|
|
colorDepthID = CO_BITSPERPEL16;
|
|
}
|
|
break;
|
|
|
|
case 24:
|
|
case 32:
|
|
{
|
|
colorDepthID = CO_BITSPERPEL24;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
default:
|
|
{
|
|
TRC_ERR((TB,_T("color depth %d unsupported\n"), colorDepthID));
|
|
return E_INVALIDARG;
|
|
}
|
|
break;
|
|
}
|
|
|
|
m_pUI->_UI.colorDepthID = colorDepthID;
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// ColorDepth property
|
|
// retrieves the colordepth
|
|
//
|
|
STDMETHODIMP CMsTscAx::get_ColorDepth(LONG* pcolorDepth)
|
|
{
|
|
LONG colorDepthBpp = 8;
|
|
if(!m_pUI)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
if(!pcolorDepth)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
switch(m_pUI->_UI.colorDepthID)
|
|
{
|
|
case CO_BITSPERPEL4:
|
|
colorDepthBpp = 4;
|
|
break;
|
|
case CO_BITSPERPEL8:
|
|
colorDepthBpp = 8;
|
|
break;
|
|
case CO_BITSPERPEL15:
|
|
colorDepthBpp = 15;
|
|
break;
|
|
case CO_BITSPERPEL16:
|
|
colorDepthBpp = 16;
|
|
break;
|
|
case CO_BITSPERPEL24:
|
|
colorDepthBpp = 24;
|
|
break;
|
|
}
|
|
|
|
*pcolorDepth = colorDepthBpp;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// SendKeys control method (non scriptable)
|
|
// atomically injects keys to the control window
|
|
//
|
|
// Params: (three parallel arrays)
|
|
// numKeys - number of keys to inject
|
|
// pbArrayKeyUp - boolean true for key is up
|
|
// plKeyData - long key data (lParam of WM_KEYDOWN msg)
|
|
// i.e this is the scancode
|
|
//
|
|
//
|
|
//
|
|
// Restrict the max number of keys that can be sent
|
|
// in one atomic opperation (to prevent this method blocking for too long).
|
|
//
|
|
// This method is non scriptable as a security measure to prevent
|
|
// web pages injecting keys to launch programs without the user's
|
|
// knowledge.
|
|
//
|
|
#define MAX_SENDVIRTUAL_KEYS 20
|
|
|
|
STDMETHODIMP CMsTscAx::SendKeys(/*[in]*/ LONG numKeys,
|
|
/*[in]*/ VARIANT_BOOL* pbArrayKeyUp,
|
|
/*[in]*/ LONG* plKeyData)
|
|
{
|
|
DC_BEGIN_FN("SendVirtualKeys");
|
|
HWND hwndInput;
|
|
|
|
if(!IsControlConnected() || !m_pUI)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
hwndInput = m_pUI->UI_GetInputWndHandle();
|
|
if(!hwndInput)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if(numKeys > MAX_SENDVIRTUAL_KEYS)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if(pbArrayKeyUp && plKeyData)
|
|
{
|
|
//Decouple the call to the IH to do the work
|
|
if (m_pUI->UI_InjectVKeys(numKeys,
|
|
pbArrayKeyUp,
|
|
plKeyData))
|
|
{
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("UI_InjectVKeys returned failure")));
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Invalid arguments (one of more null arrays)")));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// get_AdvancedSettings2
|
|
// Retrieves the v2 advanced settings interface (IMsRdpClientAdvancedSettings)
|
|
//
|
|
//
|
|
STDMETHODIMP CMsTscAx::get_AdvancedSettings2(
|
|
IMsRdpClientAdvancedSettings** ppAdvSettings)
|
|
{
|
|
DC_BEGIN_FN("get_AdvancedSettings2");
|
|
|
|
HRESULT hr = E_FAIL;
|
|
if (!ppAdvSettings)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
IMsTscAdvancedSettings* pOldAdvSettings = NULL;
|
|
hr = get_AdvancedSettings( &pOldAdvSettings);
|
|
TRC_ASSERT(pOldAdvSettings,(TB,_T("get_AdvancedSettings ret null iface")));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pOldAdvSettings->QueryInterface(
|
|
IID_IMsRdpClientAdvancedSettings,
|
|
(void**)ppAdvSettings);
|
|
pOldAdvSettings->Release();
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// get_AdvancedSettings3
|
|
// Retrieves the v3 advanced settings interface (IMsRdpClientAdvancedSettings)
|
|
//
|
|
//
|
|
STDMETHODIMP CMsTscAx::get_AdvancedSettings3(
|
|
IMsRdpClientAdvancedSettings2** ppAdvSettings)
|
|
{
|
|
DC_BEGIN_FN("get_AdvancedSettings2");
|
|
|
|
HRESULT hr = E_FAIL;
|
|
if (!ppAdvSettings)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
IMsTscAdvancedSettings* pOldAdvSettings = NULL;
|
|
hr = get_AdvancedSettings( &pOldAdvSettings);
|
|
TRC_ASSERT(pOldAdvSettings,(TB,_T("get_AdvancedSettings2 ret null iface")));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pOldAdvSettings->QueryInterface(
|
|
IID_IMsRdpClientAdvancedSettings2,
|
|
(void**)ppAdvSettings);
|
|
pOldAdvSettings->Release();
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// get_AdvancedSettings4
|
|
// Retrieves the v4 advanced settings interface (IMsRdpClientAdvancedSettings3)
|
|
//
|
|
//
|
|
STDMETHODIMP CMsTscAx::get_AdvancedSettings4(
|
|
IMsRdpClientAdvancedSettings3** ppAdvSettings)
|
|
{
|
|
DC_BEGIN_FN("get_AdvancedSettings2");
|
|
|
|
HRESULT hr = E_FAIL;
|
|
if (!ppAdvSettings)
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
IMsTscAdvancedSettings* pOldAdvSettings = NULL;
|
|
hr = get_AdvancedSettings( &pOldAdvSettings);
|
|
TRC_ASSERT(pOldAdvSettings,(TB,_T("get_AdvancedSettings ret null iface")));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pOldAdvSettings->QueryInterface(
|
|
IID_IMsRdpClientAdvancedSettings3,
|
|
(void**)ppAdvSettings);
|
|
pOldAdvSettings->Release();
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CMsTscAx::get_ExtendedDisconnectReason(/*[out]*/
|
|
ExtendedDisconnectReasonCode* pExtendedDisconnectReason)
|
|
{
|
|
DC_BEGIN_FN("get_ExtendedDisconnectReason");
|
|
if(pExtendedDisconnectReason)
|
|
{
|
|
*pExtendedDisconnectReason = (ExtendedDisconnectReasonCode)
|
|
m_pUI->UI_GetServerErrorInfo();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// put/get FullScreen fully scriptable versions for Whistler
|
|
//
|
|
STDMETHODIMP CMsTscAx::put_FullScreen(/*[in]*/ VARIANT_BOOL fFullScreen)
|
|
{
|
|
return internal_PutFullScreen(fFullScreen);
|
|
}
|
|
|
|
STDMETHODIMP CMsTscAx::get_FullScreen(/*[in]*/ VARIANT_BOOL* pfFullScreen)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fFscreen;
|
|
if (pfFullScreen)
|
|
{
|
|
hr = internal_GetFullScreen(&fFscreen);
|
|
*pfFullScreen = (VARIANT_BOOL)fFscreen;
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Override IOleObjectImpl::DoVerbInPlaceActivate to workaround
|
|
// ATL bugs (VisualStudio7 #5786 & #181708)
|
|
//
|
|
// Basically without this FireViewChange can crash in stress if
|
|
// the window allocation fails. The symptom will be a jump thru
|
|
// a bogus vtable in stress.
|
|
//
|
|
HRESULT CMsTscAx::DoVerbInPlaceActivate(LPCRECT prcPosRect,
|
|
HWND /* hwndParent */)
|
|
{
|
|
HRESULT hr;
|
|
hr = OnPreVerbInPlaceActivate();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = InPlaceActivate(OLEIVERB_INPLACEACTIVATE, prcPosRect);
|
|
|
|
//
|
|
// Added these lines to check for hWnd creation success
|
|
//
|
|
if (!m_bWndLess && !m_hWndCD)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = OnPostVerbInPlaceActivate();
|
|
if (SUCCEEDED(hr))
|
|
FireViewChange();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* Purpose : This is Salem specific call to support reverse connection */
|
|
/* pcHealth must have invoke necessary routine in Salem to */
|
|
/* connection with TermSrv and then instruct Salem to pass this */
|
|
/* connection to ActiveX control to begin login sequence */
|
|
/* */
|
|
/* Param : IN hConnectedSocket - Connected socket or INVALID_SOCKET */
|
|
/* to reset back to initate connection mode. */
|
|
/*****************************************************************************/
|
|
HRESULT CMsTscAx::SetConnectWithEndpoint( SOCKET hConnectedSocket )
|
|
{
|
|
#if defined(REDIST_CONTROL) || defined(OS_WINCE)
|
|
|
|
return E_NOTIMPL;
|
|
|
|
#else
|
|
|
|
HRESULT hr;
|
|
|
|
if( _ConnectionState == tscNotConnected )
|
|
{
|
|
hr = S_OK;
|
|
if( INVALID_SOCKET == hConnectedSocket )
|
|
{
|
|
m_ConnectionMode = CONNECTIONMODE_INITIATE;
|
|
}
|
|
else
|
|
{
|
|
m_ConnectionMode = CONNECTIONMODE_CONNECTEDENDPOINT;
|
|
m_SalemConnectedSocket = hConnectedSocket;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_ABORT;
|
|
}
|
|
|
|
return hr;
|
|
|
|
#endif
|
|
}
|
|
|
|
#ifdef OS_WINCE
|
|
// Builds of the WinCE don't have to include URLMON component and hence wouldn't
|
|
// have these set in uuid.lib. Name resolution is handled by keeping mstscax
|
|
// as a SOURCESLIB and uuid.lib as a TARGETLIB.
|
|
|
|
EXTERN_C const IID CLSID_InternetSecurityManager = {0x7b8a2d94,0x0ac9,0x11d1,{0x89,0x6c,0x00,0xc0,0x4F,0xb6,0xbf,0xc4}};
|
|
EXTERN_C const IID IID_IInternetSecurityManager = {0x79eac9ee,0xbaf9,0x11ce,{0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b}};
|
|
|
|
#endif
|