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.
3577 lines
100 KiB
3577 lines
100 KiB
//
|
|
// uiapi.cpp
|
|
//
|
|
// UI Class
|
|
//
|
|
// Copyright (C) 1997-2000 Microsoft Corporation
|
|
//
|
|
|
|
#include <adcg.h>
|
|
#define TRC_GROUP TRC_GROUP_UI
|
|
#define TRC_FILE "uiapi"
|
|
#include <atrcapi.h>
|
|
|
|
#include "wui.h"
|
|
|
|
#ifdef OS_WINCE
|
|
#include <ceconfig.h>
|
|
#endif
|
|
|
|
extern "C"
|
|
{
|
|
#ifndef OS_WINCE
|
|
#include <stdio.h>
|
|
#endif // OS_WINCE
|
|
}
|
|
|
|
#include "clx.h"
|
|
#include "aco.h"
|
|
#include "nl.h"
|
|
#include "autil.h"
|
|
|
|
//
|
|
// Debugging globals
|
|
// Do not use these values for anything
|
|
// but debugging
|
|
//
|
|
CObjs* g_pTscObjects = (CObjs*)-1;
|
|
CUI* g_pUIObject = (CUI*)-1;
|
|
LONG g_cUIref = 0;
|
|
DWORD g_cUITotalCount = 0;
|
|
#define DBG_EXIT_WITHACTIVE_REFS 0x0001
|
|
#define DBG_STAT_UI_INIT_CALLED 0x0002
|
|
#define DBG_STAT_UI_INIT_RET_PASS 0x0004
|
|
#define DBG_STAT_UI_TERM_CALLED 0x0008
|
|
#define DBG_STAT_UI_TERM_RETURNED 0x0010
|
|
#define DBG_STAT_TERMTSC_SENT 0x0020
|
|
#define DBG_STAT_UIREQUESTEDCLOSE_CALLED 0x0040
|
|
#define DBG_STAT_UIREQUESTEDCLOSE_RET 0x0080
|
|
#define DBG_STAT_UI_INIT_RET_FAIL 0x0100
|
|
DWORD g_dwTscCoreDbgStatus = 0;
|
|
#define UI_DBG_SETINFO(x) g_dwTscCoreDbgStatus |= x;
|
|
|
|
CUI::CUI()
|
|
{
|
|
DC_BEGIN_FN("CUI");
|
|
|
|
DC_MEMSET(&_UI, 0, sizeof(_UI));
|
|
DC_MEMSET(&_drInitData, 0, sizeof(_drInitData));
|
|
_Objects._pUiObject = this;
|
|
|
|
//
|
|
// Only used for debugging
|
|
//
|
|
g_pTscObjects = &_Objects;
|
|
g_pUIObject = this;
|
|
|
|
#ifdef DC_DEBUG
|
|
//
|
|
// This will dump debug output if there was a problem creating objects
|
|
//
|
|
_Objects.CheckPointers();
|
|
#endif
|
|
|
|
_pCo = _Objects._pCoObject;
|
|
_pUt = _Objects._pUtObject;
|
|
_clx = _Objects._pCLXObject;
|
|
_pTd = _Objects._pTDObject;
|
|
_pIh = _Objects._pIhObject;
|
|
_pCd = _Objects._pCdObject;
|
|
_pOp = _Objects._pOPObject;
|
|
_pUh = _Objects._pUHObject;
|
|
_pCChan = _Objects._pChanObject;
|
|
|
|
#ifdef USE_BBAR
|
|
_pBBar = NULL;
|
|
_ptBBarLastMousePos.x = -0x0FFF;
|
|
_ptBBarLastMousePos.y = -0x0FFF;
|
|
_fBBarUnhideTimerActive = TRUE;
|
|
|
|
#endif
|
|
_pHostData = NULL;
|
|
_fRecursiveScrollBarMsg = FALSE;
|
|
|
|
_fRecursiveSizeMsg = FALSE;
|
|
|
|
#ifndef OS_WINCE
|
|
_dwLangBarFlags = 0;
|
|
_fLangBarWasHidden = FALSE;
|
|
_fIhHasFocus = FALSE;
|
|
_pITLBM = NULL;
|
|
_fLangBarStateSaved = FALSE;
|
|
#endif
|
|
_fTerminating = FALSE;
|
|
|
|
#ifdef DC_DEBUG
|
|
//
|
|
// Important that these are set very early
|
|
// otherwise the failure tables in UT will not be initialized
|
|
// and mallocs could fail randomly
|
|
//
|
|
|
|
UI_SetRandomFailureItem(UT_FAILURE_MALLOC, 0);
|
|
UI_SetRandomFailureItem(UT_FAILURE_MALLOC_HUGE, 0);
|
|
#endif
|
|
|
|
#ifndef OS_WINCE
|
|
_pTaskBarList2 = NULL;
|
|
_fQueriedForTaskBarList2 = FALSE;
|
|
#endif
|
|
|
|
_pArcUI = NULL;
|
|
|
|
InterlockedIncrement(&g_cUIref);
|
|
g_cUITotalCount++;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
CUI::~CUI()
|
|
{
|
|
DC_BEGIN_FN("~CUI");
|
|
|
|
if(_UI.pszVChanAddinDlls)
|
|
{
|
|
UT_Free(_pUt, _UI.pszVChanAddinDlls);
|
|
}
|
|
|
|
InterlockedDecrement(&g_cUIref);
|
|
|
|
if(_Objects.CheckActiveReferences())
|
|
{
|
|
UI_DBG_SETINFO(DBG_EXIT_WITHACTIVE_REFS);
|
|
TRC_ABORT((TB,_T("!!!!!****Deleting objs with outstanding references")));
|
|
}
|
|
|
|
#ifdef OS_WINCE
|
|
UI_SetCompress(FALSE);
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// API functions
|
|
//
|
|
|
|
//
|
|
// Name: UI_Init
|
|
//
|
|
// Purpose: Creates the Main and Container windows and initializes the
|
|
// Core and Component Decoupler
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Params: IN - hInstance - window information
|
|
// IN - hprevInstance
|
|
//
|
|
//
|
|
HRESULT DCAPI CUI::UI_Init(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
HINSTANCE hResInstance,
|
|
HANDLE hEvtNotifyCoreInit)
|
|
{
|
|
WNDCLASS mainWindowClass;
|
|
WNDCLASS containerWindowClass;
|
|
WNDCLASS tmpWndClass;
|
|
ATOM registerClassRc;
|
|
DWORD dwStyle;
|
|
DWORD dwExStyle = 0;
|
|
|
|
#ifndef OS_WINCE
|
|
OSVERSIONINFO osVersionInfo;
|
|
#endif
|
|
HRESULT hr = E_FAIL;
|
|
|
|
#if !defined(OS_WINCE) || defined(OS_WINCE_WINDOWPLACEMENT)
|
|
UINT showCmd;
|
|
#endif
|
|
BOOL fAddedRef = FALSE;
|
|
|
|
DC_BEGIN_FN("UI_Init");
|
|
|
|
_fTerminating = FALSE;
|
|
|
|
if(!_Objects.CheckPointers())
|
|
{
|
|
TRC_ERR((TB,_T("Objects not all setup")));
|
|
hr = E_OUTOFMEMORY;
|
|
DC_QUIT;
|
|
}
|
|
if(!hInstance && !hResInstance)
|
|
{
|
|
TRC_ERR((TB,_T("Instance pointer not specified")));
|
|
hr = E_OUTOFMEMORY;
|
|
DC_QUIT;
|
|
}
|
|
|
|
if(UI_IsCoreInitialized())
|
|
{
|
|
//Don't allow re-entrant core init
|
|
//one example of how this can happen
|
|
// Connect() method called.
|
|
// Core init starts
|
|
// Core init times out and fails in control
|
|
// Core completes init (and is now initialized)
|
|
// Connect() called again
|
|
hr = E_FAIL;
|
|
DC_QUIT;
|
|
}
|
|
|
|
_Objects.AddObjReference(UI_OBJECT_FLAG);
|
|
fAddedRef = TRUE;
|
|
|
|
UI_DBG_SETINFO(DBG_STAT_UI_INIT_CALLED);
|
|
|
|
//
|
|
// UI initialisation
|
|
//
|
|
TRC_DBG((TB, _T("UI initialising UT")));
|
|
_pUt->UT_Init();
|
|
|
|
//
|
|
// Resources are in the executable. Keep this separate in case the
|
|
// resources are moved to a separate DLL: in this case just call
|
|
// GetModuleHandle() to get hResDllInstance.
|
|
//
|
|
_UI.hResDllInstance = hResInstance;
|
|
TRC_ASSERT((0 != _UI.hResDllInstance), (TB,_T("Couldn't get res dll handle")));
|
|
|
|
//
|
|
// Initialize External DLL
|
|
//
|
|
_pUt->InitExternalDll();
|
|
|
|
//
|
|
// Register the class for the Main Window
|
|
//
|
|
if (!hPrevInstance &&
|
|
!GetClassInfo(hInstance, UI_MAIN_CLASS, &tmpWndClass))
|
|
{
|
|
HICON hIcon= NULL;
|
|
#if defined(OS_WIN32) && !defined(OS_WINCE)
|
|
if(_UI.szIconFile[0] != 0)
|
|
{
|
|
hIcon = ExtractIcon(hResInstance, _UI.szIconFile, _UI.iconIndex);
|
|
}
|
|
if(NULL == hIcon)
|
|
{
|
|
hIcon = LoadIcon(hResInstance, MAKEINTRESOURCE(UI_IDI_MSTSC_ICON));
|
|
}
|
|
#else
|
|
hIcon = LoadIcon(hResInstance, MAKEINTRESOURCE(UI_IDI_MSTSC_ICON));
|
|
#endif
|
|
|
|
TRC_NRM((TB, _T("Register Main Window class")));
|
|
mainWindowClass.style = 0;
|
|
mainWindowClass.lpfnWndProc = UIStaticMainWndProc;
|
|
mainWindowClass.cbClsExtra = 0;
|
|
mainWindowClass.cbWndExtra = sizeof(void*); //store 'this' pointer
|
|
mainWindowClass.hInstance = hInstance;
|
|
mainWindowClass.hIcon = hIcon;
|
|
mainWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
mainWindowClass.hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
|
|
mainWindowClass.lpszMenuName = NULL;
|
|
mainWindowClass.lpszClassName = UI_MAIN_CLASS;
|
|
|
|
registerClassRc = RegisterClass (&mainWindowClass);
|
|
|
|
if (registerClassRc == 0)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
TRC_ERR((TB,_T("RegisterClass failed: 0x%x"), hr));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef OS_WINCE
|
|
dwStyle = WS_VSCROLL |
|
|
WS_HSCROLL |
|
|
WS_CLIPCHILDREN;
|
|
#else // OS_WINCE
|
|
dwStyle = WS_VSCROLL | WS_HSCROLL | WS_CLIPCHILDREN | WS_SYSMENU;
|
|
|
|
//
|
|
// Main window is child to control main window.
|
|
//
|
|
dwStyle = dwStyle | WS_CHILD | WS_CLIPSIBLINGS;
|
|
|
|
#endif // OS_WINCE
|
|
|
|
//
|
|
// Create the main window Initialize the window size from the
|
|
// windowPlacement. Will be recalculated to allow for scrollbars or
|
|
// fullscreen mode later.
|
|
//
|
|
// Note that on Win16, the SetWindowPlacement below will cause the
|
|
// window to be shown if its position or size are changed (even though
|
|
// we explicitly specify SW_HIDE). We avoid this by setting the window
|
|
// position on creation to be the same as that set later by
|
|
// SetWindowPlacement.
|
|
//
|
|
_UI.hwndMain = CreateWindow(
|
|
UI_MAIN_CLASS, // window class name
|
|
_UI.szFullScreenTitle, // window caption
|
|
dwStyle, // window style
|
|
_UI.windowPlacement.rcNormalPosition.left,
|
|
_UI.windowPlacement.rcNormalPosition.top,
|
|
_UI.windowPlacement.rcNormalPosition.right -
|
|
_UI.windowPlacement.rcNormalPosition.left,
|
|
_UI.windowPlacement.rcNormalPosition.bottom -
|
|
_UI.windowPlacement.rcNormalPosition.top,
|
|
_UI.hWndCntrl, // parent window handle
|
|
NULL, // window menu handle
|
|
hInstance, // program inst handle
|
|
this ); // creation parameters
|
|
|
|
TRC_NRM((TB, _T("Main Window handle: %p"), _UI.hwndMain));
|
|
|
|
if (_UI.hwndMain == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
TRC_ERR((TB,_T("CreateWindow failed: 0x%x"), hr));
|
|
DC_QUIT;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
HMENU hSysMenu = GetSystemMenu( _UI.hwndMain, FALSE);
|
|
if(hSysMenu)
|
|
{
|
|
//
|
|
// Always disable the move item on the window menu
|
|
// Window menu only appears if the control goes fullscreen
|
|
// in the non-container handled fullscreen case.
|
|
//
|
|
EnableMenuItem((HMENU)hSysMenu, SC_MOVE,
|
|
MF_GRAYED | MF_BYCOMMAND);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Register the Container class
|
|
//
|
|
TRC_DBG((TB, _T("Registering Container window class")));
|
|
if (!hPrevInstance &&
|
|
!GetClassInfo(hInstance, UI_CONTAINER_CLASS, &tmpWndClass))
|
|
{
|
|
TRC_NRM((TB, _T("Register class")));
|
|
containerWindowClass.style = CS_HREDRAW | CS_VREDRAW;
|
|
containerWindowClass.lpfnWndProc = UIStaticContainerWndProc;
|
|
containerWindowClass.cbClsExtra = 0;
|
|
containerWindowClass.cbWndExtra = sizeof(void*); //store 'this'
|
|
containerWindowClass.hInstance = hInstance;
|
|
containerWindowClass.hIcon = NULL;
|
|
containerWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
containerWindowClass.hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
|
|
containerWindowClass.lpszMenuName = NULL;
|
|
containerWindowClass.lpszClassName = UI_CONTAINER_CLASS;
|
|
|
|
registerClassRc = RegisterClass(&containerWindowClass);
|
|
|
|
if (registerClassRc == 0)
|
|
{
|
|
//
|
|
// Failed to register container window so terminate app
|
|
//
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
TRC_ERR((TB,_T("RegisterClass failed: 0x%x"), hr));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
|
|
dwExStyle = WS_EX_NOPARENTNOTIFY;
|
|
if (GetVersionEx(&osVersionInfo) &&
|
|
osVersionInfo.dwMajorVersion >= 5)
|
|
{
|
|
//
|
|
// Only allow this style on NT5+ as otherwise the
|
|
// create window can fail
|
|
//
|
|
dwExStyle |= WS_EX_NOINHERITLAYOUT;
|
|
}
|
|
#else
|
|
dwExStyle = 0;
|
|
#endif
|
|
|
|
//
|
|
// Create the Container Window
|
|
//
|
|
TRC_DBG((TB, _T("Creating Container Window")));
|
|
_UI.hwndContainer = CreateWindowEx(
|
|
dwExStyle,
|
|
UI_CONTAINER_CLASS,
|
|
NULL,
|
|
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
|
0,
|
|
0,
|
|
_UI.containerSize.width,
|
|
_UI.containerSize.height,
|
|
_UI.hwndMain,
|
|
NULL,
|
|
hInstance,
|
|
this );
|
|
|
|
if (_UI.hwndContainer == NULL)
|
|
{
|
|
//
|
|
// Failed to create container window so terminate app
|
|
//
|
|
TRC_ERR((TB,_T("CreateWindowEx for container failed 0x%x"),
|
|
GetLastError()));
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
TRC_ERR((TB,_T("CreateWindowEx failed: 0x%x"), hr));
|
|
DC_QUIT;
|
|
}
|
|
|
|
#if defined (OS_WINCE)
|
|
/********************************************************************/
|
|
/* Disable IME */
|
|
/* IME is different on 98/NT than on WinCE, on 98/NT one call to */
|
|
/* DisableIME is enough for entire process, on WinCE we must call it*/
|
|
/* on each window thread that is running to disable it. */
|
|
/********************************************************************/
|
|
DisableIME(_UI.hwndContainer);
|
|
#endif
|
|
|
|
#if !defined(OS_WINCE) || defined(OS_WINCE_WINDOWPLACEMENT)
|
|
UISetMinMaxPlacement();
|
|
showCmd = _UI.windowPlacement.showCmd;
|
|
_UI.windowPlacement.showCmd = SW_HIDE;
|
|
SetWindowPlacement(_UI.hwndMain, &_UI.windowPlacement);
|
|
_UI.windowPlacement.showCmd = showCmd;
|
|
#endif // !defined(OS_WINCE) || defined(OS_WINCE_WINDOWPLACEMENT)
|
|
|
|
UISmoothScrollingSettingChanged();
|
|
|
|
#ifndef OS_WINCE
|
|
//
|
|
// Set up our lovely Cicero interface
|
|
//
|
|
HRESULT hrLangBar = CoCreateInstance(CLSID_TF_LangBarMgr, NULL,
|
|
CLSCTX_INPROC_SERVER, IID_ITfLangBarMgr, (void **)&_pITLBM);
|
|
TRC_DBG((TB, _T("CoCreateInstance(CLSID_TF_LangBarMgr) hr= 0x%08xl"), hr));
|
|
if (FAILED(hrLangBar))
|
|
{
|
|
_pITLBM = NULL;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Initialize Core, much of this will happen
|
|
// asynchrously. An event will be signaled when core init has completed
|
|
//
|
|
TRC_DBG((TB, _T("UI Initialising Core")));
|
|
_pCo->CO_Init(hInstance, _UI.hwndMain, _UI.hwndContainer);
|
|
|
|
UI_DBG_SETINFO(DBG_STAT_UI_INIT_RET_PASS);
|
|
hr = S_OK;
|
|
|
|
if (!DuplicateHandle(
|
|
GetCurrentProcess(),
|
|
hEvtNotifyCoreInit,
|
|
GetCurrentProcess(),
|
|
&_UI.hEvtNotifyCoreInit,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS)) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// Hack: Increment the objects reference count as it will be
|
|
// released again on UI_TERM
|
|
_Objects.AddObjReference(UI_OBJECT_FLAG);
|
|
|
|
TRC_ERR((TB, _T("Duplicate handle call failed. hr = 0x%x"), hr));
|
|
DC_QUIT;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
if (FAILED(hr))
|
|
{
|
|
if (fAddedRef)
|
|
{
|
|
_Objects.ReleaseObjReference(UI_OBJECT_FLAG);
|
|
}
|
|
UI_DBG_SETINFO(DBG_STAT_UI_INIT_RET_FAIL);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Name: UI_ResetState
|
|
//
|
|
// Purpose: Resets all UI state in this component
|
|
//
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: Nothing
|
|
//
|
|
//
|
|
//
|
|
DCVOID DCAPI CUI::UI_ResetState()
|
|
{
|
|
DC_MEMSET(&_UI, 0, sizeof(_UI));
|
|
DC_MEMSET(&_drInitData, 0, sizeof(_drInitData));
|
|
UIInitializeDefaultSettings();
|
|
}
|
|
|
|
//
|
|
// Name: UI_Connect
|
|
//
|
|
// Purpose: Connects with current settings
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Params: Nothing
|
|
//
|
|
//
|
|
//
|
|
HRESULT DCAPI CUI::UI_Connect(CONNECTIONMODE connMode)
|
|
{
|
|
DC_BEGIN_FN("UI_Connect");
|
|
|
|
if(!UI_IsCoreInitialized())
|
|
{
|
|
TRC_ERR((TB,_T("Attempt to connect before core intialize")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//Reset server error state
|
|
UI_SetServerErrorInfo( TS_ERRINFO_NOERROR );
|
|
|
|
//Initialiaze the RDPDR settings struct
|
|
//this gets reset on each connection
|
|
//rdpdr gets passed down a pointer to the struct
|
|
//when it is initialized
|
|
UI_InitRdpDrSettings();
|
|
|
|
//Clean up the load balance redirect state
|
|
if (!UI_IsAutoReconnecting()) {
|
|
TRC_NRM((TB,_T("Cleaning up LB state")));
|
|
UI_CleanupLBState();
|
|
}
|
|
else {
|
|
TRC_NRM((TB,_T("AutoReconnecting don't cleanup lb state")));
|
|
}
|
|
|
|
|
|
_fRecursiveSizeMsg = FALSE;
|
|
#ifndef OS_WINCE
|
|
_fLangBarStateSaved = FALSE;
|
|
#endif
|
|
|
|
InitInputIdleTimer( UI_GetMinsToIdleTimeout() );
|
|
|
|
_fRecursiveScrollBarMsg = FALSE;
|
|
|
|
if (UIValidateCurrentParams(connMode))
|
|
{
|
|
TRC_NRM((TB, _T("Connecting")));
|
|
|
|
UISetConnectionStatus(UI_STATUS_DISCONNECTED);
|
|
_pCo->CO_SetConfigurationValue( CO_CFG_ACCELERATOR_PASSTHROUGH,
|
|
_UI.acceleratorCheckState );
|
|
_pCo->CO_SetHotkey(&(_UI.hotKey));
|
|
_pCo->CO_SetConfigurationValue( CO_CFG_ENCRYPTION,
|
|
_UI.encryptionEnabled);
|
|
UIShadowBitmapSettingChanged();
|
|
#ifdef DC_DEBUG
|
|
UI_CoreDebugSettingChanged();
|
|
#endif // DC_DEBUG
|
|
|
|
|
|
#ifdef USE_BBAR
|
|
if(!_pBBar)
|
|
{
|
|
_pBBar = new CBBar( _UI.hwndMain,
|
|
UI_GetInstanceHandle(),
|
|
this,
|
|
_UI.fBBarEnabled);
|
|
}
|
|
|
|
if(!_pBBar)
|
|
{
|
|
TRC_ERR((TB,_T("Alloc for CBBar failed")));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
_pBBar->SetPinned( _UI.fBBarPinned );
|
|
_pBBar->SetShowMinimize(UI_GetBBarShowMinimize());
|
|
_pBBar->SetShowRestore(UI_GetBBarShowRestore());
|
|
|
|
//
|
|
// Set the display name here instead of OnConnected so it
|
|
// doesn't change w.r.t to redirections (which can change strAddress)
|
|
//
|
|
_pBBar->SetDisplayedText( _UI.strAddress );
|
|
#endif
|
|
|
|
//
|
|
// Errors from the connection are
|
|
// signaled by Disconnect's that are fired
|
|
// with the appropriate disconnect code
|
|
//
|
|
UIConnectWithCurrentParams(connMode);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
TRC_ALT((TB, _T("UIValidateCurrentParams failed: not auto-connecting")));
|
|
return E_FAIL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Name: UI_Term
|
|
//
|
|
// Purpose: Calls _pCo->CO_Term and CD_Term and destroys the main window
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Params: None
|
|
//
|
|
//
|
|
HRESULT DCAPI CUI::UI_Term(DCVOID)
|
|
{
|
|
HWND hwndTmp = NULL;
|
|
HWND hwndHasFocus = NULL;
|
|
|
|
DC_BEGIN_FN("UI_Term");
|
|
|
|
UI_DBG_SETINFO(DBG_STAT_UI_TERM_CALLED);
|
|
|
|
if(!UI_IsCoreInitialized())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
_fTerminating = TRUE;
|
|
|
|
#ifdef OS_WINCE
|
|
//
|
|
// Some device are failing to restore the correct palette when the TSC
|
|
// exits. In an attempt to correct this behavior, we'll send the
|
|
// necessary message to the shell that will prompt its DefWindowProc to
|
|
// re-realize the correct palette. Non WBT only
|
|
//
|
|
|
|
if (g_CEConfig != CE_CONFIG_WBT)
|
|
{
|
|
hwndTmp = FindWindow(TEXT("DesktopExplorerWindow"), 0);
|
|
if(0 != hwndTmp)
|
|
{
|
|
PostMessage(hwndTmp, WM_QUERYNEWPALETTE, 0, 0);
|
|
hwndTmp = 0;
|
|
}
|
|
}
|
|
#endif // OS_WINCE
|
|
|
|
//
|
|
// Here's a problem. - _pCo->CO_Term terminates the SND thread (causes
|
|
// call to SND_Term) - SND_Term calls IH_Term - IH_Term calls
|
|
// DestroyWindow to destroy the input window - Because the input window
|
|
// has the focus, DestroyWindow calls SendMessage to set the focus to
|
|
// its parent.
|
|
//
|
|
// Now we have a deadly embrace: UI thread is waiting for SND thread to
|
|
// terminate; SND thread is waiting for UI thread to process
|
|
// SendMessage.
|
|
//
|
|
// The solution is to set the focus to the UI window here, so that the
|
|
// input window no longer has the focus when it is destroyed, so that
|
|
// DestroyWindow doesn't call SendMessage.
|
|
//
|
|
// WinCE has the additional problem that it doesn't set the focus to
|
|
// another application correctly when mstsc exits. (Something about
|
|
// not being able to SendMessage a WM_FOCUS during thread exit). So in
|
|
// that case we hide the main window, which removes the need for a
|
|
// separate SetFocus call.
|
|
//
|
|
#ifndef OS_WINCE
|
|
//
|
|
// Only steal the focus if our IH has it, otherwise
|
|
// there is no deadlock above. The main reason for not stealing
|
|
// the focus is that in mutli-instance environments e.g the MMC snapin
|
|
// stealing focus from another session is a bad thing (especially if the
|
|
// session we are stealing the focus from is the one the user is working on)
|
|
//
|
|
hwndHasFocus = GetFocus();
|
|
if(hwndHasFocus &&
|
|
(hwndHasFocus == UI_GetInputWndHandle() ||
|
|
hwndHasFocus == UI_GetBmpCacheMonitorHandle()))
|
|
{
|
|
TRC_NRM((TB,_T("Setting focus to main window to prevent deadlock")));
|
|
SetFocus(_UI.hwndMain);
|
|
}
|
|
#else // OS_WINCE
|
|
ShowWindow(_UI.hwndMain, SW_HIDE);
|
|
#endif // OS_WINCE
|
|
|
|
|
|
ShowWindow(_UI.hwndMain, SW_HIDE);
|
|
|
|
//
|
|
// The next lines appear to Destroy the windows OK. In the past this
|
|
// has not been the case. If the process hangs in future then the fix
|
|
// is to comment out the DestroyWindows.
|
|
//
|
|
// Note we null out our copies of the window handle before doing the
|
|
// destroy to stop anyone accessing it during the detroy processing.
|
|
//
|
|
|
|
//
|
|
// Very important to destory the windows before terminating the core
|
|
// to prevent messages from getting processed while we are terminating
|
|
//
|
|
TRC_NRM((TB, _T("Destroying windows...")));
|
|
|
|
hwndTmp = _UI.hwndContainer;
|
|
_UI.hwndContainer = NULL;
|
|
|
|
if(hwndTmp)
|
|
{
|
|
DestroyWindow(hwndTmp);
|
|
}
|
|
|
|
hwndTmp = _UI.hwndMain;
|
|
_UI.hwndMain = NULL;
|
|
|
|
if(hwndTmp)
|
|
{
|
|
DestroyWindow(hwndTmp);
|
|
}
|
|
|
|
//
|
|
// Terminate the Core and Component Decoupler
|
|
//
|
|
TRC_DBG((TB, _T("UI Terminating Core")));
|
|
_pCo->CO_Term();
|
|
|
|
|
|
//
|
|
// Free the decompression receive context (if any)
|
|
//
|
|
if (_UI.pRecvContext2) {
|
|
UT_Free(_pUt, _UI.pRecvContext2);
|
|
_UI.pRecvContext2 = NULL;
|
|
}
|
|
|
|
//
|
|
// Clear and free any autoreconnect cookies
|
|
//
|
|
UI_SetAutoReconnectCookie(NULL, 0);
|
|
|
|
|
|
TRC_NRM((TB, _T("Destroyed windows")));
|
|
|
|
UnregisterClass(UI_MAIN_CLASS, UI_GetInstanceHandle());
|
|
UnregisterClass(UI_CONTAINER_CLASS, UI_GetInstanceHandle());
|
|
|
|
//
|
|
// Cleanup any timers that are hanging around
|
|
//
|
|
if( _UI.connectStruct.hConnectionTimer )
|
|
{
|
|
_pUt->UTDeleteTimer( _UI.connectStruct.hConnectionTimer );
|
|
_UI.connectStruct.hConnectionTimer = NULL;
|
|
}
|
|
|
|
if( _UI.connectStruct.hSingleConnectTimer )
|
|
{
|
|
_pUt->UTDeleteTimer( _UI.connectStruct.hSingleConnectTimer );
|
|
_UI.connectStruct.hSingleConnectTimer = NULL;
|
|
}
|
|
|
|
if( _UI.connectStruct.hLicensingTimer )
|
|
{
|
|
_pUt->UTDeleteTimer( _UI.connectStruct.hLicensingTimer );
|
|
_UI.connectStruct.hLicensingTimer = NULL;
|
|
}
|
|
|
|
if (_UI.hDisconnectTimeout)
|
|
{
|
|
_pUt->UTDeleteTimer( _UI.hDisconnectTimeout );
|
|
_UI.hDisconnectTimeout = NULL;
|
|
}
|
|
|
|
//
|
|
// Free up BSTRs (if any) used by redirection
|
|
//
|
|
if (_UI.bstrRedirectionLBInfo)
|
|
{
|
|
SysFreeString(_UI.bstrRedirectionLBInfo);
|
|
_UI.bstrRedirectionLBInfo = NULL;
|
|
|
|
}
|
|
|
|
if (_UI.bstrScriptedLBInfo)
|
|
{
|
|
SysFreeString(_UI.bstrScriptedLBInfo);
|
|
_UI.bstrRedirectionLBInfo = NULL;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
if (_pITLBM != NULL)
|
|
{
|
|
_pITLBM->Release();
|
|
_pITLBM = NULL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_BBAR
|
|
if( _pBBar )
|
|
{
|
|
delete _pBBar;
|
|
_pBBar = NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Release our cached interface ptr to the taskbar
|
|
//
|
|
#ifndef OS_WINCE
|
|
if (_pTaskBarList2)
|
|
{
|
|
_pTaskBarList2->Release();
|
|
_pTaskBarList2 = NULL;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Release reference to control parent
|
|
//
|
|
UI_SetControlInstance(NULL);
|
|
|
|
//
|
|
// Cleanup our state to allow re-initialisation
|
|
//
|
|
UI_ResetState();
|
|
|
|
_Objects.ReleaseObjReference(UI_OBJECT_FLAG);
|
|
|
|
UI_DBG_SETINFO(DBG_STAT_UI_TERM_RETURNED);
|
|
|
|
DC_END_FN();
|
|
return S_OK;
|
|
} // UI_Term
|
|
|
|
|
|
//
|
|
// Name: UI_FatalError
|
|
//
|
|
// Purpose: notify control that a fatal error has occurred
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Params: IN error - error code
|
|
//
|
|
//
|
|
DCVOID DCAPI CUI::UI_FatalError(DCINT error)
|
|
{
|
|
DC_BEGIN_FN("UI_FatalError");
|
|
|
|
TRC_ERR((TB, _T("Fatal Error - code %d"), error));
|
|
|
|
//
|
|
// Notify the control that a fatal error has ocurred
|
|
//
|
|
SendMessage(_UI.hWndCntrl,WM_TS_FATALERROR,(WPARAM)error,0);
|
|
|
|
//
|
|
// Container should pop up a dialog and give the user
|
|
// the choice of exiting or launching a debugger..
|
|
// continuing after this point will usually lead to a crash
|
|
// as the errors are indeed fatal....
|
|
//
|
|
|
|
DC_END_FN();
|
|
return;
|
|
|
|
} // UI_FatalError
|
|
|
|
//
|
|
// Name: UI_DisplayBitmapCacheWarning
|
|
//
|
|
// Purpose: Display a bitmap cache warning popup
|
|
//
|
|
// Returns: None
|
|
//
|
|
// Params: IN unusedParm
|
|
//
|
|
//
|
|
void DCAPI CUI::UI_DisplayBitmapCacheWarning(ULONG_PTR unusedParm)
|
|
{
|
|
DC_BEGIN_FN("UI_DisplayBitmapCacheWarning");
|
|
|
|
DC_IGNORE_PARAMETER(unusedParm);
|
|
|
|
//
|
|
// Notify the control that a warning has ocurred
|
|
// pass the warn code for bitmap cache
|
|
//
|
|
SendMessage(_UI.hWndCntrl,WM_TS_WARNING,
|
|
(WPARAM)DC_WARN_BITMAPCACHE_CORRUPTED,0);
|
|
|
|
DC_END_FN();
|
|
} // UI_DisplayBitmapCacheWarning
|
|
|
|
|
|
//Called when the desktop size has changed..e.g in response
|
|
//to a shadow.
|
|
//pDesktopSize contains the new desktop size
|
|
void DCAPI CUI::UI_OnDesktopSizeChange(PDCSIZE pDesktopSize)
|
|
{
|
|
DC_BEGIN_FN("UI_OnShadowDesktopSizeChange");
|
|
TRC_ASSERT(pDesktopSize, (TB,_T("UI_OnShadowDesktopSizeChange received NULL desktop size")));
|
|
if(pDesktopSize)
|
|
{
|
|
if (pDesktopSize->width != _UI.desktopSize.width ||
|
|
pDesktopSize->height != _UI.desktopSize.height)
|
|
{
|
|
UI_SetDesktopSize( pDesktopSize);
|
|
#ifdef SMART_SIZING
|
|
//
|
|
// Notify OP and IH
|
|
//
|
|
LPARAM newSize = MAKELONG(_UI.mainWindowClientSize.width,
|
|
_UI.mainWindowClientSize.height);
|
|
|
|
UI_NotifyOfDesktopSizeChange( newSize );
|
|
#endif
|
|
//Notify the control of the change
|
|
SendMessage(_UI.hWndCntrl, WM_TS_DESKTOPSIZECHANGE,
|
|
(WPARAM)pDesktopSize->width,
|
|
(LPARAM)pDesktopSize->height);
|
|
}
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// Get default langID
|
|
//
|
|
|
|
DCLANGID CUI::UIGetDefaultLangID()
|
|
{
|
|
#if defined(OS_WIN32)
|
|
LANGID LangId;
|
|
|
|
LangId = GetSystemDefaultLangID();
|
|
switch (PRIMARYLANGID(LangId)) {
|
|
case LANG_JAPANESE: return DC_LANG_JAPANESE; break;
|
|
case LANG_KOREAN: return DC_LANG_KOREAN; break;
|
|
case LANG_CHINESE:
|
|
switch (SUBLANGID(LangId)) {
|
|
case SUBLANG_CHINESE_TRADITIONAL: return DC_LANG_CHINESE_TRADITIONAL; break;
|
|
case SUBLANG_CHINESE_SIMPLIFIED: return DC_LANG_CHINESE_SIMPLIFIED; break;
|
|
}
|
|
}
|
|
|
|
#else // defined(OS_WIN32)
|
|
DCUINT acp;
|
|
|
|
acp = GetKBCodePage();
|
|
switch (acp) {
|
|
case 932: return DC_LANG_JAPANESE; break;
|
|
case 949: return DC_LANG_KOREAN; break;
|
|
case 950: return DC_LANG_CHINESE_TRADITIONAL; break;
|
|
case 936: return DC_LANG_CHINESE_SIMPLIFIED; break;
|
|
}
|
|
#endif // defined(OS_WIN32)
|
|
|
|
return DC_LANG_UNKNOWN;
|
|
}
|
|
|
|
//
|
|
// Get default IME file name
|
|
//
|
|
DCUINT CUI::UIGetDefaultIMEFileName(PDCTCHAR imeFileName, DCUINT Size)
|
|
{
|
|
DCTCHAR DefaultIMEStr[MAX_PATH];
|
|
DCUINT intRC;
|
|
DCUINT stringID = 0;
|
|
|
|
switch (UIGetDefaultLangID()) {
|
|
case DC_LANG_JAPANESE: stringID = UI_IDS_IME_NAME_JPN; break;
|
|
case DC_LANG_KOREAN: stringID = UI_IDS_IME_NAME_KOR; break;
|
|
case DC_LANG_CHINESE_TRADITIONAL: stringID = UI_IDS_IME_NAME_CHT; break;
|
|
case DC_LANG_CHINESE_SIMPLIFIED: stringID = UI_IDS_IME_NAME_CHS; break;
|
|
}
|
|
|
|
if (stringID) {
|
|
intRC = LoadString(_UI.hResDllInstance,
|
|
stringID,
|
|
DefaultIMEStr,
|
|
MAX_PATH);
|
|
if (intRC) {
|
|
if (intRC + 1< Size) {
|
|
StringCchCopy(imeFileName, Size, DefaultIMEStr);
|
|
return intRC;
|
|
}
|
|
else {
|
|
*imeFileName = _T('\0');
|
|
return intRC;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Get IME Mapping table name
|
|
//
|
|
DCUINT CUI::UIGetIMEMappingTableName(PDCTCHAR ImeMappingTableName, DCUINT Size)
|
|
{
|
|
DCUINT len;
|
|
PDCTCHAR string = NULL;
|
|
|
|
switch (UIGetDefaultLangID()) {
|
|
case DC_LANG_JAPANESE: string = UTREG_IME_MAPPING_TABLE_JPN; break;
|
|
case DC_LANG_KOREAN: string = UTREG_IME_MAPPING_TABLE_KOR; break;
|
|
case DC_LANG_CHINESE_TRADITIONAL: string = UTREG_IME_MAPPING_TABLE_CHT; break;
|
|
case DC_LANG_CHINESE_SIMPLIFIED: string = UTREG_IME_MAPPING_TABLE_CHS; break;
|
|
}
|
|
|
|
if (string) {
|
|
if ( (len=DC_TSTRLEN(string)) < Size - 1) {
|
|
StringCchCopy(ImeMappingTableName, Size, string);
|
|
return len;
|
|
}
|
|
else {
|
|
*ImeMappingTableName = _T('\0');
|
|
return len;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Disable IME
|
|
//
|
|
VOID CUI::DisableIME(HWND hwnd)
|
|
{
|
|
#if defined(OS_WIN32)
|
|
if (_pUt->lpfnImmAssociateContext != NULL)
|
|
{
|
|
_pUt->lpfnImmAssociateContext(hwnd, (HIMC)NULL);
|
|
}
|
|
#else // defined(OS_WIN32)
|
|
if (_pUt->lpfnWINNLSEnableIME != NULL)
|
|
{
|
|
_pUt->lpfnWINNLSEnableIME(hwnd, FALSE);
|
|
}
|
|
#endif // defined(OS_WIN32)
|
|
}
|
|
|
|
//
|
|
// Get IME file name
|
|
//
|
|
VOID CUI::UIGetIMEFileName(PDCTCHAR imeFileName, DCUINT cchSize)
|
|
{
|
|
HRESULT hr;
|
|
DC_BEGIN_FN("UIGetIMEFileName");
|
|
|
|
#if defined(OS_WIN32)
|
|
imeFileName[0] = _T('\0');
|
|
#if !defined(OS_WINCE) || defined(OS_WINCE_KEYBOARD_LAYOUT)
|
|
{
|
|
if (_pUt->UT_ImmGetIMEFileName(CicSubstGetKeyboardLayout(NULL),
|
|
imeFileName, cchSize) > 0)
|
|
{
|
|
/*
|
|
* For Win95 issue
|
|
* If IME name have contains "$$$.DLL",
|
|
* then this is a process IME (i.e EXE type)
|
|
*/
|
|
PDCTCHAR str = DC_TSTRCHR(imeFileName, _T('$'));
|
|
if (str != NULL)
|
|
{
|
|
if (DC_TSTRCMP(str, _T("$$$.DLL")) == 0)
|
|
{
|
|
UIGetIMEFileName16(imeFileName, cchSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* For NT3.51-J issue
|
|
* If IME name have contains ".EXE",
|
|
* then this is a process IME (i.e EXE type)
|
|
*/
|
|
PDCTCHAR str = DC_TSTRCHR(imeFileName, _T('.'));
|
|
if (str != NULL)
|
|
{
|
|
if (DC_TSTRCMP(str, _T(".EXE")) == 0)
|
|
{
|
|
UIGetIMEFileName16(imeFileName, cchSize);
|
|
}
|
|
else
|
|
{
|
|
DCUINT len;
|
|
DCTCHAR MappedImeFileName[MAX_PATH];
|
|
DCTCHAR ImeMappingTableName[MAX_PATH];
|
|
|
|
//
|
|
// Now look for this key in the [IME Mapping Table] section of
|
|
// the client's INI file
|
|
//
|
|
len = UIGetIMEMappingTableName(ImeMappingTableName,
|
|
sizeof(ImeMappingTableName)/sizeof(DCTCHAR));
|
|
if (len != 0 &&
|
|
len < sizeof(ImeMappingTableName)/sizeof(DCTCHAR)) {
|
|
*MappedImeFileName = _T('\0');
|
|
_pUt->UT_ReadRegistryString(ImeMappingTableName,
|
|
imeFileName,
|
|
NULL,
|
|
MappedImeFileName,
|
|
sizeof(MappedImeFileName)/sizeof(DCTCHAR));
|
|
if (*MappedImeFileName) {
|
|
hr = StringCchCopy(imeFileName, cchSize,
|
|
MappedImeFileName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else // !defined(OS_WINCE) || defined(OS_WINCE_KEYBOARD_LAYOUT)
|
|
UIGetDefaultIMEFileName(imeFileName, Size);
|
|
#endif // !defined(OS_WINCE) || defined(OS_WINCE_KEYBOARD_LAYOUT)
|
|
#else // defined(OS_WIN32)
|
|
UIGetIMEFileName16(imeFileName, Size);
|
|
#endif // defined(OS_WIN32)
|
|
DC_END_FN();
|
|
}
|
|
|
|
#if !defined(OS_WINCE)
|
|
//
|
|
// Get IME file name for WINNLS functionality
|
|
//
|
|
VOID CUI::UIGetIMEFileName16(PDCTCHAR imeFileName, DCUINT Size)
|
|
{
|
|
IMEPRO IMEPro;
|
|
DCTCHAR DefaultImeFileName[MAX_PATH];
|
|
DCTCHAR ImeMappingTableName[MAX_PATH];
|
|
DCUINT intRC;
|
|
|
|
DC_BEGIN_FN("UIGetIMEFileName16");
|
|
|
|
imeFileName[0] = _T('\0');
|
|
{
|
|
if (_pUt->UT_IMPGetIME(NULL, &IMEPro) == 0)
|
|
{
|
|
TRC_ERR((TB, _T("Fatal Error - IMPGetIME returns FALSE")));
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Get file name of 8.3 form, if include directory path in IMEPro.szName
|
|
*/
|
|
DCTCHAR szBuffer[MAX_PATH];
|
|
PDCTCHAR imeFilePart;
|
|
_pUt->UT_GetFullPathName((PDCTCHAR)IMEPro.szName, sizeof(szBuffer)/sizeof(DCTCHAR),
|
|
szBuffer, &imeFilePart);
|
|
|
|
//
|
|
// Now look for this key in the [IME Mapping Table] section of
|
|
// the client's INI file
|
|
//
|
|
intRC = UIGetDefaultIMEFileName(DefaultImeFileName,
|
|
sizeof(DefaultImeFileName)/sizeof(DCTCHAR));
|
|
if (intRC && *DefaultImeFileName) {
|
|
DCUINT len;
|
|
|
|
len = UIGetIMEMappingTableName(ImeMappingTableName,
|
|
sizeof(ImeMappingTableName)/sizeof(DCTCHAR));
|
|
if (len != 0 &&
|
|
len < sizeof(ImeMappingTableName)/sizeof(DCTCHAR)) {
|
|
_pUt->UT_ReadRegistryString(ImeMappingTableName,
|
|
imeFilePart,
|
|
DefaultImeFileName,
|
|
imeFileName,
|
|
Size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
#endif // !defined(OS_WINCE)
|
|
|
|
|
|
//
|
|
// Static window procs
|
|
//
|
|
|
|
|
|
LRESULT CALLBACK CUI::UIStaticMainWndProc (HWND hwnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CUI* pUI = (CUI*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
if(WM_CREATE == message)
|
|
{
|
|
//pull out the this pointer and stuff it in the window class
|
|
LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
|
|
pUI = (CUI*)lpcs->lpCreateParams;
|
|
|
|
SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pUI);
|
|
}
|
|
|
|
//
|
|
// Delegate the message to the appropriate instance
|
|
//
|
|
|
|
if(pUI)
|
|
{
|
|
return pUI->UIMainWndProc(hwnd, message, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK CUI::UIStaticContainerWndProc (HWND hwnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CUI* pUI = (CUI*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
if(WM_CREATE == message)
|
|
{
|
|
//pull out the this pointer and stuff it in the window class
|
|
LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
|
|
pUI = (CUI*)lpcs->lpCreateParams;
|
|
|
|
SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pUI);
|
|
}
|
|
|
|
if(pUI)
|
|
{
|
|
return pUI->UIContainerWndProc(hwnd, message, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Callbacks
|
|
//
|
|
|
|
//
|
|
// Name: UI_OnCoreInitialized
|
|
//
|
|
// Purpose: For the CD to inform the UI that the Core has initialized
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnCoreInitialized(ULONG_PTR unused)
|
|
{
|
|
#ifndef OS_WINCE
|
|
BOOL bPrevMenustate;
|
|
#endif // OS_WINCE
|
|
HWND hwndDlgItem = NULL;
|
|
HWND hwndAddress = NULL;
|
|
|
|
DC_BEGIN_FN("UI_OnCoreInitialized");
|
|
|
|
DC_IGNORE_PARAMETER(unused);
|
|
|
|
DC_EXIT_POINT:
|
|
_UI.fOnCoreInitializeEventCalled = TRUE;
|
|
|
|
|
|
//
|
|
// Notify the IH of the size since there is a small window
|
|
// when the core hasn't been intitialized but we receive
|
|
// the WM_SIZE's that size the control and so the IH
|
|
// would not have received the correct sizes
|
|
//
|
|
ULONG_PTR size = MAKELONG(_UI.mainWindowClientSize.width,
|
|
_UI.mainWindowClientSize.height);
|
|
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT,
|
|
_pIh,
|
|
CD_NOTIFICATION_FUNC(CIH,IH_SetVisibleSize),
|
|
(ULONG_PTR)size);
|
|
|
|
|
|
DC_END_FN();
|
|
return;
|
|
|
|
} // UI_OnCoreInitialised
|
|
|
|
|
|
//
|
|
// Name: UI_OnInputFocusLost
|
|
//
|
|
// Purpose: When the IH loses the input
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: None
|
|
//
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnInputFocusLost(ULONG_PTR unused)
|
|
{
|
|
DC_BEGIN_FN("UI_OnInputFocusLost");
|
|
|
|
DC_IGNORE_PARAMETER(unused);
|
|
TRC_DBG((TB, _T("UI_OnInputFocusLost called")));
|
|
|
|
if (_fIhHasFocus)
|
|
{
|
|
_fIhHasFocus = FALSE;
|
|
|
|
#ifndef OS_WINCE
|
|
if (!UI_IsFullScreen())
|
|
{
|
|
UI_RestoreLangBar();
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//
|
|
// Name: UI_OnInputFocusGained
|
|
//
|
|
// Purpose: When the IH gets the input
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: None
|
|
//
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnInputFocusGained(ULONG_PTR unused)
|
|
{
|
|
DC_BEGIN_FN("UI_OnInputFocusGained");
|
|
|
|
DC_IGNORE_PARAMETER(unused);
|
|
TRC_DBG((TB, _T("UI_OnInputFocusGained called")));
|
|
|
|
TRC_ALT((TB, _T("UI_OnInputFocusGained gain _fIhHas=%d"),_fIhHasFocus));
|
|
|
|
if (!_fIhHasFocus)
|
|
{
|
|
_fIhHasFocus = TRUE;
|
|
#ifndef OS_WINCE
|
|
if (!UI_IsFullScreen())
|
|
{
|
|
UI_HideLangBar();
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("OnInputFocusGained called when we already have focus")));
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Hides the lang bar if not already hidden
|
|
// saves previous lang bar state
|
|
//
|
|
#ifndef OS_WINCE
|
|
void CUI::UI_HideLangBar()
|
|
{
|
|
DC_BEGIN_FN("UI_HideLangBar");
|
|
|
|
if (_pITLBM != NULL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _pITLBM->GetShowFloatingStatus(&_dwLangBarFlags);
|
|
TRC_ALT((TB,_T("Hiding langbar GetShow: 0x%x"), _dwLangBarFlags));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_fLangBarStateSaved = TRUE;
|
|
_fLangBarWasHidden = _dwLangBarFlags & TF_SFT_HIDDEN;
|
|
|
|
if (!_fLangBarWasHidden)
|
|
{
|
|
hr = _pITLBM->ShowFloating(TF_SFT_HIDDEN);
|
|
if (FAILED(hr))
|
|
{
|
|
TRC_ERR((TB,_T("ShowFloating failed: 0x%x"),
|
|
hr));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Restores lang bar state to that set before hiding
|
|
// in UI_HideLangBar
|
|
//
|
|
//
|
|
#ifndef OS_WINCE
|
|
void CUI::UI_RestoreLangBar()
|
|
{
|
|
DC_BEGIN_FN("UI_RestoreLangBar");
|
|
|
|
TRC_ALT((TB,_T("Restore _dwLangBarFlags: 0x%x _fWasHid:%d _fSaved:%d"),
|
|
_dwLangBarFlags, _fLangBarWasHidden, _fLangBarStateSaved));
|
|
|
|
if (_pITLBM != NULL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!_fLangBarWasHidden && _fLangBarStateSaved)
|
|
{
|
|
hr = _pITLBM->ShowFloating(_dwLangBarFlags);
|
|
if (FAILED(hr))
|
|
{
|
|
TRC_ERR((TB,_T("ShowFloating failed: 0x%x"),
|
|
hr));
|
|
}
|
|
}
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Name: UI_OnConnected
|
|
//
|
|
// Purpose: For the CD to inform the UI of connection success
|
|
// and to enable the disconnect menu item
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: None
|
|
//
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnConnected(ULONG_PTR unused)
|
|
{
|
|
BOOL fWasAutoReconnect = FALSE;
|
|
|
|
DC_BEGIN_FN("UI_OnConnected");
|
|
|
|
DC_IGNORE_PARAMETER(unused);
|
|
TRC_DBG((TB, _T("UI_OnConnected called")));
|
|
|
|
//
|
|
// Make sure the shutdown timer isn't hanging around
|
|
//
|
|
if (0 != _UI.shutdownTimer)
|
|
{
|
|
TRC_NRM((TB, _T("Killing shutdown timer")));
|
|
KillTimer(_UI.hwndMain, _UI.shutdownTimer);
|
|
_UI.shutdownTimer = 0;
|
|
}
|
|
|
|
//OnConnected can also be called if we are already connected
|
|
//we only want to fire an event to the Ax control on the
|
|
//initial connect action.
|
|
DCBOOL fJustConnected = (_UI.connectionStatus == UI_STATUS_CONNECT_PENDING) ||
|
|
(_UI.connectionStatus == UI_STATUS_PENDING_CONNECTENDPOINT);
|
|
|
|
//
|
|
// Notify the CLX test harness of the actual connection
|
|
// address and other interesting ARC/Redirection info
|
|
//
|
|
_clx->CLX_ConnectEx(
|
|
_UI.strAddress,
|
|
UI_IsAutoReconnecting(),
|
|
UI_IsClientRedirected(),
|
|
UI_GetRedirectedLBInfo()
|
|
);
|
|
|
|
|
|
//
|
|
// Dismiss the autoreconnection dialog if we get
|
|
// connected
|
|
//
|
|
|
|
if (_pArcUI) {
|
|
fWasAutoReconnect = TRUE;
|
|
UI_StopAutoReconnectDlg();
|
|
}
|
|
|
|
UISetConnectionStatus(UI_STATUS_CONNECTED);
|
|
|
|
//
|
|
// Set the disconnection reason - now we are connected, we don't expect
|
|
// a disconnect, unless user-initiated.
|
|
//
|
|
_UI.disconnectReason =
|
|
UI_MAKE_DISCONNECT_ERR(UI_ERR_UNEXPECTED_DISCONNECT);
|
|
|
|
//
|
|
// Update the screen mode (do not grab the focus here)
|
|
//
|
|
UIUpdateScreenMode( FALSE );
|
|
|
|
//
|
|
// Show the Main Window. Put this here so that the main window is seen
|
|
// only on connection
|
|
//
|
|
ShowWindow(_UI.hwndMain, SW_SHOW);
|
|
UISmoothScrollingSettingChanged();
|
|
|
|
//
|
|
// Show the Container Window.
|
|
//
|
|
ShowWindow(_UI.hwndContainer, SW_SHOW);
|
|
|
|
#ifdef OS_WINCE
|
|
//
|
|
// WinCE doesn't send a WM_SHOWINDOW to the Container, so do that work
|
|
//
|
|
SetFocus(_UI.hwndContainer);
|
|
#endif
|
|
|
|
//
|
|
// Tell the Client extension dll of the connection
|
|
//
|
|
_clx->CLX_OnConnected();
|
|
|
|
|
|
//
|
|
// On first connection set the fullscreen state
|
|
// note that UI_OnConnected also fires after logon
|
|
// don't reset the fullscreen state as the user may
|
|
// have changed it.
|
|
//
|
|
if (fJustConnected)
|
|
{
|
|
if (UI_GetStartFullScreen())
|
|
{
|
|
if (!UI_IsFullScreen())
|
|
{
|
|
UI_GoFullScreen();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If a previous connection left us fullscreen
|
|
// leave fullscreen
|
|
//
|
|
if (UI_IsFullScreen())
|
|
{
|
|
UI_LeaveFullScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We're done with the winsock hostname
|
|
// buffer at this point.
|
|
//
|
|
#ifdef OS_WINCE
|
|
if (_pHostData)
|
|
{
|
|
#endif
|
|
LocalFree(_pHostData);
|
|
_pHostData = NULL;
|
|
#ifdef OS_WINCE
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("_pHostData is NULL")));
|
|
}
|
|
#endif
|
|
|
|
#ifdef SMART_SIZING
|
|
//
|
|
// Notify OP and IH
|
|
//
|
|
LPARAM newSize = MAKELONG(_UI.mainWindowClientSize.width,
|
|
_UI.mainWindowClientSize.height);
|
|
|
|
UI_NotifyOfDesktopSizeChange( newSize );
|
|
#endif
|
|
|
|
//Inform the ActiveX control of the connection
|
|
//so it can fire an event to it's container
|
|
if(IsWindow(_UI.hWndCntrl))
|
|
{
|
|
//
|
|
// Only notify it's a new connection.
|
|
//
|
|
if(fJustConnected)
|
|
{
|
|
SendMessage(_UI.hWndCntrl,WM_TS_CONNECTED,0,0);
|
|
|
|
#ifdef USE_BBAR
|
|
if (_pBBar) {
|
|
_pBBar->SetEnabled(_UI.fBBarEnabled);
|
|
_pBBar->SetShowMinimize(UI_GetBBarShowMinimize());
|
|
_pBBar->SetShowRestore(UI_GetBBarShowRestore());
|
|
|
|
if (!_pBBar->StartupBBar(_UI.desktopSize.width,
|
|
_UI.desktopSize.height,
|
|
TRUE)) {
|
|
// BBar is a security feature drop link if it can't start
|
|
TRC_ERR((TB,_T("BBar failed to init disconnecting")));
|
|
UIGoDisconnected(_UI.disconnectReason, TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure we have the focus after a screen mode toggle
|
|
// and after the container has been notified of the connection
|
|
// (so it has a chance to restore the window if it was minimized)
|
|
// Otherwise we can hit problems because we can't assign focus to
|
|
// the minimized Container then IH window. Also the BBar won't start
|
|
// lowering if we connect in the minimized state.
|
|
//
|
|
if(_UI.fGrabFocusOnConnect)
|
|
{
|
|
HWND hwndPrevFocus;
|
|
|
|
TRC_NRM((TB,_T("CONNECT GRAB focus")));
|
|
hwndPrevFocus = SetFocus(_UI.hwndContainer);
|
|
TRC_NRM((TB,_T("SetFocus to container, prev focus 0x%x gle 0x%x"),
|
|
hwndPrevFocus, GetLastError()));
|
|
}
|
|
|
|
|
|
DC_END_FN();
|
|
return;
|
|
|
|
} // UI_OnConnected
|
|
|
|
//
|
|
// Name: UI_OnDeactivateAllPDU
|
|
//
|
|
// Purpose: For the CD to inform the UI of DeactivateAllPDU
|
|
//
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: reason (unused)
|
|
//
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnDeactivateAllPDU(ULONG_PTR reason)
|
|
{
|
|
|
|
DC_BEGIN_FN("UI_OnDeactivateAllPDU");
|
|
|
|
TRC_NRM((TB, _T("DeactivateAllPDU received")));
|
|
DC_IGNORE_PARAMETER(reason);
|
|
_UI.disconnectReason = UI_MAKE_DISCONNECT_ERR(UI_ERR_NORMAL_DISCONNECT);
|
|
|
|
|
|
//
|
|
// Create a timer to ensure that we either get disconnected
|
|
// or reconnected in a reasonable time interval otherwise
|
|
// force a disconnect (Because the user can be left hanging with
|
|
// a disabled client).
|
|
//
|
|
if (_UI.hDisconnectTimeout)
|
|
{
|
|
_pUt->UTDeleteTimer( _UI.hDisconnectTimeout );
|
|
_UI.hDisconnectTimeout = NULL;
|
|
}
|
|
_UI.hDisconnectTimeout = _pUt->UTCreateTimer(
|
|
_UI.hwndMain,
|
|
UI_TIMER_DISCONNECT_TIMERID,
|
|
UI_TOTAL_DISCONNECTION_TIMEOUT);
|
|
|
|
if (_UI.hDisconnectTimeout)
|
|
{
|
|
_pUt->UTStartTimer( _UI.hDisconnectTimeout );
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Failed to create disconnect timer")));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return;
|
|
} // UI_OnDeactivateAllPDU
|
|
|
|
|
|
//
|
|
// Name: UI_OnDemandActivePDU
|
|
//
|
|
// Purpose: For the CD to inform the UI of DemandActivePDU
|
|
//
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: reason (unused)
|
|
//
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnDemandActivePDU(ULONG_PTR reason)
|
|
{
|
|
DCUINT32 sessionId;
|
|
|
|
DC_BEGIN_FN("UI_OnDemandActivePDU");
|
|
|
|
TRC_NRM((TB, _T("DemandActivePDU received")));
|
|
|
|
DC_IGNORE_PARAMETER(reason);
|
|
|
|
if (_UI.hDisconnectTimeout )
|
|
{
|
|
_pUt->UTDeleteTimer( _UI.hDisconnectTimeout );
|
|
_UI.hDisconnectTimeout = NULL;
|
|
}
|
|
|
|
_UI.disconnectReason =
|
|
UI_MAKE_DISCONNECT_ERR(UI_ERR_UNEXPECTED_DISCONNECT);
|
|
|
|
//
|
|
// Notify CLX the reconnected session Id if client reconnects a session
|
|
//
|
|
|
|
sessionId = UI_GetSessionId();
|
|
if (sessionId) {
|
|
UI_OnLoginComplete();
|
|
}
|
|
|
|
DC_END_FN();
|
|
return;
|
|
} // UI_OnDemandActivePDU
|
|
|
|
|
|
//
|
|
// UI_OnSecurityExchangeComplete
|
|
//
|
|
// For the SL to notify us that the security exchange has completed
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnSecurityExchangeComplete(ULONG_PTR reason)
|
|
{
|
|
DC_BEGIN_FN("UI_OnSecurityExchangeComplete");
|
|
|
|
//
|
|
// stop the single and overall connection timer and start the licensing
|
|
// timer. This has to happen on the UI thread as otherwise there could
|
|
// be a race between the timers popping and the SL directly modifying
|
|
// them (see ntbug9!160001)
|
|
//
|
|
if( _UI.connectStruct.hSingleConnectTimer)
|
|
{
|
|
_pUt->UTStopTimer( _UI.connectStruct.hSingleConnectTimer);
|
|
}
|
|
if( _UI.connectStruct.hConnectionTimer )
|
|
{
|
|
_pUt->UTStopTimer( _UI.connectStruct.hConnectionTimer );
|
|
}
|
|
if( _UI.connectStruct.hLicensingTimer )
|
|
{
|
|
_pUt->UTStartTimer( _UI.connectStruct.hLicensingTimer );
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// UI_OnLicensingComplete
|
|
//
|
|
// For the SL to notify us that the licensing has completed
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnLicensingComplete(ULONG_PTR reason)
|
|
{
|
|
DC_BEGIN_FN("UI_OnLicensingComplete");
|
|
|
|
//
|
|
// stop the licensing timer.
|
|
// This has to happen on the UI thread as otherwise there could
|
|
// be a race between the timers popping and the SL directly modifying
|
|
// them (see ntbug9!160001)
|
|
//
|
|
if( _UI.connectStruct.hLicensingTimer )
|
|
{
|
|
_pUt->UTStopTimer( _UI.connectStruct.hLicensingTimer );
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: UI_OnDisconnected
|
|
//
|
|
// Purpose: For the CD to inform the UI of disconnection
|
|
//
|
|
void DCAPI CUI::UI_OnDisconnected(ULONG_PTR disconnectID)
|
|
{
|
|
unsigned mainDiscReason;
|
|
|
|
DC_BEGIN_FN("UI_OnDisconnected");
|
|
|
|
TRC_NRM((TB, _T("Disconnected with Id %#x"), disconnectID));
|
|
|
|
//
|
|
// Make sure the shutdown timer isn't hanging around
|
|
//
|
|
if (0 != _UI.shutdownTimer)
|
|
{
|
|
TRC_NRM((TB, _T("Killing shutdown timer")));
|
|
KillTimer(_UI.hwndMain, _UI.shutdownTimer);
|
|
_UI.shutdownTimer = 0;
|
|
}
|
|
|
|
if (_UI.hDisconnectTimeout )
|
|
{
|
|
_pUt->UTDeleteTimer( _UI.hDisconnectTimeout );
|
|
_UI.hDisconnectTimeout = NULL;
|
|
}
|
|
|
|
//Disable and free any idle input timers
|
|
InitInputIdleTimer(0);
|
|
|
|
//
|
|
// Restore the lang bar to it's previous state
|
|
// this is important because we won't always receive
|
|
// an OnFocusLost notification from the IH (e.g if it is
|
|
// in the disabled state when it loses focus)
|
|
//
|
|
#ifndef OS_WINCE
|
|
UI_RestoreLangBar();
|
|
#endif
|
|
|
|
//
|
|
// Special case for error handling:
|
|
// if we get disconnected while the connection is still pending
|
|
// with a network error the most likely case is that the server
|
|
// broke the link because (a) connections are disabled or (b)
|
|
// max number of connections exceeded. We can't actually send
|
|
// back status from the server at this early stage in the connection
|
|
// so instead we just make a very educated 'guess' on the client.
|
|
// UI shells should parse this error code and display the likely
|
|
// error cases:
|
|
// Server does not allow connections/max number of connections exceeded
|
|
// Network error
|
|
//
|
|
if (TS_ERRINFO_NOERROR == UI_GetServerErrorInfo() &&
|
|
UI_STATUS_CONNECT_PENDING == _UI.connectionStatus &&
|
|
NL_MAKE_DISCONNECT_ERR(NL_ERR_TDFDCLOSE) == disconnectID)
|
|
{
|
|
TRC_NRM((TB, _T(" Setting error info to TS_ERRINFO_SERVER_DENIED_CONNECTION")));
|
|
if (_UI.fUseFIPS) {
|
|
UI_SetServerErrorInfo( TS_ERRINFO_SERVER_DENIED_CONNECTION_FIPS );
|
|
}
|
|
else {
|
|
UI_SetServerErrorInfo( TS_ERRINFO_SERVER_DENIED_CONNECTION );
|
|
}
|
|
}
|
|
|
|
// When server redirection is in progress, we simply to the redirection
|
|
// without translating disconnection codes or anything else.
|
|
if (_UI.DoRedirection) {
|
|
TRC_NRM((TB,_T("DoRedirection set, doing it")));
|
|
//
|
|
// Free the previous connection's host name lookup
|
|
// buffer before continuing.
|
|
//
|
|
if(_pHostData)
|
|
{
|
|
LocalFree(_pHostData);
|
|
_pHostData = NULL;
|
|
}
|
|
UIRedirectConnection();
|
|
}
|
|
else if ((_UI.connectionStatus == UI_STATUS_CONNECT_PENDING) ||
|
|
(_UI.connectionStatus == UI_STATUS_CONNECT_PENDING_DNS)) {
|
|
// Try the next connection. Pass the disconnect code on unless we
|
|
// already have a UI-specific code that we can use. This code will
|
|
// be used if we have tried all the IP addresses.
|
|
TRC_NRM((TB, _T("ConnectPending: try next IP address?")));
|
|
if ((_UI.disconnectReason ==
|
|
UI_MAKE_DISCONNECT_ERR(UI_ERR_UNEXPECTED_DISCONNECT)) ||
|
|
(_UI.disconnectReason ==
|
|
UI_MAKE_DISCONNECT_ERR(UI_ERR_NORMAL_DISCONNECT)) ||
|
|
(NL_GET_MAIN_REASON_CODE(_UI.disconnectReason) !=
|
|
UI_DISCONNECT_ERROR))
|
|
{
|
|
_UI.disconnectReason = disconnectID;
|
|
}
|
|
|
|
UITryNextConnection();
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("Disconnect id %#x/%#x"),
|
|
_UI.disconnectReason, disconnectID));
|
|
|
|
// See if this is due to an 'expected' disconnect - such as a
|
|
// timeout.
|
|
if (_UI.disconnectReason ==
|
|
UI_MAKE_DISCONNECT_ERR(UI_ERR_UNEXPECTED_DISCONNECT)) {
|
|
// Unexpected disconnection - use the code passed in.
|
|
UIGoDisconnected(disconnectID, TRUE);
|
|
}
|
|
else if (_UI.disconnectReason ==
|
|
UI_MAKE_DISCONNECT_ERR(UI_ERR_NORMAL_DISCONNECT)) {
|
|
// Normal disconnection (ie we've received a DeactivateAllPDU).
|
|
// Use the reason code set by MCS if a DPUM has been received.
|
|
// Otherwise, leave it unchanged.
|
|
mainDiscReason = NL_GET_MAIN_REASON_CODE(disconnectID);
|
|
if ((mainDiscReason == NL_DISCONNECT_REMOTE_BY_SERVER) ||
|
|
(mainDiscReason == NL_DISCONNECT_REMOTE_BY_USER))
|
|
UIGoDisconnected(disconnectID, TRUE);
|
|
else
|
|
UIGoDisconnected(_UI.disconnectReason, TRUE);
|
|
}
|
|
else {
|
|
// UI-initiated disconnection - use the UI's code.
|
|
UIGoDisconnected(_UI.disconnectReason, TRUE);
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
} // UI_OnDisconnected
|
|
|
|
|
|
//
|
|
// Name: UI_OnShutDown
|
|
//
|
|
// Purpose: Shuts down the application if called with success from the
|
|
// core. If the called with failure informs the user to
|
|
// disconnect or log off if they wish to shut down.
|
|
//
|
|
// Params: IN - successID - information on whether server allowed
|
|
// termination
|
|
//
|
|
DCVOID DCAPI CUI::UI_OnShutDown(ULONG_PTR successID)
|
|
{
|
|
DC_BEGIN_FN("UI_OnShutDown");
|
|
|
|
if (successID == UI_SHUTDOWN_SUCCESS)
|
|
{
|
|
//
|
|
// If the Core has replied to _pCo->CO_Shutdown(CO_SHUTDOWN) with
|
|
// UI_OnShutdown(UI_SHUTDOWN_SUCCESS) then the UI is free to
|
|
// terminate, so starts the process here.
|
|
//
|
|
|
|
//
|
|
// Notify axcontrol of shutdown.
|
|
//
|
|
SendMessage(_UI.hWndCntrl,WM_TERMTSC,0,0);
|
|
UI_DBG_SETINFO(DBG_STAT_TERMTSC_SENT);
|
|
|
|
//
|
|
// Must restore the langbar state just as we do in UI_OnDisconnected
|
|
// as in this disconnect path (shutdown) the disconnect notification
|
|
// is fired from the ActiveX layer.
|
|
//
|
|
#ifndef OS_WINCE
|
|
UI_RestoreLangBar();
|
|
#endif
|
|
|
|
//
|
|
// Do tail end processing for the disconnection but do not
|
|
// fire the disconnect event, that is handled by TERMTSC
|
|
//
|
|
if (_UI.connectionStatus != UI_STATUS_DISCONNECTED) {
|
|
UIGoDisconnected(_UI.disconnectReason, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can kill the shutdown timer here since the server must have
|
|
// responded to our shutdown PDU.
|
|
//
|
|
if (0 != _UI.shutdownTimer)
|
|
{
|
|
TRC_NRM((TB, _T("Killing shutdown timer")));
|
|
KillTimer(_UI.hwndMain, _UI.shutdownTimer);
|
|
_UI.shutdownTimer = 0;
|
|
}
|
|
|
|
//
|
|
// If successID is not UI_SHUTDOWN_SUCCESS then the UI has been
|
|
// denied shutdown by the server (e.g the user has logged in so
|
|
// we need to prompt him if it's Ok to continue shutdown).
|
|
// Fire an event to the shell to ask the user if it is OK to
|
|
// proceed with the close
|
|
//
|
|
TRC_NRM((TB,_T("Firing WM_TS_ASKCONFIRMCLOSE")));
|
|
BOOL bOkToClose = TRUE;
|
|
SendMessage( _UI.hWndCntrl, WM_TS_ASKCONFIRMCLOSE,
|
|
(WPARAM)&bOkToClose, 0 );
|
|
if( bOkToClose)
|
|
{
|
|
TRC_NRM((TB,_T("User OK'd close request")));
|
|
_pCo->CO_Shutdown(CO_DISCONNECT_AND_EXIT);
|
|
}
|
|
else
|
|
{
|
|
TRC_NRM((TB,_T("User denied close request")));
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
} // UI_OnShutDown
|
|
|
|
|
|
//
|
|
// Name: UI_UpdateSessionInfo
|
|
//
|
|
// Purpose: Updates the registry with the latest session info.
|
|
//
|
|
// Params: IN - pDomain Domain
|
|
// cbDomain Length of pDomain (in bytes)
|
|
// pUserName UserName
|
|
// cbUsername Length of pUserName (in bytes)
|
|
//
|
|
DCVOID DCAPI CUI::UI_UpdateSessionInfo(PDCWCHAR pDomain,
|
|
DCUINT cbDomain,
|
|
PDCWCHAR pUserName,
|
|
DCUINT cbUsername,
|
|
DCUINT32 SessionId)
|
|
{
|
|
UNREFERENCED_PARAMETER(cbUsername);
|
|
UNREFERENCED_PARAMETER(cbDomain);
|
|
|
|
DC_BEGIN_FN("UI_UpdateSessionInfo");
|
|
|
|
//
|
|
// Update the UT variables
|
|
//
|
|
UI_SetDomain(pDomain);
|
|
UI_SetUserName(pUserName);
|
|
UI_SetSessionId(SessionId);
|
|
|
|
UI_OnLoginComplete();
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: UI_GoFullScreen
|
|
//
|
|
DCVOID CUI::UI_GoFullScreen(DCVOID)
|
|
{
|
|
DWORD dwWebCtrlStyle;
|
|
DC_BEGIN_FN("UI_GoFullScreen");
|
|
|
|
//
|
|
// Before going fullscreen restore
|
|
// the lang bar to it's previous state
|
|
// since the system will take care of hiding
|
|
// it with it's built in fullscreen detection
|
|
//
|
|
#ifndef OS_WINCE
|
|
if (!UI_IsFullScreen())
|
|
{
|
|
UI_RestoreLangBar();
|
|
}
|
|
#endif
|
|
|
|
if(_UI.fContainerHandlesFullScreenToggle)
|
|
{
|
|
//
|
|
// FullScreen is handled by the container
|
|
// notify the control to fire an event
|
|
//
|
|
//Notify activeX control of screen mode change
|
|
if(IsWindow(_UI.hWndCntrl))
|
|
{
|
|
//
|
|
// wparam = 1 means go fullscreen
|
|
//
|
|
|
|
_UI.fContainerInFullScreen = TRUE;
|
|
SendMessage( _UI.hWndCntrl, WM_TS_REQUESTFULLSCREEN, (WPARAM)1, 0);
|
|
|
|
UIUpdateScreenMode( TRUE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Control handles fullscreen
|
|
//
|
|
dwWebCtrlStyle = GetWindowLong(_UI.hwndMain, GWL_STYLE);
|
|
if(!dwWebCtrlStyle)
|
|
{
|
|
TRC_ABORT((TB, _T("GetWindowLong failed")));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Going to real full screen mode
|
|
//
|
|
dwWebCtrlStyle &= ~WS_CHILD;
|
|
dwWebCtrlStyle |= WS_POPUP;
|
|
_UI.fControlIsFullScreen = TRUE;
|
|
SetParent(_UI.hwndMain, NULL);
|
|
|
|
if(!SetWindowLong(_UI.hwndMain, GWL_STYLE, dwWebCtrlStyle))
|
|
{
|
|
TRC_ABORT((TB, _T("SetWindowLong failed for webctrl")));
|
|
}
|
|
UIUpdateScreenMode( TRUE );
|
|
|
|
TRC_ASSERT(IsWindow(_UI.hWndCntrl), (TB, _T("hWndCntrl is NULL")));
|
|
|
|
#ifndef OS_WINCE
|
|
//Notify the shell that we've gone fullscreen
|
|
CUT::NotifyShellOfFullScreen( _UI.hwndMain,
|
|
TRUE,
|
|
&_pTaskBarList2,
|
|
&_fQueriedForTaskBarList2 );
|
|
#endif
|
|
|
|
|
|
//Notify activeX control of screen mode change
|
|
if(IsWindow(_UI.hWndCntrl))
|
|
{
|
|
SendMessage( _UI.hWndCntrl, WM_TS_GONEFULLSCREEN, 0, 0);
|
|
}
|
|
}
|
|
if(UI_IsFullScreen())
|
|
{
|
|
_pIh->IH_NotifyEnterFullScreen();
|
|
#ifdef USE_BBAR
|
|
if(_pBBar)
|
|
{
|
|
_pBBar->OnNotifyEnterFullScreen();
|
|
}
|
|
#endif
|
|
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
|
|
// When the fullscreen window size is smaller than the desktop size
|
|
// we don't disable shadow bitmap
|
|
if ((_UI.mainWindowClientSize.width >= _UI.desktopSize.width) &&
|
|
(_UI.mainWindowClientSize.height >= _UI.desktopSize.height))
|
|
{
|
|
_pCd->CD_DecoupleSyncNotification(CD_RCV_COMPONENT,
|
|
_pUh,
|
|
CD_NOTIFICATION_FUNC(CUH,UH_DisableShadowBitmap),
|
|
NULL);
|
|
}
|
|
#endif // DISABLE_SHADOW_IN_FULLSCREEN
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: UI_LeaveFullScreen
|
|
//
|
|
DCVOID CUI::UI_LeaveFullScreen(DCVOID)
|
|
{
|
|
DWORD dwWebCtrlStyle;
|
|
|
|
DC_BEGIN_FN("UI_LeaveFullScreen");
|
|
if(_UI.fContainerHandlesFullScreenToggle)
|
|
{
|
|
//
|
|
// FullScreen is handled by the container
|
|
// notify the control to fire an event
|
|
//
|
|
//Notify activeX control of screen mode change
|
|
if(IsWindow(_UI.hWndCntrl))
|
|
{
|
|
//
|
|
// wparam = 1 means go fullscreen
|
|
//
|
|
|
|
_UI.fContainerInFullScreen = FALSE;
|
|
SendMessage( _UI.hWndCntrl, WM_TS_REQUESTFULLSCREEN, (WPARAM)0, 0);
|
|
|
|
UIUpdateScreenMode( TRUE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwWebCtrlStyle = GetWindowLong(_UI.hwndMain, GWL_STYLE);
|
|
if(!dwWebCtrlStyle)
|
|
{
|
|
TRC_ABORT((TB, _T("GetWindowLong failed for webctrl")));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Leaving real full screen mode
|
|
//
|
|
dwWebCtrlStyle &= ~WS_POPUP;
|
|
dwWebCtrlStyle |= WS_CHILD;
|
|
_UI.fControlIsFullScreen = FALSE;
|
|
SetParent(_UI.hwndMain, _UI.hWndCntrl);
|
|
|
|
if(!SetWindowLong(_UI.hwndMain, GWL_STYLE, dwWebCtrlStyle))
|
|
{
|
|
TRC_ABORT((TB, _T("SetWindowLong failed for webctrl")));
|
|
}
|
|
|
|
//ActiveX control is always in 'Full screen mode'
|
|
UIUpdateScreenMode( TRUE );
|
|
TRC_ASSERT(IsWindow(_UI.hWndCntrl),(TB, _T("hWndCntrl is NULL")));
|
|
|
|
#ifndef OS_WINCE
|
|
//Notify the shell that we've left fullscreen
|
|
CUT::NotifyShellOfFullScreen( _UI.hwndMain,
|
|
FALSE,
|
|
&_pTaskBarList2,
|
|
&_fQueriedForTaskBarList2 );
|
|
#endif
|
|
|
|
|
|
//Notify activeX control of screen mode change
|
|
if(IsWindow(_UI.hWndCntrl))
|
|
{
|
|
SendMessage( _UI.hWndCntrl, WM_TS_LEFTFULLSCREEN, 0, 0);
|
|
}
|
|
}
|
|
|
|
if(!UI_IsFullScreen())
|
|
{
|
|
//Notify IH
|
|
_pIh->IH_NotifyLeaveFullScreen();
|
|
#ifdef USE_BBAR
|
|
if(_pBBar)
|
|
{
|
|
_pBBar->OnNotifyLeaveFullScreen();
|
|
}
|
|
#endif
|
|
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
|
|
// When leaving fullscreen, enable the use of shadow bitmap
|
|
_pCd->CD_DecoupleSyncNotification(CD_RCV_COMPONENT,
|
|
_pUh,
|
|
CD_NOTIFICATION_FUNC(CUH,UH_EnableShadowBitmap),
|
|
NULL);
|
|
#endif // DISABLE_SHADOW_IN_FULLSCREEN
|
|
|
|
//
|
|
// After leaving fullscreen we need to handle
|
|
// hiding the langbar if the IH has the focus
|
|
//
|
|
#ifndef OS_WINCE
|
|
if (_fIhHasFocus)
|
|
{
|
|
UI_HideLangBar();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: UI_ToggleFullScreenMode
|
|
//
|
|
// Purpose: Toggle web ctrl/full screen mode
|
|
//
|
|
DCVOID CUI::UI_ToggleFullScreenMode(DCVOID)
|
|
{
|
|
DC_BEGIN_FN("UI_ToggleFullScreenMode");
|
|
|
|
if(UI_IsFullScreen())
|
|
{
|
|
UI_LeaveFullScreen();
|
|
}
|
|
else
|
|
{
|
|
UI_GoFullScreen();
|
|
}
|
|
|
|
DC_END_FN();
|
|
} // UI_ToggleFullScreenMode
|
|
|
|
|
|
//
|
|
// Name: UI_IsFullScreen
|
|
//
|
|
// Purpose: Returns true if we are in fullscreen mode
|
|
// (for both container and control handled fullscreen)
|
|
//
|
|
DCBOOL CUI::UI_IsFullScreen()
|
|
{
|
|
return _UI.fContainerHandlesFullScreenToggle ?
|
|
_UI.fContainerInFullScreen : _UI.fControlIsFullScreen;
|
|
}
|
|
|
|
|
|
#ifdef DC_DEBUG
|
|
//
|
|
// Name: UI_CoreDebugSettingChanged
|
|
//
|
|
// Purpose: Performs necessary actions when any of the Core debug
|
|
// setings are updated.
|
|
//
|
|
void DCINTERNAL CUI::UI_CoreDebugSettingChanged()
|
|
{
|
|
unsigned configFlags;
|
|
|
|
DC_BEGIN_FN("UICoreDebugSettingChanged");
|
|
|
|
if (!_UI.coreInitialized)
|
|
return;
|
|
|
|
configFlags = 0;
|
|
|
|
if (_UI.hatchBitmapPDUData)
|
|
configFlags |= CO_CFG_FLAG_HATCH_BITMAP_PDU_DATA;
|
|
|
|
if (_UI.hatchIndexPDUData)
|
|
configFlags |= CO_CFG_FLAG_HATCH_INDEX_PDU_DATA;
|
|
|
|
if (_UI.hatchSSBOrderData)
|
|
configFlags |= CO_CFG_FLAG_HATCH_SSB_ORDER_DATA;
|
|
|
|
if (_UI.hatchMemBltOrderData)
|
|
configFlags |= CO_CFG_FLAG_HATCH_MEMBLT_ORDER_DATA;
|
|
|
|
if (_UI.labelMemBltOrders)
|
|
configFlags |= CO_CFG_FLAG_LABEL_MEMBLT_ORDERS;
|
|
|
|
if (_UI.bitmapCacheMonitor)
|
|
configFlags |= CO_CFG_FLAG_BITMAP_CACHE_MONITOR;
|
|
|
|
_pCo->CO_SetConfigurationValue(CO_CFG_DEBUG_SETTINGS, configFlags);
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// Name: UI_SetRandomFailureItem
|
|
//
|
|
// Purpose: Sets the percentage failure of a specified function
|
|
//
|
|
// Params: IN - itemID - identifies the function
|
|
// IN - percent - the new percentage failure
|
|
//
|
|
void DCAPI CUI::UI_SetRandomFailureItem(unsigned itemID, int percent)
|
|
{
|
|
DC_BEGIN_FN("UI_SetRandomFailureItem");
|
|
|
|
_pUt->UT_SetRandomFailureItem(itemID, percent);
|
|
|
|
DC_END_FN();
|
|
} // UI_SetRandomFailureItem
|
|
|
|
|
|
//
|
|
// Name: UI_GetRandomFailureItem
|
|
//
|
|
// Purpose: Gets the percentage failure for a specified function
|
|
//
|
|
// Returns: The percentage
|
|
//
|
|
// Params: IN - itemID - identifies the function
|
|
//
|
|
int DCAPI CUI::UI_GetRandomFailureItem(unsigned itemID)
|
|
{
|
|
DC_BEGIN_FN("UI_GetRandomFailureItem");
|
|
DC_END_FN();
|
|
return _pUt->UT_GetRandomFailureItem(itemID);
|
|
} // UI_GetRandomFailureItem
|
|
|
|
|
|
//
|
|
// Name: UI_SetNetworkThroughput
|
|
//
|
|
// Purpose: Set the network throughput in bytes per second
|
|
//
|
|
// Params: IN - bytesPerSec to set for the maximum network throughput
|
|
//
|
|
void DCAPI CUI::UI_SetNetworkThroughput(unsigned bytesPerSec)
|
|
{
|
|
DC_BEGIN_FN("UI_SetNetworkThroughput");
|
|
|
|
TRC_ASSERT(((bytesPerSec <= 50000)),
|
|
(TB,_T("bytesPerSec is out of range")));
|
|
_pTd->NL_SetNetworkThroughput(bytesPerSec);
|
|
|
|
DC_END_FN();
|
|
} // UI_SetNetworkThroughput
|
|
|
|
|
|
//
|
|
// Name: UI_GetNetworkThroughput
|
|
//
|
|
// Purpose: Gets the percentage failure for a specified function
|
|
//
|
|
unsigned DCAPI CUI::UI_GetNetworkThroughput()
|
|
{
|
|
DC_BEGIN_FN("UI_GetNetworkThroughput");
|
|
DC_END_FN();
|
|
return _pTd->NL_GetNetworkThroughput();
|
|
} // UI_GetNetworkThroughput
|
|
|
|
#endif // DC_DEBUG
|
|
|
|
|
|
//
|
|
// Set the list of virtual channel plugins to load
|
|
//
|
|
BOOL DCAPI CUI::UI_SetVChanAddinList(TCHAR *szVChanAddins)
|
|
{
|
|
DC_BEGIN_FN("UI_SetVChanAddinList");
|
|
|
|
if(_UI.pszVChanAddinDlls)
|
|
{
|
|
//If previously set, free
|
|
UT_Free(_pUt, _UI.pszVChanAddinDlls);
|
|
}
|
|
|
|
if(!szVChanAddins || szVChanAddins[0] == 0)
|
|
{
|
|
_UI.pszVChanAddinDlls = NULL;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
DCUINT len = DC_TSTRLEN(szVChanAddins);
|
|
_UI.pszVChanAddinDlls = (PDCTCHAR)UT_Malloc(_pUt, (len +1) * sizeof(DCTCHAR));
|
|
if(_UI.pszVChanAddinDlls)
|
|
{
|
|
StringCchCopy(_UI.pszVChanAddinDlls, len+1, szVChanAddins);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Set the load balance info
|
|
//
|
|
BOOL DCAPI CUI::UI_SetLBInfo(PBYTE pLBInfo, unsigned LBInfoSize)
|
|
{
|
|
DC_BEGIN_FN("UI_SetLBInfo");
|
|
|
|
if(_UI.bstrScriptedLBInfo)
|
|
{
|
|
//If previously set, free
|
|
SysFreeString(_UI.bstrScriptedLBInfo);
|
|
}
|
|
|
|
if(!pLBInfo)
|
|
{
|
|
_UI.bstrScriptedLBInfo = NULL;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
_UI.bstrScriptedLBInfo= SysAllocStringByteLen((LPCSTR)pLBInfo, LBInfoSize);
|
|
|
|
if (_UI.bstrScriptedLBInfo == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Name: UI_SetCompress
|
|
//
|
|
void DCAPI CUI::UI_SetCompress(BOOL fCompress)
|
|
{
|
|
DC_BEGIN_FN("UI_SetCompress");
|
|
|
|
TRC_NRM((TB, _T("Setting _UI.fCompress to %d"), fCompress));
|
|
|
|
_UI.fCompress = fCompress;
|
|
//
|
|
// If compression is enabled, then allocate a receive context
|
|
//
|
|
if (fCompress && !_UI.pRecvContext2)
|
|
{
|
|
_UI.pRecvContext2 = (RecvContext2_64K *)
|
|
UT_Malloc(_pUt,sizeof(RecvContext2_64K));
|
|
if (_UI.pRecvContext2)
|
|
{
|
|
_UI.pRecvContext2->cbSize = sizeof(RecvContext2_64K);
|
|
initrecvcontext(&_UI.Context1,
|
|
(RecvContext2_Generic*)_UI.pRecvContext2,
|
|
PACKET_COMPR_TYPE_64K);
|
|
}
|
|
else
|
|
_UI.fCompress = FALSE;
|
|
}
|
|
else if (!fCompress && _UI.pRecvContext2)
|
|
{
|
|
UT_Free(_pUt, _UI.pRecvContext2);
|
|
_UI.pRecvContext2 = NULL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
} // UI_SetCompress
|
|
|
|
|
|
//
|
|
// Name: UI_GetCompress
|
|
//
|
|
BOOL DCAPI CUI::UI_GetCompress()
|
|
{
|
|
DC_BEGIN_FN("UI_GetCompress");
|
|
DC_END_FN();
|
|
return _UI.fCompress;
|
|
} // UI_GetCompress
|
|
|
|
DCUINT CUI::UI_GetAudioRedirectionMode()
|
|
{
|
|
return _UI.audioRedirectionMode;
|
|
}
|
|
|
|
VOID CUI::UI_SetAudioRedirectionMode(DCUINT audioMode)
|
|
{
|
|
DC_BEGIN_FN("UI_SetAudioRedirectionMode");
|
|
TRC_ASSERT((audioMode == UTREG_UI_AUDIO_MODE_REDIRECT ||
|
|
audioMode == UTREG_UI_AUDIO_MODE_PLAY_ON_SERVER ||
|
|
audioMode == UTREG_UI_AUDIO_MODE_NONE),
|
|
(TB,_T("Invalid audio mode passed to UI_SetAudioRedirectionMode")));
|
|
_UI.audioRedirectionMode = audioMode;
|
|
DC_END_FN();
|
|
}
|
|
|
|
BOOL CUI::UI_GetDriveRedirectionEnabled()
|
|
{
|
|
return _UI.fEnableDriveRedirection;
|
|
}
|
|
|
|
VOID CUI::UI_SetDriveRedirectionEnabled(BOOL fEnable)
|
|
{
|
|
_UI.fEnableDriveRedirection = fEnable;
|
|
}
|
|
|
|
BOOL CUI::UI_GetPrinterRedirectionEnabled()
|
|
{
|
|
return _UI.fEnablePrinterRedirection;
|
|
}
|
|
|
|
VOID CUI::UI_SetPrinterRedirectionEnabled(BOOL fEnable)
|
|
{
|
|
_UI.fEnablePrinterRedirection = fEnable;
|
|
}
|
|
|
|
BOOL CUI::UI_GetPortRedirectionEnabled()
|
|
{
|
|
return _UI.fEnablePortRedirection;
|
|
}
|
|
|
|
VOID CUI::UI_SetPortRedirectionEnabled(BOOL fEnable)
|
|
{
|
|
_UI.fEnablePortRedirection = fEnable;
|
|
}
|
|
|
|
BOOL CUI::UI_GetSCardRedirectionEnabled()
|
|
{
|
|
return _UI.fEnableSCardRedirection;
|
|
}
|
|
|
|
VOID CUI::UI_SetSCardRedirectionEnabled(BOOL fEnable)
|
|
{
|
|
_UI.fEnableSCardRedirection = fEnable;
|
|
}
|
|
|
|
VOID CUI::UI_OnDeviceChange(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
DEVICE_PARAMS DeviceParams;
|
|
|
|
DC_BEGIN_FN("UI_OnDeviceChange");
|
|
|
|
if (_fTerminating) {
|
|
DC_QUIT;
|
|
}
|
|
|
|
DeviceParams.wParam = wParam;
|
|
DeviceParams.lParam = lParam;
|
|
DeviceParams.deviceObj = _drInitData.pUpdateDeviceObj;
|
|
|
|
if (_drInitData.pUpdateDeviceObj != NULL) {
|
|
|
|
_pCd->CD_DecoupleSyncNotification(CD_RCV_COMPONENT,
|
|
_pCChan,
|
|
CD_NOTIFICATION_FUNC(CChan, OnDeviceChange),
|
|
(ULONG_PTR)(PVOID)(&DeviceParams));
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
}
|
|
|
|
//Initialize the rdpdr settings struct for this connection
|
|
//these settings get passed down to the rdpdr plugin
|
|
void CUI::UI_InitRdpDrSettings()
|
|
{
|
|
DC_BEGIN_FN("UI_InitRdpDrSettings");
|
|
|
|
// Need to reset the data only when necessary
|
|
_drInitData.fEnableRedirectedAudio = FALSE;
|
|
_drInitData.fEnableRedirectDrives = FALSE;
|
|
_drInitData.fEnableRedirectPorts = FALSE;
|
|
_drInitData.fEnableRedirectPrinters = FALSE;
|
|
|
|
_drInitData.fEnableRedirectedAudio = UI_GetAudioRedirectionMode() ==
|
|
UTREG_UI_AUDIO_MODE_REDIRECT;
|
|
|
|
_drInitData.fEnableRedirectDrives = UI_GetDriveRedirectionEnabled();
|
|
_drInitData.fEnableRedirectPrinters = UI_GetPrinterRedirectionEnabled();
|
|
_drInitData.fEnableRedirectPorts = UI_GetPortRedirectionEnabled();
|
|
_drInitData.fEnableSCardRedirection = UI_GetSCardRedirectionEnabled();
|
|
|
|
memset(_drInitData.szLocalPrintingDocName, 0,
|
|
sizeof(_drInitData.szLocalPrintingDocName));
|
|
if(!LoadString(_UI.hResDllInstance,
|
|
IDS_RDPDR_PRINT_LOCALDOCNAME,
|
|
_drInitData.szLocalPrintingDocName,
|
|
SIZECHAR(_drInitData.szLocalPrintingDocName))) {
|
|
TRC_ERR((TB,_T("LoadString IDS_RDPDR_PRINT_LOCALDOCNAME failed")));
|
|
}
|
|
|
|
memset(_drInitData.szClipCleanTempDirString, 0,
|
|
sizeof(_drInitData.szClipCleanTempDirString));
|
|
if(!LoadString(_UI.hResDllInstance,
|
|
IDS_RDPDR_CLIP_CLEANTEMPDIR,
|
|
_drInitData.szClipCleanTempDirString,
|
|
SIZECHAR(_drInitData.szClipCleanTempDirString))) {
|
|
TRC_ERR((TB,_T("LoadString IDS_RDPDR_CLIP_CLEANTEMPDIR failed")));
|
|
}
|
|
|
|
memset(_drInitData.szClipPasteInfoString, 0,
|
|
sizeof(_drInitData.szClipPasteInfoString));
|
|
if(!LoadString(_UI.hResDllInstance,
|
|
IDS_RDPDR_CLIP_PASTEINFO,
|
|
_drInitData.szClipPasteInfoString,
|
|
SIZECHAR(_drInitData.szClipPasteInfoString))) {
|
|
TRC_ERR((TB,_T("LoadString IDS_RDPDR_CLIP_PASTEINFO failed")));
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
// Clean up the LB redirect state. The load balancing cookie stuff needs to
|
|
// know when it's in the middle of a redirection.
|
|
void CUI::UI_CleanupLBState()
|
|
{
|
|
if (_UI.bstrRedirectionLBInfo)
|
|
{
|
|
SysFreeString(_UI.bstrRedirectionLBInfo);
|
|
_UI.bstrRedirectionLBInfo = NULL;
|
|
}
|
|
|
|
_UI.ClientIsRedirected = FALSE;
|
|
}
|
|
|
|
//
|
|
// Trigger a user initiated disconnection
|
|
//
|
|
// Params: discReason - disconnect reason to set
|
|
// default is NL_DISCONNECT_LOCAL
|
|
//
|
|
BOOL CUI::UI_UserInitiatedDisconnect(UINT discReason)
|
|
{
|
|
DC_BEGIN_FN("UI_UserInitiatedDisconnect");
|
|
|
|
if(UI_STATUS_DISCONNECTED == _UI.connectionStatus ||
|
|
UI_STATUS_INITIALIZING == _UI.connectionStatus)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
_UI.disconnectReason = discReason;
|
|
UIInitiateDisconnection();
|
|
return TRUE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Notify the activeX layer that core init has completed
|
|
//
|
|
BOOL CUI::UI_NotifyAxLayerCoreInit()
|
|
{
|
|
DC_BEGIN_FN("UI_NotifyAxLayerCoreInit");
|
|
|
|
if(_UI.hEvtNotifyCoreInit)
|
|
{
|
|
BOOL bRet = SetEvent(_UI.hEvtNotifyCoreInit);
|
|
|
|
// We can now close the handle to the event. This will not affect the
|
|
// waiting UI thread as hEvtNotifyCoreInit was duplicated and will
|
|
// only be destroyed if the reference count becomes zero.
|
|
|
|
CloseHandle(_UI.hEvtNotifyCoreInit);
|
|
_UI.hEvtNotifyCoreInit = NULL;
|
|
|
|
if(bRet)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ABORT((TB,_T("SetEvent _UI.hEvtNotifyCoreInit failed, err: %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
HWND CUI::UI_GetInputWndHandle()
|
|
{
|
|
DC_BEGIN_FN("UI_GetInputWndHandle");
|
|
|
|
if(_pIh)
|
|
{
|
|
return _pIh->IH_GetInputHandlerWindow();
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
HWND CUI::UI_GetBmpCacheMonitorHandle()
|
|
{
|
|
DC_BEGIN_FN("UI_GetBmpCacheMonitorHandle");
|
|
|
|
#ifdef DC_DEBUG
|
|
if(_pUh)
|
|
{
|
|
return _pUh->UH_GetBitmapCacheMonHwnd();
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
#else
|
|
//Free build has no cache monitor
|
|
return NULL;
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
//
|
|
// Injects vKeys to the IH
|
|
//
|
|
BOOL CUI::UI_InjectVKeys(/*[in]*/ LONG numKeys,
|
|
/*[in]*/ short* pfArrayKeyUp,
|
|
/*[in]*/ LONG* plKeyData)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
IH_INJECT_VKEYS_REQUEST ihrp;
|
|
DC_BEGIN_FN("UI_InjectVKeys");
|
|
|
|
if (_fTerminating) {
|
|
DC_QUIT;
|
|
}
|
|
|
|
if(UI_STATUS_CONNECTED == _UI.connectionStatus)
|
|
{
|
|
//Build a request packet and decouple the work
|
|
//to the IH. We use a sync decouple so there is
|
|
//no need to make copies of the array params
|
|
ihrp.numKeys = numKeys;
|
|
ihrp.pfArrayKeyUp = pfArrayKeyUp;
|
|
ihrp.plKeyData = plKeyData;
|
|
ihrp.fReturnStatus = FALSE;
|
|
|
|
_pCd->CD_DecoupleSyncNotification(CD_SND_COMPONENT,
|
|
_pIh,
|
|
CD_NOTIFICATION_FUNC(CIH, IH_InjectMultipleVKeys),
|
|
(ULONG_PTR)&ihrp);
|
|
fRet = ihrp.fReturnStatus;
|
|
}
|
|
else
|
|
{
|
|
fRet = FALSE;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
DC_END_FN();
|
|
return fRet;
|
|
}
|
|
|
|
BOOL CUI::UI_SetMinsToIdleTimeout(LONG minsToTimeout)
|
|
{
|
|
DC_BEGIN_FN("UI_SetMinsToIdleTimeout");
|
|
|
|
//Timers will be initialized at connection time
|
|
//see InitInputIdleTimer
|
|
if(minsToTimeout < MAX_MINS_TOIDLETIMEOUT)
|
|
{
|
|
_UI.minsToIdleTimeout = minsToTimeout;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
LONG CUI::UI_GetMinsToIdleTimeout()
|
|
{
|
|
DC_BEGIN_FN("UI_SetMinsToIdleTimeout");
|
|
|
|
DC_END_FN();
|
|
return _UI.minsToIdleTimeout;
|
|
}
|
|
|
|
DCVOID DCAPI CUI::UI_SetServerErrorInfo(ULONG_PTR errInfo)
|
|
{
|
|
DC_BEGIN_FN("UI_SetServerErrorInfo");
|
|
|
|
TRC_NRM((TB,_T("SetServerErrorInfo prev:0x%x new:0x%x"),
|
|
_UI.lastServerErrorInfo, errInfo));
|
|
|
|
_UI.lastServerErrorInfo = errInfo;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
UINT32 CUI::UI_GetServerErrorInfo()
|
|
{
|
|
DC_BEGIN_FN("UI_GetServerErrorInfo");
|
|
|
|
|
|
DC_END_FN();
|
|
return _UI.lastServerErrorInfo;
|
|
}
|
|
|
|
//
|
|
// Sets the disconnect reason. Can be called by the CD
|
|
// from other threads
|
|
//
|
|
void CUI::UI_SetDisconnectReason(ULONG_PTR reason)
|
|
{
|
|
DC_BEGIN_FN("UI_SetDisconnectReason");
|
|
|
|
_UI.disconnectReason = (DCUINT) reason;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
#ifdef USE_BBAR
|
|
void CUI::UI_OnBBarHotzoneTimerFired(ULONG_PTR unused)
|
|
{
|
|
DC_BEGIN_FN("UI_OnBBarHotzoneTimerFired");
|
|
|
|
if (_pBBar) {
|
|
_pBBar->OnBBarHotzoneFired();
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Requests a minimize, this only works in fullscreen
|
|
// If we're in container handled fullscreen then the
|
|
// request is dispatched to the container but there
|
|
// is no way to know if it was actually serviced.
|
|
//
|
|
// If we're in control handled fullscreen then
|
|
// just minimize the fullscreen window ourselves
|
|
//
|
|
BOOL CUI::UI_RequestMinimize()
|
|
{
|
|
DC_BEGIN_FN("UI_RequestMinimize");
|
|
|
|
if(UI_IsFullScreen())
|
|
{
|
|
if(_UI.fContainerHandlesFullScreenToggle)
|
|
{
|
|
//Dispatch a request to the control so
|
|
//it can fire an event requesting minimze
|
|
TRC_ASSERT( IsWindow(_UI.hWndCntrl),
|
|
(TB,_T("_UI.hWndCntrl is bad 0x%x"),
|
|
_UI.hWndCntrl));
|
|
if( IsWindow( _UI.hWndCntrl) )
|
|
{
|
|
SendMessage( _UI.hWndCntrl,
|
|
WM_TS_REQUESTMINIMIZE,
|
|
0, 0 );
|
|
}
|
|
|
|
//
|
|
// No way to know if container actually did
|
|
// what we asked, but it doesn't matter
|
|
//
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This minimizes but does not destroy the window
|
|
//
|
|
#ifndef OS_WINCE
|
|
return CloseWindow(_UI.hwndMain);
|
|
#else
|
|
ShowWindow(_UI.hwndMain, SW_MINIMIZE);
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_NRM((TB,_T("Not fullscreen minimize denied")));
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
#endif
|
|
|
|
int CUI::UI_BppToColorDepthID(int bpp)
|
|
{
|
|
int colorDepthID = CO_BITSPERPEL8;
|
|
DC_BEGIN_FN("UI_BppToColorDepthID");
|
|
|
|
switch (bpp)
|
|
{
|
|
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 %u unsupported - default to 8"),
|
|
bpp));
|
|
colorDepthID = CO_BITSPERPEL8;
|
|
}
|
|
break;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return colorDepthID;
|
|
}
|
|
|
|
int CUI::UI_GetScreenBpp()
|
|
{
|
|
HDC hdc;
|
|
int screenBpp;
|
|
DC_BEGIN_FN("UI_GetScreenBpp");
|
|
|
|
hdc = GetDC(NULL);
|
|
if(hdc)
|
|
{
|
|
screenBpp = GetDeviceCaps(hdc, BITSPIXEL);
|
|
TRC_NRM((TB, _T("HDC %p has %u bpp"), hdc, screenBpp));
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return screenBpp;
|
|
}
|
|
|
|
#ifdef SMART_SIZING
|
|
//
|
|
// Name: UI_SetSmartSizing
|
|
//
|
|
// Purpose: Save the fSmartSizing flag
|
|
//
|
|
// Params: IN fSmartSizing
|
|
//
|
|
HRESULT DCAPI CUI::UI_SetSmartSizing(BOOL fSmartSizing)
|
|
{
|
|
HWND hwndOp;
|
|
HRESULT hr = S_OK;
|
|
DC_BEGIN_FN("UI_SetSmartSizing");
|
|
|
|
TRC_NRM((TB, _T("Setting _UI.fSmartSizing to %d"), fSmartSizing));
|
|
_UI.fSmartSizing = fSmartSizing;
|
|
_UI.scrollPos.x = 0;
|
|
_UI.scrollPos.y = 0;
|
|
|
|
UIRecalculateScrollbars();
|
|
UIMoveContainerWindow();
|
|
|
|
if (_pOp) {
|
|
hwndOp = _pOp->OP_GetOutputWindowHandle();
|
|
if (hwndOp)
|
|
{
|
|
InvalidateRect(hwndOp, NULL, FALSE);
|
|
}
|
|
}
|
|
else {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
} // UI_SetSmartSizing
|
|
#endif // SMART_SIZING
|
|
|
|
BOOL CUI::UI_UserRequestedClose()
|
|
{
|
|
BOOL fRet = FALSE;
|
|
DC_BEGIN_FN("UI_UserRequestedClose");
|
|
|
|
UI_DBG_SETINFO(DBG_STAT_UIREQUESTEDCLOSE_CALLED);
|
|
|
|
//
|
|
// Call _pCo->CO_Shutdown.
|
|
//
|
|
if (UI_STATUS_CONNECTED == _UI.connectionStatus)
|
|
{
|
|
//
|
|
// Since we're connected we will start a timer in case the
|
|
// server gets stuck and doesn't process our shutdown PDU.
|
|
//
|
|
if (0 == _UI.shutdownTimer)
|
|
{
|
|
|
|
TRC_NRM((TB, _T("Setting shutdown timer is set for %u seconds"),
|
|
_UI.shutdownTimeout));
|
|
|
|
_UI.shutdownTimer = SetTimer(_UI.hwndMain,
|
|
UI_TIMER_SHUTDOWN,
|
|
1000 * _UI.shutdownTimeout,
|
|
NULL);
|
|
|
|
if (_UI.shutdownTimer)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a shame. If the server doesn't do
|
|
// anything with our shutdown PDU we'll wait
|
|
// forever. Report this as a failure so that the shell
|
|
// has an oppurtunity to do an immediate close
|
|
//
|
|
fRet = FALSE;
|
|
TRC_ERR((TB, _T("Failed to set shutdown timeout")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_NRM((TB, _T("Shutdown timer already set - leave it")));
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
|
|
_pCo->CO_Shutdown( CO_SHUTDOWN);
|
|
|
|
UI_DBG_SETINFO(DBG_STAT_UIREQUESTEDCLOSE_RET);
|
|
|
|
DC_END_FN();
|
|
return fRet;
|
|
}
|
|
|
|
//
|
|
// Notification that login has completed
|
|
// forward on to control (which fires an event)
|
|
// and CLX for debugging/test
|
|
//
|
|
void CUI::UI_OnLoginComplete()
|
|
{
|
|
DCUINT32 sessionId;
|
|
DC_BEGIN_FN("UI_OnLoginComplete");
|
|
|
|
sessionId = UI_GetSessionId();
|
|
_clx->CLX_ClxEvent(CLX_EVENT_LOGON, sessionId);
|
|
//Notify the control of the login event
|
|
SendMessage(_UI.hWndCntrl, WM_TS_LOGINCOMPLETE, 0, 0);
|
|
|
|
_pCd->CD_DecoupleSimpleNotification(CD_RCV_COMPONENT,
|
|
_pOp,
|
|
CD_NOTIFICATION_FUNC(COP,OP_DimWindow),
|
|
(ULONG_PTR)FALSE);
|
|
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
#ifdef OS_WINCE
|
|
#define LOGONID_NONE -1
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/* Name: UI_GetLocalSessionId */
|
|
/* */
|
|
/* Purpose: Retrieves the session id where the client is running. */
|
|
/****************************************************************************/
|
|
BOOL CUI::UI_GetLocalSessionId(PDCUINT32 pSessionId)
|
|
{
|
|
BOOL rc = FALSE;
|
|
DWORD dwSessionId = RNS_INFO_INVALID_SESSION_ID;
|
|
|
|
DC_BEGIN_FN("UI_GetLocalSessionId");
|
|
|
|
#ifndef OS_WINCE
|
|
|
|
HMODULE hmodule;
|
|
|
|
typedef BOOL (FNPROCESSID_TO_SESSIONID)(DWORD, DWORD*);
|
|
FNPROCESSID_TO_SESSIONID *pfnProcessIdToSessionId;
|
|
|
|
// get the handle to kernel32.dll library
|
|
hmodule = LoadLibrary(TEXT("KERNEL32.DLL"));
|
|
|
|
if (hmodule != NULL) {
|
|
|
|
rc = TRUE;
|
|
|
|
// get the proc address for ProcessIdToSessionId
|
|
pfnProcessIdToSessionId = (FNPROCESSID_TO_SESSIONID *)GetProcAddress(
|
|
hmodule, "ProcessIdToSessionId");
|
|
|
|
// get the session id
|
|
if (pfnProcessIdToSessionId != NULL) {
|
|
|
|
// We found the feature ProcessIdToSessionId.
|
|
// See if TS is really enabled on this machine
|
|
// (test valid only on Win2K and above).
|
|
if (UIIsTSOnWin2KOrGreater()) {
|
|
(*pfnProcessIdToSessionId) (GetCurrentProcessId(), &dwSessionId);
|
|
}
|
|
}
|
|
|
|
FreeLibrary(hmodule);
|
|
}
|
|
#endif //OS_WINCE
|
|
|
|
*((PDCUINT32_UA)pSessionId) = dwSessionId;
|
|
|
|
DC_END_FN()
|
|
return rc;
|
|
}
|
|
|
|
#ifdef USE_BBAR
|
|
VOID CUI::UI_SetBBarPinned(BOOL b)
|
|
{
|
|
DC_BEGIN_FN("UI_SetBBarPinned");
|
|
|
|
_UI.fBBarPinned = b;
|
|
if (_pBBar) {
|
|
_pBBar->SetPinned(b);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
BOOL CUI::UI_GetBBarPinned()
|
|
{
|
|
DC_BEGIN_FN("UI_GetBBarPinned");
|
|
|
|
if (_pBBar) {
|
|
return _pBBar->IsPinned();
|
|
}
|
|
else {
|
|
return _UI.fBBarPinned;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
|
|
DCVOID CUI::UI_OnNotifyBBarRectChange(RECT *prect)
|
|
{
|
|
if(UI_IsCoreInitialized())
|
|
_pCd->CD_DecoupleSyncNotification(CD_RCV_COMPONENT,
|
|
_pUh,
|
|
CD_NOTIFICATION_FUNC(CUH,UH_SetBBarRect),
|
|
(ULONG_PTR)prect);
|
|
}
|
|
|
|
|
|
DCVOID CUI::UI_OnNotifyBBarVisibleChange(int BBarVisible)
|
|
{
|
|
if(UI_IsCoreInitialized())
|
|
_pCd->CD_DecoupleSyncNotification(CD_RCV_COMPONENT,
|
|
_pUh,
|
|
CD_NOTIFICATION_FUNC(CUH, UH_SetBBarVisible),
|
|
(ULONG_PTR)BBarVisible);
|
|
}
|
|
#endif // DISABLE_SHADOW_IN_FULLSCREEN
|
|
#endif //USE_BBAR
|
|
|
|
VOID CUI::UI_SetControlInstance(IUnknown* pUnkControl)
|
|
{
|
|
DC_BEGIN_FN("UI_SetControlInstance");
|
|
|
|
if (_UI.pUnkAxControlInstance) {
|
|
_UI.pUnkAxControlInstance->Release();
|
|
}
|
|
|
|
_UI.pUnkAxControlInstance = pUnkControl;
|
|
|
|
if (_UI.pUnkAxControlInstance) {
|
|
_UI.pUnkAxControlInstance->AddRef();
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
IUnknown* CUI::UI_GetControlInstance()
|
|
{
|
|
DC_BEGIN_FN("UI_GetControlInstance");
|
|
|
|
if (_UI.pUnkAxControlInstance) {
|
|
_UI.pUnkAxControlInstance->AddRef();
|
|
}
|
|
|
|
DC_END_FN();
|
|
return _UI.pUnkAxControlInstance;
|
|
}
|
|
|
|
//
|
|
// Sets the autoreconnect cookie replacing existing
|
|
// Params:
|
|
// pCookie - new cookie, clear existing if NULL
|
|
// cbLen - new cookie length
|
|
// Returns status (e.g FALSE if failed)
|
|
//
|
|
BOOL CUI::UI_SetAutoReconnectCookie(PBYTE pCookie, ULONG cbLen)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
DC_BEGIN_FN("UI_SetAutoReconnectCookie");
|
|
|
|
if (_UI.pAutoReconnectCookie)
|
|
{
|
|
//For security wipe the cookie
|
|
memset(_UI.pAutoReconnectCookie, 0, _UI.cbAutoReconnectCookieLen);
|
|
//Free existing cookie
|
|
LocalFree(_UI.pAutoReconnectCookie);
|
|
_UI.pAutoReconnectCookie = NULL;
|
|
_UI.cbAutoReconnectCookieLen = 0;
|
|
}
|
|
|
|
if (pCookie && cbLen)
|
|
{
|
|
_UI.pAutoReconnectCookie = (PBYTE)LocalAlloc(LPTR,
|
|
cbLen);
|
|
if (_UI.pAutoReconnectCookie)
|
|
{
|
|
memcpy(_UI.pAutoReconnectCookie,
|
|
pCookie,
|
|
cbLen);
|
|
|
|
#ifdef INSTRUMENT_ARC
|
|
PARC_SC_PRIVATE_PACKET pArcSCPkt = (PARC_SC_PRIVATE_PACKET)
|
|
_UI.pAutoReconnectCookie;
|
|
LPDWORD pdwArcBits = (LPDWORD)pArcSCPkt->ArcRandomBits;
|
|
KdPrint(("ARC-Client:RECEIVED ARC for SID:%d"
|
|
"RAND: 0x%x,0x%x,0x%x,0x%x\n",
|
|
pArcSCPkt->LogonId,
|
|
pdwArcBits[0],pdwArcBits[1],
|
|
pdwArcBits[2],pdwArcBits[3]));
|
|
|
|
#endif
|
|
_UI.cbAutoReconnectCookieLen = cbLen;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("LocalAlloc failed for autoreconnect cookie")));
|
|
fRet = FALSE;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fRet;
|
|
}
|
|
|
|
//
|
|
// Returns TRUE if the client has the ability to autoreconnect
|
|
//
|
|
BOOL CUI::UI_CanAutoReconnect()
|
|
{
|
|
BOOL fCanARC = FALSE;
|
|
DC_BEGIN_FN("UI_CanAutoReconnect");
|
|
|
|
if (UI_GetEnableAutoReconnect() &&
|
|
UI_GetAutoReconnectCookieLen() &&
|
|
UI_GetAutoReconnectCookie())
|
|
{
|
|
fCanARC = TRUE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fCanARC;
|
|
}
|
|
|
|
BOOL CUI::UI_StartAutoReconnectDlg()
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
DC_BEGIN_FN("UI_StartAutoReconnectDlg");
|
|
|
|
TRC_ASSERT(_pArcUI == NULL,
|
|
(TB,_T("_pArcUI is already set. Clobbering!")));
|
|
|
|
//
|
|
// Startup the ARC UI
|
|
//
|
|
#ifdef ARC_MINIMAL_UI
|
|
_pArcUI = new CAutoReconnectPlainUI(_UI.hwndMain,
|
|
_UI.hInstance,
|
|
this);
|
|
#else
|
|
_pArcUI = new CAutoReconnectDlg(_UI.hwndMain,
|
|
_UI.hInstance,
|
|
this);
|
|
#endif
|
|
if (_pArcUI) {
|
|
if (_pArcUI->StartModeless()) {
|
|
_pArcUI->ShowTopMost();
|
|
|
|
//
|
|
// Start dimming the OP
|
|
//
|
|
if (_pOp) {
|
|
_pCd->CD_DecoupleSimpleNotification(CD_RCV_COMPONENT,
|
|
_pOp,
|
|
CD_NOTIFICATION_FUNC(COP,OP_DimWindow),
|
|
(ULONG_PTR)TRUE);
|
|
}
|
|
|
|
#ifdef USE_BBAR
|
|
//
|
|
// In fullscreen mode lower and lock the bbar
|
|
//
|
|
if (UI_IsFullScreen() && _pBBar && _pBBar->GetEnabled()) {
|
|
_pBBar->StartLowerBBar();
|
|
_pBBar->SetLocked(TRUE);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
TRC_ERR((TB,_T("Arc dlg failed to start modeless")));
|
|
}
|
|
}
|
|
|
|
fRet = (_pArcUI != NULL);
|
|
|
|
DC_END_FN();
|
|
return fRet;
|
|
}
|
|
|
|
BOOL CUI::UI_StopAutoReconnectDlg()
|
|
{
|
|
DC_BEGIN_FN("UI_StopAutoReconnectDlg");
|
|
|
|
if (_pArcUI) {
|
|
_pArcUI->Destroy();
|
|
delete _pArcUI;
|
|
_pArcUI = NULL;
|
|
}
|
|
|
|
#ifdef USE_BBAR
|
|
//
|
|
// Force the bbar unlocked
|
|
//
|
|
if (_pBBar) {
|
|
_pBBar->SetLocked(FALSE);
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Notification that we are autoreconnecting
|
|
//
|
|
// This is the intenal core event that is fired before
|
|
// the activex layer fires one out to the outside world
|
|
// Params:
|
|
// discReason - disconnection reason
|
|
// attemptCount - number of tries so far
|
|
// maxAttemptCount - total number of times to try
|
|
// pfContinueArc - OUT param set to FALSE to stop ARC'ing
|
|
//
|
|
VOID
|
|
CUI::UI_OnAutoReconnecting(
|
|
LONG discReason,
|
|
LONG attemptCount,
|
|
LONG maxAttemptCount,
|
|
BOOL* pfContinueArc)
|
|
{
|
|
DC_BEGIN_FN("UI_OnAutoReconnecing");
|
|
|
|
if (1 == attemptCount) {
|
|
TRC_NRM((TB,_T("Trying to start ARC dlg. Attempt count is 1")));
|
|
UI_StartAutoReconnectDlg();
|
|
}
|
|
|
|
//
|
|
// If the arc dialog is up just pass it the event
|
|
//
|
|
if (_pArcUI) {
|
|
_pArcUI->OnNotifyAutoReconnecting(discReason,
|
|
attemptCount,
|
|
maxAttemptCount,
|
|
pfContinueArc);
|
|
}
|
|
else {
|
|
//
|
|
// If no ARC dialog then don't stop ARC'ing
|
|
//
|
|
*pfContinueArc = TRUE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Received autoreconenct status from the server
|
|
//
|
|
VOID
|
|
CUI::UI_OnReceivedArcStatus(LONG arcStatus)
|
|
{
|
|
DC_BEGIN_FN("UI_OnReceivedArcStatus");
|
|
|
|
TRC_NRM((TB,_T("arcStatus: 0x%x"), arcStatus));
|
|
|
|
//
|
|
// This is our signal to undim the OP and go back to normal
|
|
// painting because ARC failed and we are sitting at winlogon
|
|
//
|
|
|
|
//
|
|
// All events are signals that autoreconnect has stopped
|
|
//
|
|
UI_OnAutoReconnectStopped();
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
VOID
|
|
CUI::UI_OnAutoReconnectStopped()
|
|
{
|
|
DC_BEGIN_FN("UI_OnAutoReconnectStopped");
|
|
|
|
|
|
if (_pArcUI) {
|
|
UI_StopAutoReconnectDlg();
|
|
}
|
|
|
|
if (_pCd && _pOp) {
|
|
|
|
_pCd->CD_DecoupleSimpleNotification(CD_RCV_COMPONENT,
|
|
_pOp,
|
|
CD_NOTIFICATION_FUNC(COP,OP_DimWindow),
|
|
(ULONG_PTR)FALSE);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
// SetServerRedirectionInfo
|
|
//
|
|
// Used on receipt of a TS_SERVER_REDIRECT_PDU to store the info needed to
|
|
// redirect the client to a new server. Sets the DoRedirection flag as well
|
|
// to indicate these data members are set and ready for use. Also sets the
|
|
// ClientIsRedirected flag, which is longer-lived than the DoRedirection
|
|
// flag and is used to send the correct cookie when redirected.
|
|
/****************************************************************************/
|
|
HRESULT
|
|
CUI::UI_SetServerRedirectionInfo(
|
|
UINT32 SessionID,
|
|
LPTSTR pszServerAddress,
|
|
PBYTE LBInfo,
|
|
unsigned LBInfoSize,
|
|
BOOL fNeedRedirect
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
DC_BEGIN_FN("UI_SetServerRedirectionInfo");
|
|
|
|
_UI.RedirectionSessionID = SessionID;
|
|
|
|
//
|
|
// We were redirected so set the flag
|
|
//
|
|
_UI.ClientIsRedirected = TRUE;
|
|
|
|
TRC_NRM((TB,_T("Set server redir info: sid:%d addr:%s lpinfo: %p")
|
|
_T("lbsize: %d fRedir:%d"),
|
|
SessionID, pszServerAddress, LBInfo,
|
|
LBInfoSize, fNeedRedirect));
|
|
|
|
if (pszServerAddress) {
|
|
|
|
hr = StringCchCopy(_UI.RedirectionServerAddress,
|
|
SIZE_TCHARS(_UI.RedirectionServerAddress),
|
|
pszServerAddress);
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
_UI.DoRedirection = fNeedRedirect;
|
|
|
|
if (LBInfoSize > 0) {
|
|
_UI.bstrRedirectionLBInfo = SysAllocStringByteLen(
|
|
(LPCSTR)LBInfo, LBInfoSize);
|
|
|
|
if (_UI.bstrRedirectionLBInfo == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
TRC_ERR((TB,
|
|
_T("RDP_SERVER_REDIRECTION_PACKET, failed to set the LB info")));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
|