|
|
/****************************************************************************/ /* uhapi.cpp */ /* */ /* Update Handler API */ /* */ /* Copyright(C) Microsoft Corporation 1997-1999 */ /****************************************************************************/
#include <adcg.h>
extern "C" { #define TRC_GROUP TRC_GROUP_CORE
#define TRC_FILE "uhapi"
#include <atrcapi.h>
}
#include "autil.h"
#include "uh.h"
#include "op.h"
#include "od.h"
#include "aco.h"
#include "cd.h"
#include "or.h"
#include "cc.h"
#include "wui.h"
#include "sl.h"
extern "C" { #include <stdio.h>
#ifdef OS_WINNT
#include <shlobj.h>
#endif
}
#ifdef OS_WINCE
#ifdef DC_DEBUG
#include <eosint.h>
#endif
#endif
CUH::CUH(CObjs* objs) { _pClientObjects = objs; }
CUH::~CUH() { }
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/****************************************************************************/ // UHGrabPersistentCacheLock
//
// Takes out a lock on the persistent cache directory to make sure no other
// instances of MSTSC on the system can use the cache directory.
// Returns FALSE if the lock could not be grabbed, nonzero if it was grabbed.
/****************************************************************************/ inline BOOL CUH::UHGrabPersistentCacheLock(VOID) { BOOL rc = TRUE;
DC_BEGIN_FN("UHGrabPersistentCacheLock");
_UH.hPersistentCacheLock = CreateMutex(NULL, TRUE, _UH.PersistentLockName); if (_UH.hPersistentCacheLock == NULL || GetLastError() == ERROR_ALREADY_EXISTS) { if (_UH.hPersistentCacheLock != NULL) { CloseHandle(_UH.hPersistentCacheLock); _UH.hPersistentCacheLock = NULL; } rc = FALSE; }
DC_END_FN(); return rc; }
/****************************************************************************/ // UHReleasePersistentCacheLock
//
// Releases the lock taken out with UHGrabPersistentCacheLock().
/****************************************************************************/ inline VOID CUH::UHReleasePersistentCacheLock(VOID) { DC_BEGIN_FN("UHReleasePersistentCacheLock");
if (_UH.hPersistentCacheLock != NULL) { CloseHandle(_UH.hPersistentCacheLock); _UH.hPersistentCacheLock = NULL; }
DC_END_FN(); }
/****************************************************************************/ // Wrappers for directory enumeration functions - to translate into Win32
// (non-WinCE) and Win16 enumeration methods.
//
// UHFindFirstFile returns INVALID_FILE_HANDLE on enumeration start failure.
// UHFindNextFile returns TRUE if there are more files to enumerate.
/****************************************************************************/ #if (defined(OS_WINNT) || (defined(OS_WINCE) && defined(ENABLE_BMP_CACHING_FOR_WINCE)))
inline HANDLE CUH::UHFindFirstFile( const TCHAR *Path, TCHAR *Filename, long *pFileSize) { HANDLE hSearch; WIN32_FIND_DATA FindData;
hSearch = FindFirstFile(Path, &FindData); if (hSearch != INVALID_HANDLE_VALUE) { Filename[12] = _T('\0'); _tcsncpy(Filename, FindData.cFileName, 12); *pFileSize = FindData.nFileSizeLow; }
return hSearch; }
inline BOOL CUH::UHFindNextFile( HANDLE hSearch, TCHAR *Filename, long *pFileSize) { WIN32_FIND_DATA FindData;
if (FindNextFile(hSearch, &FindData)) { Filename[12] = _T('\0'); _tcsncpy(Filename, FindData.cFileName, 12); *pFileSize = FindData.nFileSizeLow; return TRUE; }
return FALSE; }
inline void CUH::UHFindClose(HANDLE hSearch) { FindClose(hSearch); }
#endif // OS_WINNT and OS_WINCE
#ifdef OS_WINNT
inline BOOL CUH::UHGetDiskFreeSpace( TCHAR *pPathName, ULONG *pSectorsPerCluster, ULONG *pBytesPerSector, ULONG *pNumberOfFreeClusters, ULONG *pTotalNumberOfClusters) { return GetDiskFreeSpace(pPathName, pSectorsPerCluster, pBytesPerSector, pNumberOfFreeClusters, pTotalNumberOfClusters); }
#elif defined(OS_WINCE)
#ifdef ENABLE_BMP_CACHING_FOR_WINCE
inline BOOL CUH::UHGetDiskFreeSpace( TCHAR *pPathName, ULONG *pSectorsPerCluster, ULONG *pBytesPerSector, ULONG *pNumberOfFreeClusters, ULONG *pTotalNumberOfClusters) {
ULARGE_INTEGER FreeBytesAvailableToCaller; // receives the number of bytes on
// disk available to the caller
ULARGE_INTEGER TotalNumberOfBytes; // receives the number of bytes on disk
ULARGE_INTEGER TotalNumberOfFreeBytes; // receives the free bytes on disk
BOOL bRet = GetDiskFreeSpaceEx( pPathName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, &TotalNumberOfFreeBytes );
if (bRet) { // For calculation of free space, we assume that each cluster contains
// one sector, and each sector contains one byte.
*pSectorsPerCluster = 1; *pBytesPerSector = 1; *pNumberOfFreeClusters = TotalNumberOfFreeBytes.LowPart; *pTotalNumberOfClusters = TotalNumberOfBytes.LowPart; }
return bRet;
} #endif // ENABLE_BMP_CACHING_FOR_WINCE
#endif // OS_WINNT and OS_WINCE
/***************************************************************************/ // UHSendPersistentBitmapKeyList
//
// Attempts to send a persistent bitmap key PDU
/***************************************************************************/ #define UH_BM_PERSISTENT_LIST_SENDBUFSIZE 1400
VOID DCINTERNAL CUH::UHSendPersistentBitmapKeyList(ULONG_PTR unusedParm) { UINT i; ULONG curEntry; SL_BUFHND hBuf; PTS_BITMAPCACHE_PERSISTENT_LIST pList;
// Max entries we can fill into the max PDU size we will be using.
const unsigned MaxPDUEntries = ((UH_BM_PERSISTENT_LIST_SENDBUFSIZE - sizeof(TS_BITMAPCACHE_PERSISTENT_LIST)) / sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY)) + 1;
DC_BEGIN_FN("UHSendPersistentBitmapKeyList");
DC_IGNORE_PARAMETER(unusedParm);
TRC_ASSERT((_UH.bEnabled), (TB, _T("UH not enabled"))); TRC_ASSERT((_UH.bBitmapKeyEnumComplete), (TB, _T("Enumeration is not complete")));
TRC_NRM((TB, _T("Send Persistent Bitmap Key PDU")));
if (_UH.totalNumKeyEntries == 0) { for (i = 0; i < _UH.NumBitmapCaches; i++) { _UH.numKeyEntries[i] = min(_UH.numKeyEntries[i], _UH.bitmapCache[i].BCInfo.NumVirtualEntries); _UH.totalNumKeyEntries += _UH.numKeyEntries[i]; } }
if (_pSl->SL_GetBuffer(UH_BM_PERSISTENT_LIST_SENDBUFSIZE, (PPDCUINT8)&pList, &hBuf)) { // Fill in the header information - zero first then set nonzero
// fields.
memset(pList, 0, sizeof(TS_BITMAPCACHE_PERSISTENT_LIST)); pList->shareDataHeader.shareControlHeader.pduType = TS_PDUTYPE_DATAPDU | TS_PROTOCOL_VERSION; pList->shareDataHeader.shareControlHeader.pduSource = _pUi->UI_GetClientMCSID(); pList->shareDataHeader.shareID = _pUi->UI_GetShareID(); pList->shareDataHeader.streamID = TS_STREAM_LOW; pList->shareDataHeader.pduType2 = TS_PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST;
// set the first PDU flag
if (_UH.sendNumBitmapKeys == 0) pList->bFirstPDU = TRUE;
// set the last PDU flag
if (_UH.totalNumKeyEntries - _UH.sendNumBitmapKeys <= MaxPDUEntries) pList->bLastPDU = TRUE;
// Copy the total entries.
for (i = 0; i < _UH.NumBitmapCaches; i++) pList->TotalEntries[i] = (DCUINT16) _UH.numKeyEntries[i];
// Continue the entry enumeration from where we left off.
curEntry = 0; while (curEntry < MaxPDUEntries && _UH.sendBitmapCacheId < _UH.NumBitmapCaches) { if (_UH.sendBitmapCacheIndex < _UH.numKeyEntries[_UH.sendBitmapCacheId]) { // set up the Bitmap Page Table
_UH.bitmapCache[_UH.sendBitmapCacheId].PageTable.PageEntries [_UH.sendBitmapCacheIndex].bmpInfo = _UH.pBitmapKeyDB [_UH.sendBitmapCacheId][_UH.sendBitmapCacheIndex]; #ifdef DC_DEBUG
UHCacheEntryKeyLoadOnSessionStart(_UH.sendBitmapCacheId, _UH.sendBitmapCacheIndex); #endif
// fill the bitmap keys into PDU
pList->Entries[curEntry].Key1 = _UH.bitmapCache [_UH.sendBitmapCacheId].PageTable.PageEntries [_UH.sendBitmapCacheIndex].bmpInfo.Key1; pList->Entries[curEntry].Key2 = _UH.bitmapCache [_UH.sendBitmapCacheId].PageTable.PageEntries [_UH.sendBitmapCacheIndex].bmpInfo.Key2;
TRC_NRM((TB,_T("Idx: %d K1: 0x%x K2: 0x%x"), _UH.sendBitmapCacheIndex, pList->Entries[curEntry].Key1, pList->Entries[curEntry].Key2 ));
pList->NumEntries[_UH.sendBitmapCacheId]++;
// move on to the next key
_UH.sendBitmapCacheIndex++; curEntry++; } else { // move on to next cache
_UH.sendBitmapCacheId++; _UH.sendBitmapCacheIndex = 0; } }
// Send the PDU.
pList->shareDataHeader.shareControlHeader.totalLength = (TSUINT16)(sizeof(TS_BITMAPCACHE_PERSISTENT_LIST) - sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY) + (curEntry * sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY))); _pSl->SL_SendPacket((PDCUINT8)pList, pList->shareDataHeader.shareControlHeader.totalLength, RNS_SEC_ENCRYPT, hBuf, _pUi->UI_GetClientMCSID(), _pUi->UI_GetChannelID(), TS_MEDPRIORITY);
TRC_NRM((TB,_T("Sent persistent bitmap key PDU, #keys=%u"),curEntry)); _UH.sendNumBitmapKeys += curEntry;
if (_UH.sendNumBitmapKeys >= _UH.totalNumKeyEntries) { _UH.bPersistentBitmapKeysSent = TRUE; //
// now we need to send
// a zero font list PDU
//
_pFs->FS_SendZeroFontList(0); } else { // more key PDU to send
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this, CD_NOTIFICATION_FUNC(CUH,UHSendPersistentBitmapKeyList), 0); } } else { // On buffer allocation failure, UHSendPersistentBitmapKeyList will
// be retried from UH_BufferAvailable.
TRC_ALT((TB, _T("Unable to allocate buffer to send Bitmap Key PDU"))); }
DC_EXIT_POINT: DC_END_FN(); } // UHSendPersistentBitmapKeyList
/****************************************************************************/ // UHReadFromCacheFileForEnum
//
// Read a bitmap entry from the cache file for the purpose of
// enumerating keys.
/****************************************************************************/ _inline BOOL DCINTERNAL CUH::UHReadFromCacheFileForEnum(VOID) { BOOL rc = FALSE; BOOL bApiRet = FALSE; LONG filelen = 0;
DC_BEGIN_FN("UHReadFromCacheFile");
TRC_ASSERT(_UH.bBitmapKeyEnumerating, (TB,_T("UHReadFromCacheFile should only be called for enum")));
TRC_ASSERT(_UH.currentCopyMultiplier, (TB,_T("currentCopyMultiplier not set")));
// read the bitmap entry to the bitmap key database
DWORD cbRead; bApiRet = ReadFile( _UH.currentFileHandle, &_UH.pBitmapKeyDB[_UH.currentBitmapCacheId] [_UH.numKeyEntries[_UH.currentBitmapCacheId]], sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY), &cbRead, NULL ); if(bApiRet && sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY) == cbRead) { if (_UH.pBitmapKeyDB[_UH.currentBitmapCacheId][_UH.numKeyEntries [_UH.currentBitmapCacheId]].Key1 != 0 && _UH.pBitmapKeyDB[_UH.currentBitmapCacheId][_UH.numKeyEntries [_UH.currentBitmapCacheId]].Key2 != 0) { // we read a valid entry
_UH.numKeyEntries[_UH.currentBitmapCacheId]++; rc = TRUE;
// Move onto the next entry in the cache file
if((SetFilePointer(_UH.currentFileHandle, _UH.numKeyEntries[_UH.currentBitmapCacheId] * (UH_CellSizeFromCacheIDAndMult( _UH.currentBitmapCacheId, _UH.currentCopyMultiplier) + sizeof(UHBITMAPFILEHDR)), NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) && (_UH.numKeyEntries[_UH.currentBitmapCacheId] < _UH.maxNumKeyEntries[_UH.currentBitmapCacheId])) { DC_QUIT; } }
#ifdef DC_HICOLOR
// This needs to be here - or we may try to do an lseek on a file
// that's hit the end
DWORD dwRet = SetFilePointer(_UH.currentFileHandle, 0, NULL, FILE_END); if(INVALID_SET_FILE_POINTER != dwRet) { filelen = dwRet; }
if (filelen > 0) { _UH.bitmapCacheSizeInUse += filelen; } else { TRC_ABORT((TB, _T("failed SetFilePointer to end of file"))); } #endif
} else { // end of file or error in cache file.
// Close this cache file and move on to next one
TRC_ERR((TB, _T("ReadFile failed with err 0x%x"), GetLastError())); if(GetLastError() == ERROR_HANDLE_EOF) { rc = TRUE; } }
#ifndef DC_HICOLOR
DWORD dwRet = SetFilePointer(_UH.currentFileHandle, 0, NULL, FILE_END); if(INVALID_SET_FILE_POINTER != dwRet) { filelen = dwRet; }
if (filelen > 0) { _UH.bitmapCacheSizeInUse += filelen; } else { TRC_ABORT((TB, _T("failed SetFilePointer to end of file"))); } #endif //HICOLOR
CloseHandle(_UH.currentFileHandle); _UH.currentFileHandle = INVALID_HANDLE_VALUE; _UH.currentBitmapCacheId++; _UH.currentFileHandle = 0;
DC_EXIT_POINT: DC_END_FN();
return rc; }
/****************************************************************************/ // UHEnumerateBitmapKeyList
//
// Enumerate the persistent bitmap keys from disk cache
/****************************************************************************/ #define UH_ENUM_PER_POST 50
VOID DCINTERNAL CUH::UHEnumerateBitmapKeyList(ULONG_PTR unusedParm) { UINT numEnum; UINT virtualSize = 0; HRESULT hr;
DC_BEGIN_FN("UHEnumerateBitmapKeyList");
DC_IGNORE_PARAMETER(unusedParm);
numEnum = 0;
if (_UH.bBitmapKeyEnumComplete) { TRC_NRM((TB,_T("Enumeration has completed. Bailing out"))); DC_QUIT; }
if (!_UH.bBitmapKeyEnumerating) { TRC_NRM((TB,_T("Starting new enumeration for copymult:%d"), _UH.copyMultiplier)); _UH.bBitmapKeyEnumerating = TRUE;
//
// Track enumeration copy-multiplier as _UH.copyMultiplier
// can potentially change during enumeration as a UH_Enable
// call comes in
//
_UH.currentCopyMultiplier = _UH.copyMultiplier; }
//
// Can't be enumerating while complete
//
TRC_ASSERT(!(_UH.bBitmapKeyEnumerating && _UH.bBitmapKeyEnumComplete), (TB,_T("Bad state: enumerating while complete")));
// enumerate the bitmap cache directories
while (_UH.currentBitmapCacheId < _UH.RegNumBitmapCaches && numEnum < UH_ENUM_PER_POST) { // See if this cache is marked persistent.
if (_UH.RegBCInfo[_UH.currentBitmapCacheId].bSendBitmapKeys) { if (_UH.pBitmapKeyDB[_UH.currentBitmapCacheId] == NULL) { // we haven't allocate key database memory for this cache yet
// determine the max possible key database entries for this cache
virtualSize = UH_PropVirtualCacheSizeFromMult(_UH.currentCopyMultiplier); _UH.maxNumKeyEntries[_UH.currentBitmapCacheId] = virtualSize / (UH_CellSizeFromCacheIDAndMult( _UH.currentBitmapCacheId, _UH.currentCopyMultiplier) + sizeof(UHBITMAPFILEHDR));
_UH.pBitmapKeyDB[_UH.currentBitmapCacheId] = (PTS_BITMAPCACHE_PERSISTENT_LIST_ENTRY) UT_MallocHuge(_pUt, _UH.maxNumKeyEntries[_UH.currentBitmapCacheId] * sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY));
if (_UH.pBitmapKeyDB[_UH.currentBitmapCacheId] == NULL) { TRC_ERR((TB, _T("failed to alloc mem for key database"))); _UH.bBitmapKeyEnumComplete = TRUE; break; } }
if (_UH.currentFileHandle != INVALID_HANDLE_VALUE) { // we already have an open cache file
// read a bitmap's info from the cache file
UHReadFromCacheFileForEnum(); }
else { // we need to open this cache file
hr = UHSetCurrentCacheFileName(_UH.currentBitmapCacheId, _UH.currentCopyMultiplier);
if (SUCCEEDED(hr)) {
// Start the file enumeration.
#ifndef OS_WINCE
if (!_UH.fBmpCacheMemoryAlloced) { _UH.currentFileHandle = CreateFile( _UH.PersistCacheFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { //UH_Enable and UHAllocBitmapCacheMemory has been called
//and should have created the bitmap cache files. If we were
//to create file here we'd get a sharing violation so instead
//duplicated the existing handle
HANDLE hCacheFile = _UH.bitmapCache[_UH.currentBitmapCacheId].PageTable.CacheFileInfo.hCacheFile; TRC_NRM((TB,_T("About to dup handle to bmp cache file 0x%x"), hCacheFile)); if (INVALID_HANDLE_VALUE != hCacheFile) { HANDLE hCurProc = GetCurrentProcess(); if (hCurProc) { if(!DuplicateHandle(hCurProc, hCacheFile, hCurProc, &_UH.currentFileHandle, GENERIC_READ, FALSE, 0)) { TRC_ERR((TB,_T("Dup handle failed 0x%x"), GetLastError())); _UH.currentFileHandle = INVALID_HANDLE_VALUE; } } else { TRC_ERR((TB,_T("GetCurrentProcess failed 0x%x"), GetLastError())); _UH.currentFileHandle = INVALID_HANDLE_VALUE; } } else { _UH.currentFileHandle = INVALID_HANDLE_VALUE; } } #else //OS_WINCE
// CE_FIXNOTE:
// CE doesn't support duplicate handle so on a reconnect
// it is possible the CreateFile will fail with a sharing
// violation. Might need to revisit the logic and on CE only
// create the files with R/W sharing
//
_UH.currentFileHandle = CreateFile( _UH.PersistCacheFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); #endif
} else { _UH.currentFileHandle = INVALID_HANDLE_VALUE; }
if (_UH.currentFileHandle != INVALID_HANDLE_VALUE) {
// First entry of the cache file
UHReadFromCacheFileForEnum(); } else { // we can't open the cache file for this cache,
// move on to the next cache
// we also need to clear the cache file
UH_ClearOneBitmapDiskCache(_UH.currentBitmapCacheId, _UH.currentCopyMultiplier); _UH.currentBitmapCacheId++; _UH.currentFileHandle = INVALID_HANDLE_VALUE; } }
numEnum++; } else { // check next cache
_UH.currentBitmapCacheId++; _UH.currentFileHandle = INVALID_HANDLE_VALUE; } } // end of while
if (_UH.currentBitmapCacheId == _UH.RegNumBitmapCaches || _UH.bBitmapKeyEnumComplete == TRUE) { TRC_NRM((TB, _T("Finished bitmap keys enumeration for copymult:%d"), _UH.currentCopyMultiplier)); _UH.bBitmapKeyEnumComplete = TRUE; _UH.bBitmapKeyEnumerating = FALSE;
// We need to make sure we have enough disk space for persistent caching
UINT vcacheSize = UH_PropVirtualCacheSizeFromMult(_UH.currentCopyMultiplier); if (vcacheSize / _UH.BytesPerCluster >= _UH.NumberOfFreeClusters) { //
// Be careful to correctly map the array index (-1 to go 0 based)
//
_UH.PropBitmapVirtualCacheSize[_UH.currentCopyMultiplier-1] = min(vcacheSize,(_UH.bitmapCacheSizeInUse + _UH.NumberOfFreeClusters / 2 * _UH.BytesPerCluster)); } // We disable persistent caching if we don't have enough disk space
// We need at least as much as memory cache size
if (UH_PropVirtualCacheSizeFromMult(_UH.currentCopyMultiplier) < _UH.RegBitmapCacheSize) { _UH.bPersistenceDisable = TRUE; }
// UH is enabled and enumeration is finished, try to send the bitmap
// key PDU now
if (_UH.bEnabled) { if (_UH.bPersistenceActive && !_UH.bPersistentBitmapKeysSent) { if (_UH.currentCopyMultiplier == _UH.copyMultiplier) { //Great we've enumerated keys for the correct
//copy multiplier
UHSendPersistentBitmapKeyList(0); } else { //
// We got connected at a different copy multiplier
// need to enumerate keys again. Reset enumeration state
//
UHResetAndRestartEnumeration(); } } } } else { if (_UH.bitmapKeyEnumTimerId == 0) { TRC_DBG((TB, _T("Calling CD again"))); _pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this, CD_NOTIFICATION_FUNC(CUH,UHEnumerateBitmapKeyList), 0); } }
DC_EXIT_POINT:
if (_UH.bBitmapKeyEnumComplete) { _UH.bBitmapKeyEnumerating = FALSE; }
DC_END_FN(); } //UHEnumerateBitmapKeyList
/****************************************************************************/ // UH_ClearOneBitmapDiskCache
//
// remove all the files under a bitmap disk cache
/****************************************************************************/ VOID DCAPI CUH::UH_ClearOneBitmapDiskCache(UINT cacheId, UINT copyMultiplier) { DC_BEGIN_FN("UH_ClearOneBitmapDiskCache");
UHSetCurrentCacheFileName(cacheId, copyMultiplier);
DeleteFile(_UH.PersistCacheFileName);
DC_END_FN(); } #endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/****************************************************************************/ // UH_Init
//
// Purpose: Initialize _UH. Called on program init, one or more connections
// may be performed after this and before UH_Term is called.
/****************************************************************************/ DCVOID DCAPI CUH::UH_Init(DCVOID) { PDCUINT16 pIndexTable; DCUINT i; HRESULT hr;
#ifdef OS_WINCE
BOOL bUseStorageCard = FALSE; BOOL bSuccess = FALSE; #endif
DC_BEGIN_FN("UH_Init");
TRC_ASSERT(_pClientObjects, (TB,_T("_pClientObjects is NULL"))); _pClientObjects->AddObjReference(UH_OBJECT_FLAG);
#ifdef DC_DEBUG
_pClientObjects->CheckPointers(); #endif
_pGh = _pClientObjects->_pGHObject; _pOp = _pClientObjects->_pOPObject; _pSl = _pClientObjects->_pSlObject; _pUt = _pClientObjects->_pUtObject; _pFs = _pClientObjects->_pFsObject; _pOd = _pClientObjects->_pODObject; _pIh = _pClientObjects->_pIhObject; _pCd = _pClientObjects->_pCdObject; _pUi = _pClientObjects->_pUiObject; _pCc = _pClientObjects->_pCcObject; _pClx = _pClientObjects->_pCLXObject; _pOr = _pClientObjects->_pOrObject;
memset(&_UH, 0, sizeof(_UH));
//
// At UH_Init time the client hasn't connected
// yet so key the color depth off what the user
// has requested
//
switch (_pUi->_UI.colorDepthID) { case CO_BITSPERPEL8: _UH.copyMultiplier = 1; break; case CO_BITSPERPEL15: case CO_BITSPERPEL16: _UH.copyMultiplier = 2; break; case CO_BITSPERPEL24: _UH.copyMultiplier = 3; break; default: TRC_ERR((TB,_T("Unknown color depth: %d"), _pUi->UI_GetColorDepth())); _UH.copyMultiplier = 1; break; }
_UH.currentFileHandle = INVALID_HANDLE_VALUE;
_pGh->GH_Init();
/************************************************************************/ // Set up the nonzero invariant fields in the BitmapInfoHeader
// structure. This is used for processing received Bitmap PDUs.
// Note that for WinCE this is required for UHAllocBitmapCacheMemory().
/************************************************************************/ _UH.bitmapInfo.hdr.biSize = sizeof(BITMAPINFOHEADER); _UH.bitmapInfo.hdr.biPlanes = 1; _UH.bitmapInfo.hdr.biBitCount = 8; _UH.bitmapInfo.hdr.biCompression = BMCRGB; _UH.bitmapInfo.hdr.biXPelsPerMeter = 10000; _UH.bitmapInfo.hdr.biYPelsPerMeter = 10000;
/************************************************************************/ // Allocate and init the color table cache memory.
// If alloc fails then we will not later allocate and advertise bitmap
// and glyph caching capability.
// Note that bitmap cache memory and capabilities are set up during
// connection.
/************************************************************************/ if (UHAllocColorTableCacheMemory()) { TRC_NRM((TB, _T("Color table cache memory OK")));
// Init headers with default values.
for (i = 0; i < UH_COLOR_TABLE_CACHE_ENTRIES; i++) { _UH.pMappedColorTableCache[i].hdr.biSize = sizeof(BITMAPINFOHEADER); _UH.pMappedColorTableCache[i].hdr.biPlanes = 1; _UH.pMappedColorTableCache[i].hdr.biBitCount = 8; _UH.pMappedColorTableCache[i].hdr.biCompression = BMCRGB; _UH.pMappedColorTableCache[i].hdr.biSizeImage = 0; _UH.pMappedColorTableCache[i].hdr.biXPelsPerMeter = 10000; _UH.pMappedColorTableCache[i].hdr.biYPelsPerMeter = 10000; _UH.pMappedColorTableCache[i].hdr.biClrUsed = 0; _UH.pMappedColorTableCache[i].hdr.biClrImportant = 0; } } else { TRC_ERR((TB, _T("Color table cache alloc failed - bitmap caching ") _T("disabled"))); #ifdef OS_WINCE
//This and other failure paths are added for WINCE because it is difficult to
//recover from an OOM scenario on CE. So we trigger a fatal error and not let
//the connection continue in case any memory allocation fails.
DC_QUIT; #endif
}
// Allocate the glyph cache memory, set up glyph cache capabilities.
if (UHAllocGlyphCacheMemory()) TRC_NRM((TB, _T("Glyph cache memory OK"))); else #ifdef OS_WINCE
{ #endif
TRC_ERR((TB, _T("Glyph cache memory allocation failed!"))); #ifdef OS_WINCE
DC_QUIT; } #endif
// Allocate the brush cache.
if (UHAllocBrushCacheMemory()) TRC_NRM((TB, _T("Brush cache memory OK"))); else #ifdef OS_WINCE
{ #endif
TRC_ERR((TB, _T("Brush cache memory allocation failed!"))); #ifdef OS_WINCE
DC_QUIT; } #endif
// Allocate the offscreen cache
if (UHAllocOffscreenCacheMemory()) { TRC_NRM((TB, _T("Offscreen cache memory OK"))); } else { TRC_ERR((TB, _T("Offscreen cache memory allocation failed!"))); }
#ifdef DRAW_NINEGRID
// Allocate the drawninegrid cache
if (UHAllocDrawNineGridCacheMemory()) { TRC_NRM((TB, _T("DrawNineGrid cache memory OK"))); } else { TRC_ERR((TB, _T("DrawNineGrid cache memory allocation failed!"))); #ifdef OS_WINCE
DC_QUIT; #endif
} #endif
// Preload bitmap cache registry settings.
UHReadBitmapCacheSettings();
_UH.hpalDefault = (HPALETTE)GetStockObject(DEFAULT_PALETTE); _UH.hpalCurrent = _UH.hpalDefault;
_UH.hrgnUpdate = CreateRectRgn(0, 0, 0, 0); _UH.hrgnUpdateRect = CreateRectRgn(0, 0, 0, 0);
_UH.colorIndicesEnabled = TRUE; _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderFlags |= TS_ORDERFLAGS_COLORINDEXSUPPORT;
#ifdef DC_DEBUG
/************************************************************************/ /* Initialize the Bitmap Cache Monitor */ /************************************************************************/ UHInitBitmapCacheMonitor(); #endif /* DC_DEBUG */
/************************************************************************/ // We pass received bitmap data to StretchDIBits with the
// CO_DIB_PAL_COLORS option, which requires a table of indices into
// the currently selected palette in place of a color table.
//
// We set up this table here, as we always have a simple 1-1
// mapping. Start from 1 since we zeroed the 1st entry with the memset
// above.
/************************************************************************/ pIndexTable = &(_UH.bitmapInfo.paletteIndexTable[1]); for (i = 1; i < 256; i++) *pIndexTable++ = (UINT16)i; _UH.bitmapInfo.bIdentityPalette = TRUE;
/************************************************************************/ /* Set up the codepage */ /************************************************************************/ _pCc->_ccCombinedCapabilities.orderCapabilitySet.textANSICodePage = (UINT16)_pUt->UT_GetANSICodePage();
/************************************************************************/ /* Read the update frequency */ /************************************************************************/ _UH.drawThreshold = _pUi->_UI.orderDrawThreshold; if (_UH.drawThreshold == 0) { _UH.drawThreshold = (DCUINT)(-1); } TRC_NRM((TB, _T("Draw output every %d orders"), _UH.drawThreshold));
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/************************************************************************/ // Grab the mstsc's executable path for use in managing bitmap caches as
// default. _UH.EndPersistCacheDir points to the '\0' after the path.
/************************************************************************/ #ifdef OS_WINNT
if (_UH.PersistCacheFileName[0] == _T('\0')) { #define CACHE_PROFILE_NAME _T("\\Microsoft\\Terminal Server Client\\Cache\\")
// for NT5, by default, we should place the cache directory at the user profile
// location instead of where the client is installed
HRESULT hr = E_FAIL; #ifdef UNIWRAP
//Call the uniwrap SHGetFolderPath, it does the necessary dynamic
//binding and will thunk to ANSI on Win9x
hr = SHGetFolderPathWrapW(NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, _UH.PersistCacheFileName); #else //UNIWRAP not defined
HMODULE hmodSH32DLL;
#ifdef UNICODE
typedef HRESULT (STDAPICALLTYPE FNSHGetFolderPath)(HWND, int, HANDLE, DWORD, LPWSTR); #else
typedef HRESULT (STDAPICALLTYPE FNSHGetFolderPath)(HWND, int, HANDLE, DWORD, LPSTR); #endif
FNSHGetFolderPath *pfnSHGetFolderPath;
// get the handle to shell32.dll library
hmodSH32DLL = LoadLibrary(TEXT("SHELL32.DLL"));
if (hmodSH32DLL != NULL) { // get the proc address for SHGetFolderPath
#ifdef UNICODE
pfnSHGetFolderPath = (FNSHGetFolderPath *)GetProcAddress(hmodSH32DLL, "SHGetFolderPathW"); #else
pfnSHGetFolderPath = (FNSHGetFolderPath *)GetProcAddress(hmodSH32DLL, "SHGetFolderPathA"); #endif
// get the user profile local application data location
if (pfnSHGetFolderPath != NULL) { hr = (*pfnSHGetFolderPath) (NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, _UH.PersistCacheFileName); }
FreeLibrary(hmodSH32DLL); } #endif //UNIWRAP
if (SUCCEEDED(hr)) // did SHGetFolderPath succeed
{ _UH.EndPersistCacheDir = _tcslen(_UH.PersistCacheFileName); if (_UH.EndPersistCacheDir + sizeof(CACHE_PROFILE_NAME)/sizeof(TCHAR) + 1< MAX_PATH) {
//LENGTH is validated above
StringCchCopy(_UH.PersistCacheFileName + _UH.EndPersistCacheDir, MAX_PATH, CACHE_PROFILE_NAME); } } } #endif //OS_WINNT
if (_UH.PersistCacheFileName[0] == _T('\0')) { #ifdef OS_WINCE
//
// First let's see if there is a storage card.
// and if there is enough space in there, then we will use it.
//
DWORDLONG tmpDiskSize = 0; UINT32 BytesPerSector = 0, SectorsPerCluster = 0, TotalNumberOfClusters = 0, FreeClusters = 0;
// If we're scaling the bitmap caches by the bit depth, test disk
// space for 24-bit depth, otherwise test simply for 8bpp.
if (UHGetDiskFreeSpace( WINCE_STORAGE_CARD_DIRECTORY, (PULONG)&SectorsPerCluster, (PULONG)&BytesPerSector, (PULONG)&FreeClusters, (PULONG)&TotalNumberOfClusters)) { //The cast is needed to do 64bit math, without it we have
//an overflow problem
tmpDiskSize = (DWORDLONG)BytesPerSector * SectorsPerCluster * FreeClusters; if(tmpDiskSize >= (_UH.RegBitmapCacheSize * (_UH.RegScaleBitmapCachesByBPP ? 3 : 1))) { bUseStorageCard = TRUE; _tcscpy(_UH.PersistCacheFileName, WINCE_STORAGE_CARD_DIRECTORY); _tcscat(_UH.PersistCacheFileName, CACHE_DIRECTORY_NAME); } } else { #endif
_UH.EndPersistCacheDir = GetModuleFileName(_pUi->UI_GetInstanceHandle(), _UH.PersistCacheFileName, MAX_PATH - sizeof(CACHE_DIRECTORY_NAME)/sizeof(TCHAR)); if (_UH.EndPersistCacheDir > 0) { // Strip the module name off the end to leave the executable
// directory path, by looking for the last backslash.
_UH.EndPersistCacheDir--; while (_UH.EndPersistCacheDir != 0) { if (_UH.PersistCacheFileName[_UH.EndPersistCacheDir] != _T('\\')) { _UH.EndPersistCacheDir--; continue; }
_UH.EndPersistCacheDir++; break; }
// we should set up persistent cache disk directory
_UH.PersistCacheFileName[_UH.EndPersistCacheDir] = _T('\0');
// Check we have enough space for the base path + the dir name
if ((_UH.EndPersistCacheDir + _tcslen(CACHE_DIRECTORY_NAME) + 1) < MAX_PATH) {
//
// Length checked above
//
StringCchCopy(_UH.PersistCacheFileName + _UH.EndPersistCacheDir, MAX_PATH, CACHE_DIRECTORY_NAME); } else { _UH.bPersistenceDisable = TRUE; } } else { // since we can't find the mstsc path, we can't determine where
// to store the bitmaps on disk. So, we simply disable the
// persistence bitmap here
_UH.bPersistenceDisable = TRUE; TRC_ERR((TB,_T("GetModuleFileName() error, could not retrieve path"))); } #ifdef OS_WINCE // OS_WINCE
} #endif // OS_WINCE
} _UH.EndPersistCacheDir = _tcslen(_UH.PersistCacheFileName);
// Make sure _UH.PersistCacheFileName ends with a \ for directory name
if (_UH.PersistCacheFileName[_UH.EndPersistCacheDir - 1] != _T('\\')) { _UH.PersistCacheFileName[_UH.EndPersistCacheDir] = _T('\\'); _UH.PersistCacheFileName[++_UH.EndPersistCacheDir] = _T('\0'); }
// Check that our path is not too long to contain the base path
// plus each cache filename. If so, we can't use the path.
if ((_UH.EndPersistCacheDir + CACHE_FILENAME_LENGTH + 1) >= MAX_PATH) { TRC_ERR((TB,_T("Base cache path \"%s\" too long, cannot load ") _T("persistent bitmaps"), _UH.PersistCacheFileName)); _UH.bPersistenceDisable = TRUE; }
/*********************************************************************/ // To make sure we have enough space to hold the virtual memory cache
// we should check the free disk space
/*********************************************************************/ // make sure we don't have a UNC app path
#ifndef OS_WINCE
if (_UH.PersistCacheFileName[0] != _T('\\')) { #else
if (_UH.PersistCacheFileName[0] != _T('\0')) { // path in wince is of the form "\Windows\Cache"
#endif
UINT32 BytesPerSector = 0, SectorsPerCluster = 0, TotalNumberOfClusters = 0;
#ifndef OS_WINCE
TCHAR RootPath[4]; _tcsncpy(RootPath, _UH.PersistCacheFileName, 3); RootPath[3] = _T('\0'); #endif
// Get disk information
if (UHGetDiskFreeSpace( #ifndef OS_WINCE
RootPath, #else
(bUseStorageCard) ? WINCE_STORAGE_CARD_DIRECTORY : WINCE_FILE_SYSTEM_ROOT , #endif
(PULONG)&SectorsPerCluster, (PULONG)&BytesPerSector, &_UH.NumberOfFreeClusters, (PULONG)&TotalNumberOfClusters)) { _UH.BytesPerCluster = BytesPerSector * SectorsPerCluster; } else { // we can't get disk info, we have to turn the persistent flag off
_UH.bPersistenceDisable = TRUE; } } else { // we don't support network disk
_UH.bPersistenceDisable = TRUE; }
/*********************************************************************/ // If the persistent is not disabled,we need to lock the persistent disk
// cache before another session grabs it. If we failed to get the cache
// lock, persistent caching is not supported for this session
/*********************************************************************/ if (!_UH.bPersistenceDisable) { unsigned len;
// Compose lock name, it's based on the cache directory name
#if (defined(OS_WINCE))
_tcscpy(_UH.PersistentLockName, TEXT("MSTSC_")); len = _tcslen(_UH.PersistentLockName); #else
// For Terminal server platforms, we need to use global in
// persistentlockname to make sure the locking is cross sessions.
// but on non-terminal server NT platforms, we can't use global
// as the lock name. (in createmutex)
if (_pUt->UT_IsTerminalServicesEnabled()) { hr = StringCchCopy(_UH.PersistentLockName, SIZE_TCHARS(_UH.PersistentLockName), TEXT("Global\\MSTSC_")); } else { hr = StringCchCopy(_UH.PersistentLockName, SIZE_TCHARS(_UH.PersistentLockName), TEXT("MSTSC_")); } //Lock name should fit since it's a fixed format
TRC_ASSERT(SUCCEEDED(hr), (TB,_T("Error copying persistent lock name: 0x%x"), hr)); len = _tcslen(_UH.PersistentLockName); #endif
for (i = 0; i < _UH.EndPersistCacheDir; i++) { // Tried to use _istalnum for 2nd clause, but CRTDLL doesn't
// like it.
if (_UH.PersistCacheFileName[i] == _T('\\')) _UH.PersistentLockName[len++] = _T('_'); else if ((_UH.PersistCacheFileName[i] >= _T('0') && _UH.PersistCacheFileName[i] <= _T('9')) || (_UH.PersistCacheFileName[i] >= _T('A') && _UH.PersistCacheFileName[i] <= _T('Z')) || (_UH.PersistCacheFileName[i] >= _T('a') && _UH.PersistCacheFileName[i] <= _T('z'))) _UH.PersistentLockName[len++] = _UH.PersistCacheFileName[i]; } _UH.PersistentLockName[len] = _T('\0');
// try to lock the cache directory for persistent caching
if (!UHGrabPersistentCacheLock()) { _UH.bPersistenceDisable = TRUE; } }
/********************************************************************/ // We need to enumerate the disk to get the bitmap key database
// The client will always enumerate the keys even the persistent
// caching option might be changed later on.
/********************************************************************/ if (!_UH.bPersistenceDisable) { _pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this, CD_NOTIFICATION_FUNC(CUH,UHEnumerateBitmapKeyList), 0); } #endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
#ifdef DRAW_GDIPLUS
// Initialize fGdipEnabled
_UH.fGdipEnabled = FALSE; #endif
#ifdef OS_WINCE
bSuccess = TRUE; DC_EXIT_POINT: if (!bSuccess) { _pCd->CD_DecoupleSimpleNotification(CD_UI_COMPONENT, _pUi, CD_NOTIFICATION_FUNC(CUI,UI_FatalError), (ULONG_PTR) DC_ERR_OUTOFMEMORY); } #endif
DC_END_FN(); } /* UH_Init */
/****************************************************************************/ // UH_Term
//
// Terminates _UH. Called on app exit.
/****************************************************************************/ DCVOID DCAPI CUH::UH_Term(DCVOID) {
DC_BEGIN_FN("UH_Term");
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// unlock the persistent cache directory if this session locked it earlier
UHReleasePersistentCacheLock();
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
#ifdef DRAW_GDIPLUS
UHDrawGdiplusShutdown(0); #endif
/************************************************************************/ /* Free off any bitmaps that are specific to the connection. */ /************************************************************************/ if (NULL != _UH.hShadowBitmap) { /********************************************************************/ /* Delete the Shadow Bitmap. */ /********************************************************************/ TRC_NRM((TB, _T("Delete the Shadow Bitmap"))); UHDeleteBitmap(&_UH.hdcShadowBitmap, &_UH.hShadowBitmap, &_UH.hunusedBitmapForShadowDC); }
if (NULL != _UH.hSaveScreenBitmap) { /********************************************************************/ /* Delete the Save Bitmap. */ /********************************************************************/ TRC_NRM((TB, _T("Delete save screen bitmap"))); UHDeleteBitmap(&_UH.hdcSaveScreenBitmap, &_UH.hSaveScreenBitmap, &_UH.hunusedBitmapForSSBDC); }
if (NULL != _UH.hbmpDisconnectedBitmap) { UHDeleteBitmap(&_UH.hdcDisconnected, &_UH.hbmpDisconnectedBitmap, &_UH.hbmpUnusedDisconnectedBitmap); }
// Delete all the offscreen bitmaps
if (NULL != _UH.hdcOffscreenBitmap) { unsigned i; for (i = 0; i < _UH.offscrCacheEntries; i++) { if (_UH.offscrBitmapCache[i].offscrBitmap) { SelectBitmap(_UH.hdcOffscreenBitmap, _UH.hUnusedOffscrBitmap); DeleteBitmap(_UH.offscrBitmapCache[i].offscrBitmap); } } }
#ifdef DRAW_NINEGRID
// Delete all the drawNineGrid bitmaps
if (NULL != _UH.hdcDrawNineGridBitmap) { unsigned i; for (i = 0; i < _UH.drawNineGridCacheEntries; i++) { if (_UH.drawNineGridBitmapCache[i].drawNineGridBitmap) { SelectBitmap(_UH.hdcDrawNineGridBitmap, _UH.hUnusedDrawNineGridBitmap); DeleteBitmap(_UH.drawNineGridBitmapCache[i].drawNineGridBitmap); } } } #endif
#ifdef DC_DEBUG
/************************************************************************/ /* Terminate the Bitmap Cache Monitor */ /************************************************************************/ UHTermBitmapCacheMonitor(); #endif /* DC_DEBUG */
DeleteRgn(_UH.hrgnUpdate); DeleteRgn(_UH.hrgnUpdateRect);
UHFreeCacheMemory();
/************************************************************************/ // Free the palette (if not the default). This needs to happen after
// freeing bitmap cache resources so the palettes can be written to disk
// with the bitmap files.
/************************************************************************/ if ((_UH.hpalCurrent != NULL) && (_UH.hpalCurrent != _UH.hpalDefault)) { TRC_NRM((TB, _T("Delete current palette %p"), _UH.hpalCurrent)); DeletePalette(_UH.hpalCurrent); }
/************************************************************************/ // If we created a decompression buffer, get rid of it now.
/************************************************************************/ if (_UH.bitmapDecompressionBuffer != NULL) { UT_Free( _pUt, _UH.bitmapDecompressionBuffer); _UH.bitmapDecompressionBuffer = NULL; _UH.bitmapDecompressionBufferSize = 0; }
/************************************************************************/ // Release cached glyph resources
/************************************************************************/ if (_UH.hdcGlyph != NULL) { DeleteDC(_UH.hdcGlyph); _UH.hdcGlyph = NULL; }
if (_UH.hbmGlyph != NULL) { DeleteObject(_UH.hbmGlyph); _UH.hbmGlyph = NULL; }
if (_UH.hdcBrushBitmap != NULL) { DeleteDC(_UH.hdcBrushBitmap); _UH.hdcBrushBitmap = NULL; }
// Release the offscreen bitmap DC
if (_UH.hdcOffscreenBitmap != NULL) { DeleteDC(_UH.hdcOffscreenBitmap); }
#ifdef DRAW_NINEGRID
// Release the drawninegrid bitmap DC
if (_UH.hdcDrawNineGridBitmap != NULL) { DeleteDC(_UH.hdcDrawNineGridBitmap); _UH.hdcDrawNineGridBitmap = NULL; }
if (_UH.hDrawNineGridClipRegion != NULL) { DeleteObject(_UH.hDrawNineGridClipRegion); _UH.hdcDrawNineGridBitmap = NULL; }
if (_UH.drawNineGridDecompressionBuffer != NULL) { UT_Free( _pUt, _UH.drawNineGridDecompressionBuffer); _UH.drawNineGridDecompressionBuffer = NULL; _UH.drawNineGridDecompressionBufferSize = 0; }
if (_UH.drawNineGridAssembleBuffer != NULL) { UT_Free( _pUt, _UH.drawNineGridAssembleBuffer); _UH.drawNineGridAssembleBuffer = NULL; }
if (_UH.hModuleGDI32 != NULL) { FreeLibrary(_UH.hModuleGDI32); _UH.hModuleGDI32 = NULL; }
if (_UH.hModuleMSIMG32 != NULL) { FreeLibrary(_UH.hModuleMSIMG32); _UH.hModuleMSIMG32 = NULL; } #endif
_pClientObjects->ReleaseObjReference(UH_OBJECT_FLAG);
DC_END_FN(); } /* UH_Term */
#ifdef DC_DEBUG
/****************************************************************************/ /* Name: UH_ChangeDebugSettings */ /* */ /* Purpose: Changes the current debug settings. */ /* */ /* Params: IN - flags: */ /* CO_CFG_FLAG_HATCH_BITMAP_PDU_DATA */ /* CO_CFG_FLAG_HATCH_SSB_ORDER_DATA */ /* CO_CFG_FLAG_HATCH_MEMBLT_ORDER_DATA */ /* CO_CFG_FLAG_LABEL_MEMBLT_ORDERS */ /* CO_CFG_FLAG_BITMAP_CACHE_MONITOR */ /****************************************************************************/ DCVOID DCAPI CUH::UH_ChangeDebugSettings(ULONG_PTR flags) { DC_BEGIN_FN("UH_ChangeDebugSettings");
TRC_NRM((TB, _T("flags %#x"), flags));
_UH.hatchBitmapPDUData = TEST_FLAG(flags, CO_CFG_FLAG_HATCH_BITMAP_PDU_DATA) ? TRUE : FALSE;
_UH.hatchIndexPDUData = TEST_FLAG(flags, CO_CFG_FLAG_HATCH_INDEX_PDU_DATA) ? TRUE : FALSE;
_UH.hatchSSBOrderData = TEST_FLAG(flags, CO_CFG_FLAG_HATCH_SSB_ORDER_DATA) ? TRUE : FALSE;
_UH.hatchMemBltOrderData = TEST_FLAG(flags, CO_CFG_FLAG_HATCH_MEMBLT_ORDER_DATA) ? TRUE : FALSE;
_UH.labelMemBltOrders = TEST_FLAG(flags, CO_CFG_FLAG_LABEL_MEMBLT_ORDERS) ? TRUE : FALSE;
_UH.showBitmapCacheMonitor = TEST_FLAG(flags, CO_CFG_FLAG_BITMAP_CACHE_MONITOR) ? TRUE : FALSE;
ShowWindow( _UH.hwndBitmapCacheMonitor, _UH.showBitmapCacheMonitor ? SW_SHOWNOACTIVATE : SW_HIDE );
DC_END_FN(); } #endif /* DC_DEBUG */
/****************************************************************************/ // UH_SetConnectOptions
//
// Called on receive thread at session connect time. Takes some connection
// flags from CC and does connect-time init.
//
// Params: connectFlags - flags used to determine whether to enable
// the Shadow Bitmap and SaveScreenBitmap order support.
/****************************************************************************/ DCVOID DCAPI CUH::UH_SetConnectOptions(ULONG_PTR connectFlags) { DC_BEGIN_FN("UH_SetConnectOptions");
/************************************************************************/ /* Get the flags out. */ /************************************************************************/ _UH.shadowBitmapRequested = ((connectFlags & CO_CONN_FLAG_SHADOW_BITMAP_ENABLED) ? TRUE : FALSE); _UH.dedicatedTerminal = ((connectFlags & CO_CONN_FLAG_DEDICATED_TERMINAL) ? TRUE : FALSE);
TRC_NRM((TB, _T("Flags from CC shadow(%u), terminal(%u)"), _UH.shadowBitmapRequested, _UH.dedicatedTerminal));
/************************************************************************/ /* Set the capabilities to not support SSB and ScreenBlt orders by */ /* default. These are only supported if the shadow bitmap is enabled. */ /************************************************************************/ _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_SAVEBITMAP_INDEX] = 0; _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_SCRBLT_INDEX] = 0;
// We have not yet sent the persistent bitmap cache keys in this session.
_UH.bPersistentBitmapKeysSent = FALSE;
// We have not yet set up the post-DemandActivePDU capabilities for bitmap
// caching, nor allocated the caches.
_UH.bEnabledOnce = FALSE;
DC_END_FN(); } /* UH_SetConnectOptions */
/****************************************************************************/ // UH_BufferAvailable
//
// When there is available buffer, we try to send the persistent keys
// and the font list
/****************************************************************************/ VOID DCAPI CUH::UH_BufferAvailable(VOID) { DC_BEGIN_FN("UH_BufferAvailable");
// UH_BufferAvailable is called when there is an available send
// buffer. If so, it tries to send persistent key list if any,
// and the font list
UH_SendPersistentKeysAndFontList();
DC_END_FN(); }
/****************************************************************************/ // UH_SendPersistentKeysAndFontList
//
// Send persistent key list followed by font list if they are ready to be
// send. If we don't have to send any persistent key list, we simply send
// font list directly.
/****************************************************************************/ void DCAPI CUH::UH_SendPersistentKeysAndFontList(void) { DC_BEGIN_FN("UH_BufferAvailable");
if (_UH.bEnabled) { #if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
if (_UH.bPersistenceActive) { if (_UH.bBitmapKeyEnumComplete) { if (!_UH.bPersistentBitmapKeysSent) { if (_UH.currentCopyMultiplier == _UH.copyMultiplier) { //Great we've enumerated keys for the correct
//copy multiplier
UHSendPersistentBitmapKeyList(0); } else { //
// We got connected at a different copy multiplier
// need to enumerate keys again. Reset enumeration state
//
UHResetAndRestartEnumeration(); } } else { _pFs->FS_SendZeroFontList(0); } } } else { #endif //((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
_pFs->FS_SendZeroFontList(0); #if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
} #endif //((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
} DC_END_FN(); }
/****************************************************************************/ // UH_Enable
//
// Enables _UH. Called on receive thread after receipt of DemandActivePDU
// containing the server-side capabilities, but before client caps are
// returned with a ConfirmActivePDU.
//
// Params: IN unused - required by the component decoupler.
/****************************************************************************/ void DCAPI CUH::UH_Enable(ULONG_PTR unused) { HBRUSH hbr; RECT rect; DCSIZE desktopSize; #ifdef DRAW_GDIPLUS
unsigned ProtocolColorDepth; unsigned rc; #endif
#ifdef DC_HICOLOR
int colorDepth; UINT16 FAR *pIndexTable; DWORD *pColorTable; unsigned i; #endif
DC_BEGIN_FN("UH_Enable");
DC_IGNORE_PARAMETER(unused);
if (NULL != _UH.hbmpDisconnectedBitmap) { UHDeleteBitmap(&_UH.hdcDisconnected, &_UH.hbmpDisconnectedBitmap, &_UH.hbmpUnusedDisconnectedBitmap); }
#ifdef DC_HICOLOR
// Set up the bitmap color format. Has to be first thing we do here!
colorDepth = _pUi->UI_GetColorDepth(); if ((colorDepth == 4) || (colorDepth == 8)) { TRC_NRM((TB, _T("Low color - use PAL"))); _UH.DIBFormat = DIB_PAL_COLORS; _UH.copyMultiplier = 1; _UH.protocolBpp = 8; _UH.bitmapBpp = 8;
_UH.bitmapInfo.hdr.biCompression = BMCRGB; _UH.bitmapInfo.hdr.biBitCount = 8; _UH.bitmapInfo.hdr.biClrUsed = 0;
// Update the color table cache - if we've previously connected at
// a high color depth, the bitcounts will be wrong.
if (_UH.pMappedColorTableCache) { TRC_DBG((TB, _T("Update color table cache to 8bpp"))); for (i = 0; i < UH_COLOR_TABLE_CACHE_ENTRIES; i++) { _UH.pMappedColorTableCache[i].hdr.biBitCount = 8; _UH.pMappedColorTableCache[i].hdr.biCompression = BI_RGB; _UH.pMappedColorTableCache[i].hdr.biClrUsed = 0;
pColorTable = (DWORD *) _UH.pMappedColorTableCache[i].paletteIndexTable; pColorTable[0] = 0; pColorTable[1] = 0; pColorTable[2] = 0;
// We default to identity palette flag set for 4 and 8 bits,
// this may be changed when the server sends a color table.
_UH.pMappedColorTableCache[i].bIdentityPalette = TRUE; } }
// Similarly, a high color connection may have overwritten some
// entries here too.
pIndexTable = _UH.bitmapInfo.paletteIndexTable; for (i = 0; i < 256; i++) *pIndexTable++ = (UINT16)i; _UH.bitmapInfo.bIdentityPalette = TRUE; } else { TRC_NRM((TB, _T("Hi color - use RGB"))); _UH.DIBFormat = DIB_RGB_COLORS; _UH.protocolBpp = colorDepth;
// Since we don't use palettes for these color depths,
// set the BitmapPDU palette identity flag so UHDIBCopyBits() will
// always do a straight copy.
_UH.bitmapInfo.bIdentityPalette = TRUE;
if (colorDepth == 24) { TRC_DBG((TB, _T("24bpp"))); _UH.bitmapInfo.hdr.biBitCount = 24; _UH.bitmapBpp = 24; _UH.copyMultiplier = 3; _UH.bitmapInfo.hdr.biCompression = BI_RGB; _UH.bitmapInfo.hdr.biClrUsed = 0;
// Update the color table cache - though we won't use the color
// tables as such, the bitmap info will be used.
if (_UH.pMappedColorTableCache) { TRC_DBG((TB, _T("Update color table cache to 24bpp"))); for (i = 0; i < UH_COLOR_TABLE_CACHE_ENTRIES; i++) { _UH.pMappedColorTableCache[i].hdr.biBitCount = 24; _UH.pMappedColorTableCache[i].hdr.biCompression = BI_RGB; _UH.pMappedColorTableCache[i].hdr.biClrUsed = 0;
pColorTable = (DWORD *) _UH.pMappedColorTableCache[i].paletteIndexTable; pColorTable[0] = 0; pColorTable[1] = 0; pColorTable[2] = 0;
// Since we don't use palettes for this color depth,
// set the palettes to identity so UHDIBCopyBits() will
// always do a straight copy.
_UH.pMappedColorTableCache[i].bIdentityPalette = TRUE; } } } else if (colorDepth == 16) { TRC_DBG((TB, _T("16bpp - 565")));
// 16 bpp uses two bytes, with the color masks defined in the
// bmiColors field. This is supposedly in the order R, G, B,
// but as ever we have to swap R & B...
// - LS 5 bits = blue = 0x001f
// - next 6 bits = green mask = 0x07e0
// - next 5 bits = red mask = 0xf800
_UH.bitmapInfo.hdr.biBitCount = 16; _UH.bitmapBpp = 16; _UH.copyMultiplier = 2; _UH.bitmapInfo.hdr.biCompression = BI_BITFIELDS; _UH.bitmapInfo.hdr.biClrUsed = 3;
pColorTable = (DWORD *)_UH.bitmapInfo.paletteIndexTable; pColorTable[0] = TS_RED_MASK_16BPP; pColorTable[1] = TS_GREEN_MASK_16BPP; pColorTable[2] = TS_BLUE_MASK_16BPP;
// Update the color table cache - though we won't use the color
// tables as such, the bitmap info will be used.
if (_UH.pMappedColorTableCache) { TRC_DBG((TB, _T("Update color table cache to 16bpp"))); for (i = 0; i < UH_COLOR_TABLE_CACHE_ENTRIES; i++) { _UH.pMappedColorTableCache[i].hdr.biBitCount = 16; _UH.pMappedColorTableCache[i].hdr.biCompression = BI_BITFIELDS; _UH.pMappedColorTableCache[i].hdr.biClrUsed = 3;
pColorTable = (DWORD *) _UH.pMappedColorTableCache[i].paletteIndexTable; pColorTable[0] = TS_RED_MASK_16BPP; pColorTable[1] = TS_GREEN_MASK_16BPP; pColorTable[2] = TS_BLUE_MASK_16BPP;
// Since we don't use palettes for this color depth,
// set the palettes to identity so UHDIBCopyBits() will
// always do a straight copy.
_UH.pMappedColorTableCache[i].bIdentityPalette = TRUE; } } } else if (colorDepth == 15) { TRC_DBG((TB, _T("15bpp - 16bpp & 555")));
// 15 bpp uses two bytes with - least significant 5 bits = blue
// - next 5 bits = green - next 5 = red - most significant bit
// = Not used
// Note that we still have to claim to be 16 bpp to the bitmap
// functions...
_UH.bitmapInfo.hdr.biBitCount = 16; _UH.bitmapBpp = 16; _UH.copyMultiplier = 2; _UH.bitmapInfo.hdr.biCompression = BI_RGB; _UH.bitmapInfo.hdr.biClrUsed = 0;
// Update the color table cache - though we won't use the color
// tables as such, the bitmap info will be used.
if (_UH.pMappedColorTableCache) { TRC_DBG((TB, _T("Update color table cache to 15bpp"))); for (i = 0; i < UH_COLOR_TABLE_CACHE_ENTRIES; i++) { _UH.pMappedColorTableCache[i].hdr.biBitCount = 16; _UH.pMappedColorTableCache[i].hdr.biCompression = BI_RGB; _UH.pMappedColorTableCache[i].hdr.biClrUsed = 0;
pColorTable = (DWORD *) _UH.pMappedColorTableCache[i].paletteIndexTable; pColorTable[0] = 0; pColorTable[1] = 0; pColorTable[2] = 0;
// Since we don't use palettes for this color depth,
// set the palettes to identity so UHDIBCopyBits() will
// always do a straight copy.
_UH.pMappedColorTableCache[i].bIdentityPalette = TRUE; } } } else { TRC_ABORT((TB, _T("Unsupported color depth"))); } } #endif //HICOLOR
// Check and see if we have already set up the caps and allocated the
// memory. If so, don't repeat the work since we are simply reconnecting
// instead of disconnecting.
if (!_UH.bEnabledOnce) { _UH.bEnabledOnce = TRUE;
TRC_ALT((TB, _T("Doing one-time enabling")));
// We are connected.
_UH.bConnected = TRUE;
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
_UH.DontUseShadowBitmap = FALSE; #endif
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// reset flags
_UH.sendBitmapCacheId = 0; _UH.sendBitmapCacheIndex = 0; _UH.sendNumBitmapKeys = 0; _UH.totalNumKeyEntries = 0; _UH.totalNumErrorPDUs = 0; #endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
_UH.bWarningDisplayed = FALSE; _UH.bPersistentBitmapKeysSent = FALSE;
// No matter what we have to make sure the capabilities are initialized
// to empty -- any leftover settings from the previous connection are
// invalid. Also make sure it's set to rev1 caps so that the server
// will disable bitmap caching if the bitmap caches cannot be
// allocated.
memset(&_pCc->_ccCombinedCapabilities.bitmapCacheCaps, 0, sizeof(TS_BITMAPCACHE_CAPABILITYSET)); _pCc->_ccCombinedCapabilities.bitmapCacheCaps.lengthCapability = sizeof(TS_BITMAPCACHE_CAPABILITYSET); _pCc->_ccCombinedCapabilities.bitmapCacheCaps.capabilitySetType = TS_CAPSETTYPE_BITMAPCACHE;
// Allocate the bitmap cache memory. This is done during connect time
// because we depend on the server capabilities already processed in
// UH_ProcessBCHostSupportCaps. It is also dependent on the color table
// cache having been allocated on app init.
if (_UH.pColorTableCache != NULL && _UH.pMappedColorTableCache != NULL) { UHAllocBitmapCacheMemory(); _UH.fBmpCacheMemoryAlloced = TRUE; } else { TRC_ERR((TB,_T("Color table cache did not alloc, not allocating bitmap ") _T("cache memory and caps"))); } #ifdef DRAW_GDIPLUS
// Allocate the drawgdiplus cache
if (UHAllocDrawGdiplusCacheMemory()) { TRC_NRM((TB, _T("DrawGdiplus cache memory OK"))); } else { TRC_ALT((TB, _T("DrawGdiplus cache memory allocation failed!"))); } #endif
#ifdef DC_DEBUG
// Reset the Bitmap Cache Monitor.
UHEnableBitmapCacheMonitor(); #endif /* DC_DEBUG */
#ifdef DC_HICOLOR
// Allocate the screen data decompression buffer, allowing enough
// space for 24bpp regardless of the actual depth, as we might find
// ourselves shadowing a 24bpp session without the opportunity to
// reallocate it. We don't check for success here since we can't
// return an init error. Instead, we check the pointer whenever we
// decode screen data.
_UH.bitmapDecompressionBufferSize = max( UH_DECOMPRESSION_BUFFER_LENGTH, (TS_BITMAPCACHE_0_CELL_SIZE << (2*(_UH.NumBitmapCaches))) * 3); _UH.bitmapDecompressionBuffer = (PDCUINT8)UT_Malloc( _pUt, _UH.bitmapDecompressionBufferSize); #else
// Allocate the screen data decompression buffer. We don't check for
// success here since we can't return an init error. Instead, we
// check the pointer whenever we decode screen data.
_UH.bitmapDecompressionBufferSize = max( UH_DECOMPRESSION_BUFFER_LENGTH, UH_CellSizeFromCacheID(_UH.NumBitmapCaches)); _UH.bitmapDecompressionBuffer = (PBYTE)UT_Malloc( _pUt, _UH.bitmapDecompressionBufferSize); #endif //HICOLOR
if (NULL == _UH.bitmapDecompressionBuffer) { _UH.bitmapDecompressionBufferSize = 0; }
#ifdef OS_WINCE
if (_UH.bitmapDecompressionBuffer == NULL) _pUi->UI_FatalError(DC_ERR_OUTOFMEMORY); #endif
// Get a DC for the Output Window.
_UH.hdcOutputWindow = GetDC(_pOp->OP_GetOutputWindowHandle()); TRC_ASSERT(_UH.hdcOutputWindow, (TB,_T("_UH.hdcOutputWindow is NULL, GetDC failed"))); if (!_UH.hdcOutputWindow) _pUi->UI_FatalError(DC_ERR_OUTOFMEMORY); // Reset maxColorTableId. We only expect to reset our color cache
// once in a session.
_UH.maxColorTableId = -1; } #ifdef DC_HICOLOR
else if (_UH.BitmapCacheVersion > TS_BITMAPCACHE_REV1) { //
// If the new color depth doesn't match the one we enumerated
// keys for the block persitent caching
//
if (_UH.currentCopyMultiplier != _UH.copyMultiplier) { TS_BITMAPCACHE_CAPABILITYSET_REV2 *pRev2Caps; pRev2Caps = (TS_BITMAPCACHE_CAPABILITYSET_REV2 *) &_pCc->_ccCombinedCapabilities.bitmapCacheCaps;
for (i = 0; i < _UH.NumBitmapCaches; i++) { CALC_NUM_CACHE_ENTRIES(_UH.bitmapCache[i].BCInfo.NumEntries, _UH.bitmapCache[i].BCInfo.OrigNumEntries, _UH.bitmapCache[i].BCInfo.MemLen - UH_CellSizeFromCacheID(i), i);
TRC_ALT((TB, _T("Cache %d has %d entries"), i, _UH.bitmapCache[i].BCInfo.NumEntries));
pRev2Caps->CellCacheInfo[i].NumEntries = _UH.bitmapCache[i].BCInfo.NumEntries;
// If we've got persistent caching on, we'd better clear all
// the cache entries to disk.
if (_UH.bitmapCache[i].BCInfo.NumVirtualEntries) { pRev2Caps->CellCacheInfo[i].NumEntries = _UH.bitmapCache[i].BCInfo.NumVirtualEntries; UHInitBitmapCachePageTable(i); } } TRC_NRM((TB,_T("Blocking persiten cache (different col depth)"))); _UH.bPersistenceDisable = TRUE; } } #endif
/************************************************************************/ // Following items must be done on each reception of DemandActivePDU.
/************************************************************************/ _pUi->UI_GetDesktopSize(&desktopSize);
// Possibly create the Shadow and Save Screen bitmaps and update the
// capabilities in CC accordingly.
UHMaybeCreateShadowBitmap();
if (_UH.shadowBitmapEnabled || (_UH.dedicatedTerminal && (desktopSize.width <= (unsigned)GetSystemMetrics(SM_CXSCREEN)) && (desktopSize.height <= (unsigned)GetSystemMetrics(SM_CYSCREEN)))) { TRC_NRM((TB, _T("OK to use ScreenBlt orders"))); _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_SCRBLT_INDEX] = 1; _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_MULTISCRBLT_INDEX] = 1; } else { TRC_NRM((TB, _T("Cannot use ScreenBlt orders"))); _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_SCRBLT_INDEX] = 0; _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_MULTISCRBLT_INDEX] = 0; }
UHMaybeCreateSaveScreenBitmap(); if (_UH.hSaveScreenBitmap != NULL) { TRC_NRM((TB, _T("Support SaveScreenBits orders"))); _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_SAVEBITMAP_INDEX] = 1; } else { TRC_NRM((TB, _T("Cannot support SaveScreenBits orders"))); _pCc->_ccCombinedCapabilities.orderCapabilitySet.orderSupport[ TS_NEG_SAVEBITMAP_INDEX] = 0; }
// Set the value of _UH.hdcDraw according to the value of
// _UH.shadowBitmapEnabled.
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
_UH.hdcDraw = !_UH.DontUseShadowBitmap ? _UH.hdcShadowBitmap : _UH.hdcOutputWindow; #else
_UH.hdcDraw = _UH.shadowBitmapEnabled ? _UH.hdcShadowBitmap : _UH.hdcOutputWindow; #endif // DISABLE_SHADOW_IN_FULLSCREEN
#if defined (OS_WINCE)
_UH.validClipDC = NULL; _UH.validBkColorDC = NULL; _UH.validBkModeDC = NULL; _UH.validROPDC = NULL; _UH.validTextColorDC = NULL; _UH.validPenDC = NULL; _UH.validBrushDC = NULL; #endif
UHResetDCState();
#ifdef OS_WINCE
if (g_CEConfig != CE_CONFIG_WBT) UHGetPaletteCaps(); #endif
TRC_DBG((TB, _T("_UH.shadowBitmapEnabled(%u) _UH.hShadowBitmap(%#hx)"), _UH.shadowBitmapEnabled, _UH.hShadowBitmap)); TRC_DBG((TB, _T("_UH.hSaveScreenBitmap(%#hx)"), _UH.hSaveScreenBitmap)); TRC_DBG((TB, _T("_UH.hdcDraw(%#hx) _UH.hdcShadowBitmap(%#hx)"), _UH.hdcDraw, _UH.hdcShadowBitmap));
if (_UH.shadowBitmapEnabled) { // Fill Shadow Bitmap with black.
TRC_NRM((TB, _T("Fill with black")));
#ifndef OS_WINCE
hbr = CreateSolidBrush(RGB(0,0,0)); #else
hbr = CECreateSolidBrush(RGB(0,0,0)); #endif
TRC_ASSERT(hbr, (TB,_T("CreateSolidBrush failed"))); if(hbr) { rect.left = 0; rect.top = 0; rect.right = desktopSize.width; rect.bottom = desktopSize.height; UH_ResetClipRegion(); FillRect( _UH.hdcShadowBitmap, &rect, hbr ); #ifndef OS_WINCE
DeleteBrush(hbr); #else
CEDeleteBrush(hbr); #endif
} }
// Tell OP and OD that the share is coming up.
_pOp->OP_Enable(); _pOd->OD_Enable();
#ifdef DRAW_GDIPLUS
if (_UH.pfnGdipPlayTSClientRecord) { if (!_UH.fGdipEnabled) { rc = _UH.pfnGdipPlayTSClientRecord(_UH.hdcShadowBitmap, DrawTSClientEnable, NULL, 0, NULL); _UH.fGdipEnabled = TRUE; if (rc != 0) { TRC_ERR((TB, _T("Call to GdipPlay:DrawTSClientEnable failed"))); } }
ProtocolColorDepth = _UH.protocolBpp; if (_UH.pfnGdipPlayTSClientRecord(_UH.hdcShadowBitmap, DrawTSClientDisplayChange, (BYTE *)&ProtocolColorDepth, sizeof(unsigned int), NULL)) { TRC_ERR((TB, _T("GdipPlay:DrawTSClientDisplayChange failed"))); } } #endif
// We are enabled now.
_UH.bEnabled = TRUE;
DC_END_FN(); }
/****************************************************************************/ // UHCommonDisable
//
// Encapsulates common disable/disconnect code.
/****************************************************************************/ void DCINTERNAL CUH::UHCommonDisable(BOOL fDisplayDisabledBitmap) { BOOL fUseDisabledBitmap = FALSE; DC_BEGIN_FN("UHCommonDisable");
if (_UH.bEnabled) { _UH.bEnabled = FALSE; }
// Tell OP and OD that the share is going down.
//
// Pass flag to OP telling it if we are now disconnected
// this starts all the window dimming stuff
//
_pOp->OP_Disable(!_UH.bConnected); _pOd->OD_Disable();
DC_END_FN(); }
/****************************************************************************/ // UH_Disable
//
// Disables _UH. Called at reception of DisableAllPDU from server. This
// function should not be used to do cleanup for the session (see
// UH_Disconnect), as the server may continue the session on server-side
// reconnect by starting a new share starting with a new DemandActivePDU.
//
// Params: IN unused - required by the component decoupler.
/****************************************************************************/ void DCAPI CUH::UH_Disable(ULONG_PTR unused) { DC_BEGIN_FN("UH_Disable");
DC_IGNORE_PARAMETER(unused);
TRC_NRM((TB, _T("Disabling UH")));
// We don't have anything to do here for bitmap caching. Whether we
// are communicating with a rev1 or rev2 bitmap caching server, we
// don't need to repeat work and allocations here. For rev2 servers
// we cannot change the cache contents on DisableAllPDU since we
// may actually be reconnecting and the server will assume state was
// maintained.
// Do work that needs doing on both UH_Disable() and UH_Disconnect().
UHCommonDisable(TRUE);
DC_END_FN(); }
/****************************************************************************/ // UH_Disconnect
//
// Disconnects _UH. Called at session end to indicate session cleanup should
// occur.
//
// Params: IN unused - required by the component decoupler.
/****************************************************************************/ void DCAPI CUH::UH_Disconnect(ULONG_PTR unused) { UINT cacheId; UINT32 cacheIndex;
DC_BEGIN_FN("UH_Disconnect");
DC_IGNORE_PARAMETER(unused);
TRC_NRM((TB, _T("Disconnecting UH")));
// We can be called here multiple times. Don't do a lot of extra work.
if (_UH.bConnected) {
UHCreateDisconnectedBitmap();
_UH.bConnected = FALSE;
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
if (_UH.bPersistenceActive) { if (!_UH.bWarningDisplayed) { UINT32 Key1, Key2;
for (cacheId = 0; cacheId < _UH.NumBitmapCaches; cacheId++) { _UH.numKeyEntries[cacheId] = 0; if (_UH.pBitmapKeyDB[cacheId] != NULL) { for (cacheIndex = 0; cacheIndex < _UH.bitmapCache[cacheId]. BCInfo.NumVirtualEntries; cacheIndex++) { Key1 = _UH.bitmapCache[cacheId].PageTable.PageEntries[ cacheIndex].bmpInfo.Key1; Key2 = _UH.bitmapCache[cacheId].PageTable.PageEntries[ cacheIndex].bmpInfo.Key2; if (Key1 != 0 && Key2 != 0) { // need to reset the bitmap key database to what's in
// the bitmap cache page table
_UH.pBitmapKeyDB[cacheId][_UH.numKeyEntries[cacheId]] = _UH.bitmapCache[cacheId].PageTable.PageEntries[ cacheIndex].bmpInfo; _UH.numKeyEntries[cacheId]++; } else { break; } } } } } else { // we had a persistent caching failure, so we should disable
// persistent caching for next reconnect
for (cacheId = 0; cacheId < _UH.NumBitmapCaches; cacheId++) { _UH.numKeyEntries[cacheId] = 0;
UH_ClearOneBitmapDiskCache(cacheId, _UH.copyMultiplier); } _pUi->UI_SetBitmapPersistence(FALSE); }
_UH.bBitmapKeyEnumComplete = TRUE; _UH.bBitmapKeyEnumerating = FALSE; } #endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
//
// Reset bitmap cache alloced flag
//
_UH.fBmpCacheMemoryAlloced = FALSE;
// Free bitmap cache info in use.
for (cacheId = 0; cacheId < _UH.NumBitmapCaches; cacheId++) { if (_UH.bitmapCache[cacheId].Header != NULL) { UT_Free( _pUt, _UH.bitmapCache[cacheId].Header); _UH.bitmapCache[cacheId].Header = NULL; } if (_UH.bitmapCache[cacheId].Entries != NULL) { UT_Free( _pUt, _UH.bitmapCache[cacheId].Entries); _UH.bitmapCache[cacheId].Entries = NULL; }
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// reset the last time bitmap error pdu sent for all caches
_UH.lastTimeErrorPDU[cacheId] = 0;
// Free bitmap page table
if (_UH.bitmapCache[cacheId].PageTable.PageEntries != NULL) { UT_Free( _pUt, _UH.bitmapCache[cacheId].PageTable.PageEntries); _UH.bitmapCache[cacheId].PageTable.PageEntries = NULL; _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries = 0; }
// close the file handle for the cache files
if (INVALID_HANDLE_VALUE != _UH.bitmapCache[cacheId].PageTable.CacheFileInfo.hCacheFile) { CloseHandle(_UH.bitmapCache[cacheId].PageTable.CacheFileInfo.hCacheFile); _UH.bitmapCache[cacheId].PageTable.CacheFileInfo.hCacheFile = INVALID_HANDLE_VALUE;
#ifdef VM_BMPCACHE
if (_UH.bitmapCache[cacheId].PageTable.CacheFileInfo.pMappedView) { if (!UnmapViewOfFile( _UH.bitmapCache[cacheId].PageTable.CacheFileInfo.pMappedView)) { TRC_ERR((TB,_T("UnmapViewOfFile failed 0x%d"), GetLastError())); } } #endif
}
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
} _UH.NumBitmapCaches = 0;
// free the decompression buffer
if (_UH.bitmapDecompressionBuffer != NULL) { UT_Free( _pUt, _UH.bitmapDecompressionBuffer); _UH.bitmapDecompressionBuffer = NULL; _UH.bitmapDecompressionBufferSize = 0; }
// Delete all the offscreen bitmaps
if (NULL != _UH.hdcOffscreenBitmap) { unsigned i; for (i = 0; i < _UH.offscrCacheEntries; i++) { if (_UH.offscrBitmapCache[i].offscrBitmap) { SelectBitmap(_UH.hdcOffscreenBitmap, _UH.hUnusedOffscrBitmap); DeleteBitmap(_UH.offscrBitmapCache[i].offscrBitmap); _UH.offscrBitmapCache[i].offscrBitmap = 0; _UH.offscrBitmapCache[i].cx = 0; _UH.offscrBitmapCache[i].cy = 0; } } }
#ifdef DRAW_NINEGRID
// Delete all the drawStream bitmaps
if (NULL != _UH.hdcDrawNineGridBitmap) { unsigned i; for (i = 0; i < _UH.drawNineGridCacheEntries; i++) { if (_UH.drawNineGridBitmapCache[i].drawNineGridBitmap) { SelectBitmap(_UH.hdcDrawNineGridBitmap, _UH.hUnusedDrawNineGridBitmap); DeleteBitmap(_UH.drawNineGridBitmapCache[i].drawNineGridBitmap); _UH.drawNineGridBitmapCache[i].drawNineGridBitmap = 0; _UH.drawNineGridBitmapCache[i].cx = 0; _UH.drawNineGridBitmapCache[i].cy = 0; } } } #endif
#ifdef DC_DEBUG
// Force a redraw of the bitmap cache monitor, since it cannot any
// longer display contents from the entries array freed above.
UHDisconnectBitmapCacheMonitor(); #endif
/********************************************************************/ // We need to free up any resources we might have set up in the draw
// DC, along with the bitmap used for pattern brushes.
// We do this by selecting in stock objects - which we don't need to
// free - and deleting the old object (if any)
/********************************************************************/ if (NULL != _UH.hdcDraw) { HPEN hPenNew; HPEN hPenOld; HBRUSH hBrushNew; HBRUSH hBrushOld; HFONT hFontNew; HFONT hFontOld;
TRC_NRM((TB, _T("tidying DC resources")));
// First the pen.
hPenNew = (HPEN)GetStockObject(NULL_PEN); hPenOld = SelectPen(_UH.hdcDraw, hPenNew); if (NULL != hPenOld) { TRC_NRM((TB, _T("Delete old pen"))); DeleteObject(hPenOld); }
// Now the brush.
hBrushNew = (HBRUSH)GetStockObject(NULL_BRUSH); hBrushOld = SelectBrush(_UH.hdcDraw, hBrushNew); if (NULL != hBrushOld) { TRC_NRM((TB, _T("Delete old brush"))); DeleteObject(hBrushOld); }
// Now the font.
hFontNew = (HFONT)GetStockObject(SYSTEM_FONT); hFontOld = SelectFont(_UH.hdcDraw, hFontNew); if (NULL != hFontOld) { TRC_NRM((TB, _T("Delete old Font"))); DeleteObject(hFontOld); }
#ifdef OS_WINCE
//Now the palette.
//On WinCE when the device is capable of only 8bpp, when you
//disconnect from a session and return to the main dialog, the
//palette isnt reset, and the rest of CE screen looks ugly.
if (NULL != _UH.hpalDefault) { SelectPalette(_UH.hdcDraw, _UH.hpalDefault, FALSE ); RealizePalette(_UH.hdcDraw); }
if ((_UH.hpalCurrent != NULL) && (_UH.hpalCurrent != _UH.hpalDefault)) { TRC_NRM((TB, _T("Delete current palette %p"), _UH.hpalCurrent)); DeletePalette(_UH.hpalCurrent); }
_UH.hpalCurrent = _UH.hpalDefault; #endif
// Make sure this DC is nulled out to avoid problems if we're
// called again. This is just a copy of _UH.hdcOutputWindow, which
// is NULLed below.
_UH.hdcDraw = NULL; }
/********************************************************************/ // If we're not using a shadow bitmap, we should release the DC we
// have to the output window - remembering that it is possible that
// we didn't successfully connect, in which case UH_OnConnected won't
// have been called and so we won't have acquired a DC to need
// releasing!
/********************************************************************/ if (NULL != _UH.hdcOutputWindow) { TRC_NRM((TB, _T("Releasing Output Window HDC"))); ReleaseDC(_pOp->OP_GetOutputWindowHandle(), _UH.hdcOutputWindow); _UH.hdcOutputWindow = NULL; } }
// Do work that needs doing on both UH_Disable() and UH_Disconnect().
UHCommonDisable(TRUE);
DC_END_FN(); }
#ifdef DC_DEBUG
/****************************************************************************/ /* Name: UH_HatchRect */ /* */ /* Purpose: Draws a hatched rectangle in _UH.hdcOutputWindow in the given */ /* color. */ /* */ /* Params: left - left coord of rect */ /* top - top coord of rect */ /* right - right coord of rect */ /* bottom - bottom coord of rect */ /* color - color of hatching to draw */ /* hatchStyle - style of hatching to draw */ /****************************************************************************/ DCVOID DCAPI CUH::UH_HatchOutputRect(DCINT left, DCINT top, DCINT right, DCINT bottom, COLORREF color, DCUINT hatchStyle) { DC_BEGIN_FN("UHHatchOutputRect"); UH_HatchRectDC(_UH.hdcOutputWindow, left, top, right, bottom, color, hatchStyle); DC_END_FN(); }
/****************************************************************************/ /* Name: UH_HatchRect */ /* */ /* Purpose: Draws a hatched rectangle in _UH.hdcDraw in the given color. */ /* */ /* Params: left - left coord of rect */ /* top - top coord of rect */ /* right - right coord of rect */ /* bottom - bottom coord of rect */ /* color - color of hatching to draw */ /* hatchStyle - style of hatching to draw */ /****************************************************************************/ DCVOID DCAPI CUH::UH_HatchRect( DCINT left, DCINT top, DCINT right, DCINT bottom, COLORREF color, DCUINT hatchStyle ) { DC_BEGIN_FN("UHHatchRect"); UH_HatchRectDC(_UH.hdcDraw, left, top, right, bottom, color, hatchStyle); DC_END_FN(); }
/****************************************************************************/ /* Name: UH_HatchRectDC */ /* */ /* Purpose: Draws a hatched rectangle in the hDC in the given color. */ /* */ /* Params: left - left coord of rect */ /* top - top coord of rect */ /* right - right coord of rect */ /* bottom - bottom coord of rect */ /* color - color of hatching to draw */ /* hatchStyle - style of hatching to draw */ /****************************************************************************/ DCVOID DCAPI CUH::UH_HatchRectDC(HDC hdc, DCINT left, DCINT top, DCINT right, DCINT bottom, COLORREF color, DCUINT hatchStyle) { HBRUSH hbrHatch; DCUINT oldBkMode; DCUINT oldRop2; DCUINT winHatchStyle = 0; POINT oldOrigin; RECT rect; HRGN hrgn; HBRUSH hbrOld; HPEN hpen; HPEN hpenOld;
DC_BEGIN_FN("UHHatchRectDC");
switch (hatchStyle) { case UH_BRUSHTYPE_FDIAGONAL: { winHatchStyle = HS_FDIAGONAL; } break;
case UH_BRUSHTYPE_DIAGCROSS: { winHatchStyle = HS_DIAGCROSS; } break;
case UH_BRUSHTYPE_HORIZONTAL: { winHatchStyle = HS_HORIZONTAL; } break;
case UH_BRUSHTYPE_VERTICAL: { winHatchStyle = HS_VERTICAL; } break;
default: { TRC_ABORT((TB, _T("Unspecified hatch type request, %u"), hatchStyle)); } break; }
hbrHatch = CreateHatchBrush(winHatchStyle, color); oldBkMode = SetBkMode(hdc, TRANSPARENT); oldRop2 = SetROP2(hdc, R2_COPYPEN); SetBrushOrgEx(hdc, 0, 0, &oldOrigin);
rect.left = left; rect.top = top; rect.right = right; rect.bottom = bottom;
/************************************************************************/ /* Fill the rectangle with the hatched brush. */ /************************************************************************/ hrgn = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
#ifndef OS_WINCE
/************************************************************************/ /* Just draw bounding rectangle on WinCE */ /************************************************************************/ FillRgn( hdc, hrgn, hbrHatch ); #endif
DeleteRgn(hrgn); DeleteBrush(hbrHatch);
hbrOld = SelectBrush(hdc, GetStockObject(HOLLOW_BRUSH));
hpen = CreatePen(PS_SOLID, 1, color); hpenOld = SelectPen(hdc, hpen);
/************************************************************************/ /* Draw a border around the hatched rectangle. */ /************************************************************************/ Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
SelectBrush(hdc, hbrOld);
SelectPen(hdc, hpenOld); DeletePen(hpen);
/************************************************************************/ /* Reset the original DC state. */ /************************************************************************/ SetBrushOrgEx(hdc, oldOrigin.x, oldOrigin.y, NULL); SetROP2(hdc, oldRop2); SetBkMode(hdc, oldBkMode);
DC_END_FN(); } #endif
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
void DCAPI CUH::UH_SetBBarRect(ULONG_PTR pData) { RECT *prect = (RECT *)pData;
_UH.rectBBar.left = prect->left; _UH.rectBBar.top = prect->top; _UH.rectBBar.right = prect->right; _UH.rectBBar.bottom = prect->bottom; }
void DCAPI CUH::UH_SetBBarVisible(ULONG_PTR pData) { if (0 == (int)pData) _UH.fIsBBarVisible = FALSE; else _UH.fIsBBarVisible = TRUE; }
// Disable use of shadow in full-screen
void DCAPI CUH::UH_DisableShadowBitmap(ULONG_PTR) { DC_BEGIN_FN("UH_DisableShadowBitmap");
_UH.hdcDraw = _UH.hdcOutputWindow; _UH.DontUseShadowBitmap = TRUE; UHResetDCState();
DC_END_FN(); }
// Enable use of shadow when leaving full-screen
void DCAPI CUH::UH_EnableShadowBitmap(ULONG_PTR) { DC_BEGIN_FN("UH_EnableShadowBitmap");
DCSIZE desktopSize; RECT rect;
if (_UH.DontUseShadowBitmap) { _pUi->UI_GetDesktopSize(&desktopSize);
_UH.hdcDraw = _UH.hdcShadowBitmap; _UH.DontUseShadowBitmap = FALSE;
rect.left = 0; rect.top = 0; rect.right = desktopSize.width; rect.bottom = desktopSize.height; // Since we have no copy of screen, ask the server to resend
_pCd->CD_DecoupleNotification(CD_SND_COMPONENT, _pOr, CD_NOTIFICATION_FUNC(COR,OR_RequestUpdate), &rect, sizeof(RECT)); UHResetDCState(); }
DC_END_FN(); return; } #endif // DISABLE_SHADOW_IN_FULLSCREEN
#ifdef DRAW_GDIPLUS
// Ininitalize the gdiplus
BOOL DCAPI CUH::UHDrawGdiplusStartup(ULONG_PTR unused) { Gdiplus::GdiplusStartupInput sti; unsigned GdipVersion; unsigned rc = FALSE;
DC_BEGIN_FN("UHDrawGdiplusStartup");
if (_UH.pfnGdiplusStartup(&_UH.gpToken, &sti, NULL) == Gdiplus::Ok) { _UH.gpValid = TRUE;
GdipVersion = _UH.pfnGdipPlayTSClientRecord(NULL, DrawTSClientQueryVersion, NULL, 0, NULL); _pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipVersion = GdipVersion;
rc = TRUE; } else { TRC_ERR((TB, _T("Call to GdiplusStartup failed"))); }
DC_END_FN();
return rc; }
// Shutdown the gdiplus
void DCAPI CUH::UHDrawGdiplusShutdown(ULONG_PTR unused) { DC_BEGIN_FN("UHDrawGdiplusShutDown");
if (_UH.pfnGdipPlayTSClientRecord) { _UH.pfnGdipPlayTSClientRecord(NULL, DrawTSClientDisable, NULL, 0, NULL); } if (_UH.gpValid) { _UH.pfnGdiplusShutdown(_UH.gpToken); }
if (_UH.hModuleGDIPlus != NULL) { FreeLibrary(_UH.hModuleGDIPlus); _UH.pfnGdipPlayTSClientRecord = NULL; _UH.hModuleGDIPlus = NULL; }
DC_END_FN(); } #endif // DRAW_GDIPLUS
|