|
|
//
// 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; }
|