/****************************************************************************/ /* uhapi.cpp */ /* */ /* Update Handler API */ /* */ /* Copyright(C) Microsoft Corporation 1997-1999 */ /****************************************************************************/ #include extern "C" { #define TRC_GROUP TRC_GROUP_CORE #define TRC_FILE "uhapi" #include } #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 #ifdef OS_WINNT #include #endif } #ifdef OS_WINCE #ifdef DC_DEBUG #include #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