Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1731 lines
76 KiB

/****************************************************************************/
// asbcapi.cpp
//
// Send Bitmap Cache API functions.
//
// Copyright(c) Microsoft, PictureTel 1992-1997
// (C) 1997-2000 Microsoft Corp.
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_FILE "asbcapi"
#include <as_conf.hpp>
/****************************************************************************/
// SBC_Init(): Initializes the SBC.
//
// Returns: FALSE on failure to initialize.
/****************************************************************************/
void RDPCALL SHCLASS SBC_Init(void)
{
long cachingDisabled;
TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT HostCaps;
DC_BEGIN_FN("SBC_Init");
// This initializes all the global data for this component.
#define DC_INIT_DATA
#include <asbcdata.c>
#undef DC_INIT_DATA
COM_ReadProfInt32(m_pTSWd,
SBC_INI_CACHING_DISABLED,
SBC_DEFAULT_CACHING_DISABLED,
&cachingDisabled);
sbcBitmapCachingEnabled = !(cachingDisabled & SBC_DISABLE_BITMAP_CACHE);
sbcBrushCachingEnabled = !(cachingDisabled & SBC_DISABLE_BRUSH_CACHE);
sbcGlyphCachingEnabled = !(cachingDisabled & SBC_DISABLE_GLYPH_CACHE);
sbcOffscreenCachingEnabled = !(cachingDisabled & SBC_DISABLE_OFFSCREEN_CACHE);
#ifdef DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
sbcDrawNineGridCachingEnabled = !(cachingDisabled & SBC_DISABLE_DRAWNINEGRID_CACHE);
sbcDrawGdiplusEnabled = !(cachingDisabled & SBC_DISABLE_DRAWGDIPLUS_CACHE);
TRC_NRM((TB, "Caches enabled: Bitmap=%u, Brush=%u, Glyph=%u, Offscreen=%u, DNG=%u, GDIP=%u",
sbcBitmapCachingEnabled,
sbcBrushCachingEnabled,
sbcGlyphCachingEnabled,
sbcOffscreenCachingEnabled,
sbcDrawNineGridCachingEnabled,
sbcDrawGdiplusEnabled));
#else
sbcDrawGdiplusEnabled = !(cachingDisabled & SBC_DISABLE_DRAWGDIPLUS_CACHE);
TRC_NRM((TB, "Caches enabled: Bitmap=%u, Brush=%u, Glyph=%u, Offscreen=%u",
sbcBitmapCachingEnabled,
sbcBrushCachingEnabled,
sbcGlyphCachingEnabled,
sbcOffscreenCachingEnabled));
#endif // DRAW_NINEGRID
#else // DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
sbcDrawNineGridCachingEnabled = !(cachingDisabled & SBC_DISABLE_DRAWNINEGRID_CACHE);
TRC_NRM((TB, "Caches enabled: Bitmap=%u, Brush=%u, Glyph=%u, Offscreen=%u, DNG=%u",
sbcBitmapCachingEnabled,
sbcBrushCachingEnabled,
sbcGlyphCachingEnabled,
sbcOffscreenCachingEnabled,
sbcDrawNineGridCachingEnabled));
#else
TRC_NRM((TB, "Caches enabled: Bitmap=%u, Brush=%u, Glyph=%u, Offscreen=%u",
sbcBitmapCachingEnabled,
sbcBrushCachingEnabled,
sbcGlyphCachingEnabled,
sbcOffscreenCachingEnabled));
#endif // DRAW_NINEGRID
#endif // DRAW_GDIPLUS
// The server supports rev2 bitmap caching. Indicate this support with a
// client-to-server capability so the client can respond in kind.
HostCaps.capabilitySetType = TS_CAPSETTYPE_BITMAPCACHE_HOSTSUPPORT;
HostCaps.lengthCapability = sizeof(HostCaps);
HostCaps.CacheVersion = TS_BITMAPCACHE_REV2;
HostCaps.Pad1 = 0;
HostCaps.Pad2 = 0;
CPC_RegisterCapabilities((PTS_CAPABILITYHEADER)&HostCaps,
sizeof(TS_BITMAPCACHE_CAPABILITYSET_HOSTSUPPORT));
TRC_NRM((TB, "SBC initialized OK"));
DC_END_FN();
}
/****************************************************************************/
// SBC_Term(): Terminates the SBC.
/****************************************************************************/
void RDPCALL SHCLASS SBC_Term(void)
{
DC_BEGIN_FN("SBC_Term");
SBC_FreeBitmapKeyDatabase();
DC_END_FN();
}
/****************************************************************************/
// SBC_SyncUpdatesNow: Called to force a sync, which clears all caches.
/****************************************************************************/
void RDPCALL SHCLASS SBC_SyncUpdatesNow(void)
{
DC_BEGIN_FN("SBC_SyncUpdatesNow");
#ifdef DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled ||
sbcBrushCachingEnabled || sbcOffscreenCachingEnabled ||
sbcDrawNineGridCachingEnabled || sbcDrawGdiplusEnabled) {
#else
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled ||
sbcBrushCachingEnabled || sbcOffscreenCachingEnabled ||
sbcDrawGdiplusEnabled) {
#endif // DRAW_NINEGRID
#else // DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled ||
sbcBrushCachingEnabled || sbcOffscreenCachingEnabled ||
sbcDrawNineGridCachingEnabled) {
#else
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled ||
sbcBrushCachingEnabled || sbcOffscreenCachingEnabled) {
#endif // DRAW_NINEGRID
#endif // DRAW_GDIPLUS
sbcSyncRequired = TRUE;
DCS_TriggerUpdateShmCallback();
}
DC_END_FN();
}
/****************************************************************************/
// SBC_DumpBitmapKeyDatabase
//
// Allocates a key database and fills it in with the current contents of
// the bitmap caches.
/****************************************************************************/
void RDPCALL SHCLASS SBC_DumpBitmapKeyDatabase(BOOLEAN bSaveDatabase)
{
unsigned i, j;
unsigned TotalEntries, CurEntry;
CHNODE *pNode;
DC_BEGIN_FN("SBC_DumpBitmapKeyDatabase");
// If we have a previous database, possibly from the original client
// persistent key upload, destroy it.
SBC_FreeBitmapKeyDatabase();
// Count up the total number of entries we will need if preserving the key
// database. For shadows, this information is always discarded.
TotalEntries = 0;
if (bSaveDatabase) {
for (i = 0; i < m_pShm->sbc.NumBitmapCaches; i++)
if (m_pShm->sbc.bitmapCacheInfo[i].cacheHandle != NULL)
TotalEntries += CH_GetNumEntries(m_pShm->sbc.bitmapCacheInfo[i].
cacheHandle);
}
if (TotalEntries > 0) {
// Allocate the database.
sbcKeyDatabaseSize = sizeof(SBC_BITMAP_CACHE_KEY_INFO) + (TotalEntries - 1) *
sizeof(SBC_MRU_KEY);
sbcKeyDatabase = (SBC_BITMAP_CACHE_KEY_INFO *)COM_Malloc(sbcKeyDatabaseSize);
if (sbcKeyDatabase != NULL) {
sbcKeyDatabase->TotalKeys = TotalEntries;
// Fill in the database from each cache.
CurEntry = 0;
for (i = 0; i < m_pShm->sbc.NumBitmapCaches; i++) {
sbcKeyDatabase->NumKeys[i] = CH_GetNumEntries(m_pShm->sbc.
bitmapCacheInfo[i].cacheHandle);
sbcKeyDatabase->KeyStart[i] = CurEntry;
SBC_DumpMRUList(m_pShm->sbc.bitmapCacheInfo[i].cacheHandle,
&(sbcKeyDatabase->Keys[sbcKeyDatabase->KeyStart[i]]));
CurEntry += sbcKeyDatabase->NumKeys[i];
}
// Fill in remainder of pointers and info with zeros to indicate
// nothing there.
for (; i < TS_BITMAPCACHE_MAX_CELL_CACHES; i++) {
sbcKeyDatabase->NumKeys[i] = 0;
sbcKeyDatabase->KeyStart[i] = 0;
}
}
else {
// Not allocating the database is an error, but not fatal, since
// it just means that the caches will be cleared instead of being
// initialized.
TRC_ERR((TB,"Failed to allocate key database"));
sbcKeyDatabaseSize = 0;
}
}
DC_END_FN();
}
/****************************************************************************/
// SBC_DumpMRUList
//
// Walks a cache MRU list and dumps the keys and indices to an
// SBC_MRU_KEY array.
/****************************************************************************/
void RDPCALL SHCLASS SBC_DumpMRUList(CHCACHEHANDLE hCache, void *pList)
{
CHNODE *pNode;
unsigned CurEntry;
PLIST_ENTRY pCurrentListEntry;
SBC_MRU_KEY *pKeys = (SBC_MRU_KEY *)pList;
PCHCACHEDATA pCacheData;
DC_BEGIN_FN("SBC_DumpMRUList");
pCacheData = (CHCACHEDATA *)hCache;
CurEntry = 0;
pCurrentListEntry = pCacheData->MRUList.Flink;
while (pCurrentListEntry != &pCacheData->MRUList) {
pNode = CONTAINING_RECORD(pCurrentListEntry, CHNODE, MRUList);
pKeys[CurEntry].Key1 = pNode->Key1;
pKeys[CurEntry].Key2 = pNode->Key2;
pKeys[CurEntry].CacheIndex = (unsigned)(pNode - pCacheData->NodeArray);
CurEntry++;
pCurrentListEntry = pCurrentListEntry->Flink;
}
TRC_ASSERT((CurEntry == pCacheData->NumEntries),
(TB,"NumEntries (%u) != # entries in MRU list (%u)",
pCacheData->NumEntries, CurEntry));
DC_END_FN();
}
/****************************************************************************/
// SBC_PartyJoiningShare: Called when a new party is joining the share.
//
// Params:
// locPersonID - local person ID of remote person joining the share.
// oldShareSize - the number of the parties which were in the share (ie
// excludes the joining party).
//
// Returns: TRUE if the party can join the share, FALSE otherwise.
/****************************************************************************/
BOOLEAN RDPCALL SHCLASS SBC_PartyJoiningShare(
LOCALPERSONID locPersonID,
unsigned oldShareSize)
{
DC_BEGIN_FN("SBC_PartyJoiningShare");
DC_IGNORE_PARAMETER(oldShareSize);
TRC_NRM((TB, "[%x] joining share", locPersonID));
#ifdef DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled || sbcDrawNineGridCachingEnabled || sbcDrawGdiplusEnabled) {
#else
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled || sbcDrawGdiplusEnabled) {
#endif // DRAW_NINEGRID
#else // DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled || sbcDrawNineGridCachingEnabled) {
#else
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled) {
#endif // DRAW_NINEGRID
#endif // DRAW_GDIPLUS
// Local server does not require new action.
if (locPersonID != SC_LOCAL_PERSON_ID) {
sbcCachingOn = TRUE;
sbcNewCapsData = TRUE;
// Redetermine the size of the bitmap cache.
if (sbcBitmapCachingEnabled)
SBCRedetermineBitmapCacheSize();
// Redetermine the size of the glyph cache.
if (sbcGlyphCachingEnabled)
SBCRedetermineGlyphCacheSize();
// Redetermine the brush support level
if (sbcBrushCachingEnabled)
SBCRedetermineBrushSupport();
// Redetermine the offscreen support level
if (sbcOffscreenCachingEnabled) {
SBCRedetermineOffscreenSupport();
}
#ifdef DRAW_NINEGRID
// Redetermine the drawninegrid support level
if (sbcDrawNineGridCachingEnabled) {
SBCRedetermineDrawNineGridSupport();
}
#endif
#ifdef DRAW_GDIPLUS
if (sbcDrawGdiplusEnabled) {
SBCRedetermineDrawGdiplusSupport();
}
#endif
// Force a callback on the WinStation context so we can update
// the shared memory.
DCS_TriggerUpdateShmCallback();
}
}
DC_END_FN();
return TRUE;
}
/****************************************************************************/
// SBC_PartyLeftShare(): Called when a party has left the share.
//
// Params:
// locPersonID - local person ID of remote person leaving the share.
// newShareSize - the number of the parties now in the call (ie excludes
// the leaving party).
/****************************************************************************/
void RDPCALL SHCLASS SBC_PartyLeftShare(
LOCALPERSONID locPersonID,
unsigned newShareSize)
{
DC_BEGIN_FN("SBC_PartyLeftShare");
DC_IGNORE_PARAMETER(newShareSize);
TRC_NRM((TB, "[%x] left share", locPersonID));
// Must have active caches
#ifdef DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled || sbcDrawNineGridCachingEnabled || sbcDrawGdiplusEnabled) {
#else
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled || sbcDrawGdiplusEnabled) {
#endif // DRAW_NINEGRID
#else // DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled || sbcDrawNineGridCachingEnabled) {
#else
if (sbcBitmapCachingEnabled || sbcGlyphCachingEnabled || sbcBrushCachingEnabled ||
sbcOffscreenCachingEnabled) {
#endif // DRAW_NINEGRID
#endif // DRAW_GDIPLUS
// If all people left the share then disable caching.
if (locPersonID == SC_LOCAL_PERSON_ID) {
TRC_NRM((TB, "Disable caching"));
sbcCachingOn = FALSE;
sbcNewCapsData = TRUE;
// Force a callback on the WinStation context so we can update the
// shared memory.
DCS_TriggerUpdateShmCallback();
}
// Else, look thru the capabilities again to see what's possible
else {
sbcCachingOn = TRUE;
sbcNewCapsData = TRUE;
// Redetermine the size of the bitmap cache.
if (sbcBitmapCachingEnabled)
SBCRedetermineBitmapCacheSize();
// Redetermine the size of the glyph cache.
if (sbcGlyphCachingEnabled)
SBCRedetermineGlyphCacheSize();
// Redetermine the brush support level
if (sbcBrushCachingEnabled)
SBCRedetermineBrushSupport();
// Redetermine the offscreen support level
if (sbcOffscreenCachingEnabled) {
SBCRedetermineOffscreenSupport();
}
#ifdef DRAW_NINEGRID
// Redetermine the drawninegrid support level
if (sbcDrawNineGridCachingEnabled) {
SBCRedetermineDrawNineGridSupport();
}
#endif
#ifdef DRAW_GDIPLUS
if (sbcDrawGdiplusEnabled) {
SBCRedetermineDrawGdiplusSupport();
}
#endif
// TODO: Is this really necessary?
DCS_TriggerUpdateShmCallback();
}
}
DC_END_FN();
}
/****************************************************************************/
// SBC_HandlePersistentCacheList(): Handles list of persistent cache keys
// from the client.
/****************************************************************************/
void RDPCALL SHCLASS SBC_HandlePersistentCacheList(
TS_BITMAPCACHE_PERSISTENT_LIST *pPDU,
unsigned DataLength,
LOCALPERSONID LocalID)
{
unsigned i, j, CurEntry;
INT TotalEntries;
DC_BEGIN_FN("SBC_HandlePersistentCacheList");
// Check the packet length against its internal representation, make sure
// it is as long as it needs to be. If not, we either received a buggy
// packet or we're being attacked.
if (DataLength >= (sizeof(TS_BITMAPCACHE_PERSISTENT_LIST) -
sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY))) {
if (pPDU->bFirstPDU) {
// Check that we have not already received persistent key info.
// If we have and we get a new PDU, it is a protocol error.
if (sbcPersistentKeysReceived) {
TRC_ERR((TB,"Persistent key packet received marked FIRST "
"illegally"));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_PersistentKeyPDUIllegalFIRST,
(PBYTE)pPDU, DataLength);
goto ExitFunc;
}
// Get the total number of entries from the PDU array. Check
// against the negotiated caps and make sure the client is not
// trying to send too many.
TotalEntries = 0;
for (i = 0; i < TS_BITMAPCACHE_MAX_CELL_CACHES; i++) {
TotalEntries += pPDU->TotalEntries[i];
if (pPDU->TotalEntries[i] > sbcCurrentBitmapCaps.
CellCacheInfo[i].NumEntries) {
TRC_ERR((TB,"Persistent key packet received specified "
"more keys (%u) than there are cache entries (%u) "
"for cache %u", pPDU->TotalEntries[i],
sbcCurrentBitmapCaps.CellCacheInfo[i].NumEntries,
i));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_PersistentKeyPDUTooManyCacheKeys,
(PBYTE)pPDU, DataLength);
goto ExitFunc;
}
}
// Check if we receive 0 keys, in this case, we will just exit the
// function quietly
if (TotalEntries == 0) {
TRC_ERR((TB, "0 persistent key"));
goto ExitFunc;
}
// Check this against the max allowed by the protocol.
if (TotalEntries > TS_BITMAPCACHE_MAX_TOTAL_PERSISTENT_KEYS) {
TRC_ERR((TB,"Client specified %u total keys, beyond %u "
"protocol limit", TotalEntries,
TS_BITMAPCACHE_MAX_TOTAL_PERSISTENT_KEYS));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_PersistentKeyPDUTooManyTotalKeys,
(PBYTE)pPDU, DataLength);
goto ExitFunc;
}
sbcKeyDatabaseSize = sizeof(SBC_BITMAP_CACHE_KEY_INFO) + (TotalEntries - 1) *
sizeof(SBC_MRU_KEY);
sbcKeyDatabase = (SBC_BITMAP_CACHE_KEY_INFO *)COM_Malloc(sbcKeyDatabaseSize);
if (sbcKeyDatabase == NULL) {
sbcKeyDatabaseSize = 0;
TRC_ERR((TB,"Could not alloc persistent key info"));
goto ExitFunc;
}
// Set up general data and entry pointers within the key array.
CurEntry = 0;
for (i = 0; i < TS_BITMAPCACHE_MAX_CELL_CACHES; i++) {
sbcKeyDatabase->KeyStart[i] = CurEntry;
CurEntry += pPDU->TotalEntries[i];
sbcKeyDatabase->NumKeys[i] = 0;
sbcNumKeysExpected[i] = pPDU->TotalEntries[i];
}
sbcTotalKeysExpected = TotalEntries;
sbcKeyDatabase->TotalKeys = 0;
// Mark that we have received the first-keys packet.
sbcPersistentKeysReceived = TRUE;
}
// If this is not the first PDU but we failed a previous allocation,
// too bad, no persistent keys. This could also happen if the client
// continues sending persistent cache keys after sending the
// TS_BITMAPCACHE_LAST_OVERALL flag that indicates the end of the key
// packet stream.
if (sbcKeyDatabase == NULL)
goto ExitFunc;
// Total the supposed number of keys received in the PDU. Check against
// the PDU size.
TotalEntries = 0;
for (i = 0; i < TS_BITMAPCACHE_MAX_CELL_CACHES; i++)
TotalEntries += pPDU->NumEntries[i];
if (DataLength < (sizeof(TS_BITMAPCACHE_PERSISTENT_LIST) +
(TotalEntries - 1) *
sizeof(TS_BITMAPCACHE_PERSISTENT_LIST_ENTRY))) {
TRC_ERR((TB,"Client specified %u keys in this PersistentListPDU, "
"PDU data not long enough", TotalEntries));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_PersistentKeyPDUBadLength,
(PBYTE)pPDU, DataLength);
goto ExitFunc;
}
// Loop across the caches to check each one.
CurEntry = 0;
for (i = 0; i < TS_BITMAPCACHE_MAX_CELL_CACHES; i++) {
// Make sure that we don't receive more keys than were specified in
// the original PDU.
if ((sbcKeyDatabase->NumKeys[i] + pPDU->NumEntries[i]) <=
sbcNumKeysExpected[i]) {
// Transfer keys into the key list. We set these up for the MRU
// list in the same order received since the client does not
// have any MRU priority info to give us.
for (j = 0; j < pPDU->NumEntries[i]; j++) {
(&(sbcKeyDatabase->Keys[sbcKeyDatabase->KeyStart[i]]))
[sbcKeyDatabase->NumKeys[i] + j].Key1 =
pPDU->Entries[CurEntry].Key1;
(&(sbcKeyDatabase->Keys[sbcKeyDatabase->KeyStart[i]]))
[sbcKeyDatabase->NumKeys[i] + j].Key2 =
pPDU->Entries[CurEntry].Key2;
(&(sbcKeyDatabase->Keys[sbcKeyDatabase->KeyStart[i]]))
[sbcKeyDatabase->NumKeys[i] + j].CacheIndex =
sbcKeyDatabase->NumKeys[i] + j;
CurEntry++;
}
sbcKeyDatabase->NumKeys[i] += pPDU->NumEntries[i];
sbcKeyDatabase->TotalKeys += pPDU->NumEntries[i];
}
else {
TRC_ERR((TB,"Received too many keys in cache %u", i));
WDW_LogAndDisconnect(m_pTSWd, TRUE,
Log_RDP_PersistentKeyPDUTooManyCacheKeys,
(PBYTE)pPDU, DataLength);
goto ExitFunc;
}
}
if (pPDU->bLastPDU) {
// This is an assertion but not fatal -- we simply use what we
// received.
TRC_ASSERT((sbcKeyDatabase->TotalKeys == sbcTotalKeysExpected),
(TB,"Num expected persistent keys does not match sent keys "
"(rec'd=%d, expect=%d)", sbcKeyDatabase->TotalKeys,
sbcTotalKeysExpected));
}
}
else {
TRC_ERR((TB,"Persistent key PDU received but data is not long enough "
"for header, LocalID=%u", LocalID));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_PersistentKeyPDUBadLength,
(PBYTE)pPDU, DataLength);
}
ExitFunc:
DC_END_FN();
}
/****************************************************************************/
// Returns the persistent key database to the DD and free the local copy
/****************************************************************************/
void RDPCALL SHCLASS SBC_GetBitmapKeyDatabase(unsigned* keyDBSize,
BYTE* pKeyDB)
{
unsigned i, CurEntry;
SBC_BITMAP_CACHE_KEY_INFO* pKeyDatabase;
DC_BEGIN_FN("SBC_GetBitmapKeyDatabase");
// No persistent key database setup
if ( sbcKeyDatabaseSize == 0 || sbcKeyDatabase == NULL) {
TRC_NRM((TB, "Failed to get the key database: dd keysize=%d, wd keysize=%d, keydatabase=%p",
*keyDBSize, sbcKeyDatabaseSize, sbcKeyDatabase));
*keyDBSize = 0;
DC_QUIT;
}
// DD's buffer is too small
if (*keyDBSize < sbcKeyDatabaseSize) {
TRC_NRM((TB, "Failed to get the key database: dd keysize=%d, wd keysize=%d, keydatabase=%p",
*keyDBSize, sbcKeyDatabaseSize, sbcKeyDatabase));
*keyDBSize = sbcKeyDatabaseSize;
DC_QUIT;
}
TRC_NRM((TB, "get bitmapKeyDatabase: copy keys from wd to dd"));
pKeyDatabase = (SBC_BITMAP_CACHE_KEY_INFO*)(pKeyDB);
memcpy(pKeyDatabase, sbcKeyDatabase, sbcKeyDatabaseSize);
*keyDBSize = sbcKeyDatabaseSize;
SBC_FreeBitmapKeyDatabase();
DC_EXIT_POINT:
return;
}
/****************************************************************************/
// Free the key databaes
/****************************************************************************/
void RDPCALL SHCLASS SBC_FreeBitmapKeyDatabase()
{
if (sbcKeyDatabase != NULL) {
COM_Free(sbcKeyDatabase);
sbcKeyDatabase = NULL;
}
sbcKeyDatabaseSize = 0;
}
/****************************************************************************/
// SBC_HandleBitmapCacheErrorPDU: Handles a bitmap cache error PDU.
// Right now this function just checks the length of the PDU to make
// sure it is valid. If not, the server close the client connection
// This function is for future support of error PDU implementation
/****************************************************************************/
void RDPCALL SHCLASS SBC_HandleBitmapCacheErrorPDU(
TS_BITMAPCACHE_ERROR_PDU *pPDU,
unsigned DataLength,
LOCALPERSONID LocalID)
{
unsigned i;
DC_BEGIN_FN("SBC_HandleBitmapCacheErrorPDU");
if (DataLength >= (sizeof(TS_BITMAPCACHE_ERROR_PDU) -
sizeof(TS_BITMAPCACHE_ERROR_INFO))) {
if ((sizeof(TS_BITMAPCACHE_ERROR_PDU) - sizeof(TS_BITMAPCACHE_ERROR_INFO)
+ pPDU->NumInfoBlocks * sizeof(TS_BITMAPCACHE_ERROR_INFO))
== DataLength) {
TRC_NRM((TB, "Received a bitmap cache error PDU"));
// update the total number of error pdus received
sbcTotalNumErrorPDUs++;
// For the duration of a session, we will only handle maximum
// MAX_NUM_ERROR_PDU_SEND numbers of error PDUs received.
// This is to avoid bad clients attack the server with error pdu
if (sbcTotalNumErrorPDUs <= MAX_NUM_ERROR_PDU_SEND) {
for (i = 0; i < pPDU->NumInfoBlocks; i++) {
if (pPDU->Info[i].CacheID < sbcCurrentBitmapCaps.NumCellCaches) {
// For now, the server only handles the client clear cache
// request. Server will clear the cache and then issue a screen
// redraw. The server doesn't handle if the client requests to
// resize the cache.
sbcClearCache[pPDU->Info[i].CacheID] = pPDU->Info[i].bFlushCache;
}
}
TRC_DBG((TB, "Issued clear cache to RDPDD"));
// trigger a timer so that when DD gets it, it will clear the cache.
DCS_TriggerUpdateShmCallback();
}
else {
TRC_DBG((TB, "Received more than %d bitmap error pdus.",
MAX_NUM_ERROR_PDU_SEND));
}
}
else {
TRC_ERR((TB,"Bitmap Cache Error PDU received but data Length is wrong, "
"too many or too few info blocks, LocalID=%u", LocalID));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_BitmapCacheErrorPDUBadLength,
(PBYTE)pPDU, DataLength);
}
}
else {
TRC_ERR((TB,"Bitmap Cache Error PDU received but data is not long enough "
"for header, LocalID=%u", LocalID));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_BitmapCacheErrorPDUBadLength,
(PBYTE)pPDU, DataLength);
}
DC_END_FN();
}
/****************************************************************************/
// SBC_HandleOffscrCacheErrorPDU: Handles an offscr cache error PDU.
// This function checks the length of the PDU to make
// sure it is valid. If not, the server close the client connection
// When this PDU is received, WD will pass disable offscreen rendering to
// DD and DD will disable the offscreen rendering support and refresh
// the screen
/****************************************************************************/
void RDPCALL SHCLASS SBC_HandleOffscrCacheErrorPDU(
TS_OFFSCRCACHE_ERROR_PDU *pPDU,
unsigned DataLength,
LOCALPERSONID LocalID)
{
DC_BEGIN_FN("SBC_HandleOffscrCacheErrorPDU");
if (DataLength >= sizeof(TS_OFFSCRCACHE_ERROR_PDU)) {
TRC_NRM((TB, "Received an offscreen cache error PDU"));
if (pPDU->flags & TS_FLUSH_AND_DISABLE_OFFSCREEN) {
TRC_DBG((TB, "Issued clear cache to RDPDD"));
sbcDisableOffscreenCaching = TRUE;
// trigger a timer so that when DD gets it, it will disable
// offscreen rendering and refresh the screen
DCS_TriggerUpdateShmCallback();
}
else {
TRC_DBG((TB, "Unsupported flag, just ignore this PDU"));
}
}
else {
TRC_ERR((TB,"Offscr Cache Error PDU received but data is not long enough "
"for header, LocalID=%u", LocalID));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_BitmapCacheErrorPDUBadLength,
(PBYTE)pPDU, DataLength);
}
DC_END_FN();
}
#ifdef DRAW_NINEGRID
/****************************************************************************/
// SBC_HandleDrawNineGridErrorPDU: Handles a drawninegrid cache error PDU.
// This function checks the length of the PDU to make
// sure it is valid. If not, the server close the client connection
// When this PDU is received, WD will pass disable drawninegrid rendering to
// DD and DD will disable the drawninegrid rendering support and refresh
// the screen
/****************************************************************************/
void RDPCALL SHCLASS SBC_HandleDrawNineGridErrorPDU(
TS_DRAWNINEGRID_ERROR_PDU *pPDU,
unsigned DataLength,
LOCALPERSONID LocalID)
{
DC_BEGIN_FN("SBC_HandleDrawNineGridErrorPDU");
if (DataLength >= sizeof(TS_DRAWNINEGRID_ERROR_PDU)) {
TRC_NRM((TB, "Received an drawninegrid cache error PDU"));
if (pPDU->flags & TS_FLUSH_AND_DISABLE_DRAWNINEGRID) {
TRC_DBG((TB, "Issued clear cache to RDPDD"));
sbcDisableDrawNineGridCaching = TRUE;
// trigger a timer so that when DD gets it, it will disable
// drawninegrid rendering and refresh the screen
DCS_TriggerUpdateShmCallback();
}
else {
TRC_DBG((TB, "Unsupported flag, just ignore this PDU"));
}
}
else {
TRC_ERR((TB,"DrawNineGrid Cache Error PDU received but data is not long enough "
"for header, LocalID=%u", LocalID));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_BitmapCacheErrorPDUBadLength,
(PBYTE)pPDU, DataLength);
}
DC_END_FN();
}
#endif
#ifdef DRAW_GDIPLUS
void RDPCALL SHCLASS SBC_HandleDrawGdiplusErrorPDU(
TS_DRAWGDIPLUS_ERROR_PDU *pPDU,
unsigned DataLength,
LOCALPERSONID LocalID)
{
DC_BEGIN_FN("SBC_HandleDrawGdiplusErrorPDU");
if (DataLength >= sizeof(TS_DRAWGDIPLUS_ERROR_PDU)) {
TRC_ERR((TB, "Received a drawgdiplus error PDU"));
if (pPDU->flags & TS_FLUSH_AND_DISABLE_DRAWGDIPLUS) {
TRC_DBG((TB, "Issued clear cache to RDPDD"));
sbcDisableDrawGdiplus = TRUE;
// trigger a timer so that when DD gets it, it will disable
// drawninegrid rendering and refresh the screen
DCS_TriggerUpdateShmCallback();
}
else {
TRC_DBG((TB, "Unsupported flag, just ignore this PDU"));
}
}
else {
TRC_ERR((TB,"DrawGdiplus Error PDU received but data is not long enough "
"for header, LocalID=%u", LocalID));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_BitmapCacheErrorPDUBadLength,
(PBYTE)pPDU, DataLength);
}
DC_END_FN();
}
#endif // DRAW_GDIPLUS
/****************************************************************************/
// SBC_UpdateShm: Called on WinStation context to update the SBC shared
// memory.
/****************************************************************************/
void RDPCALL SHCLASS SBC_UpdateShm(void)
{
unsigned i;
DC_BEGIN_FN("SBC_UpdateShm");
TRC_NRM((TB, "Update SBC shm"));
// Cell bitmap caches.
m_pShm->sbc.NumBitmapCaches = sbcCurrentBitmapCaps.NumCellCaches;
m_pShm->sbc.fClearCache = FALSE;
for (i = 0; i < sbcCurrentBitmapCaps.NumCellCaches; i++) {
m_pShm->sbc.bitmapCacheInfo[i].Info =
sbcCurrentBitmapCaps.CellCacheInfo[i];
// set the clear cache flag for all caches
if (sbcClearCache[i] == TRUE) {
m_pShm->sbc.fClearCache = TRUE;
}
m_pShm->sbc.bitmapCacheInfo[i].fClearCache = sbcClearCache[i];
sbcClearCache[i] = FALSE;
TRC_NRM((TB, "bitmap cell cache(%u) NumEntries(%u) CellSize(%u)",
i, m_pShm->sbc.bitmapCacheInfo[i].Info.NumEntries,
SBC_CellSizeFromCacheID(i)));
}
// Cache bitmap order style.
m_pShm->sbc.bUseRev2CacheBitmapOrder =
((sbcCurrentBitmapCaps.capabilitySetType >=
TS_BITMAPCACHE_REV2) ? TRUE : FALSE);
// Glyph and glyph fragment caching.
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++) {
m_pShm->sbc.caps.glyphCacheSize[i].cEntries = sbcGlyphCacheSizes[i].cEntries;
m_pShm->sbc.caps.glyphCacheSize[i].cbCellSize = sbcGlyphCacheSizes[i].cbCellSize;
TRC_NRM((TB, "glyph cache(%u) entries(%u) cellSize(%u)", i,
m_pShm->sbc.caps.glyphCacheSize[i].cEntries,
m_pShm->sbc.caps.glyphCacheSize[i].cbCellSize));
}
m_pShm->sbc.caps.fragCacheSize[0].cEntries = sbcFragCacheSizes[0].cEntries;
m_pShm->sbc.caps.fragCacheSize[0].cbCellSize = sbcFragCacheSizes[0].cbCellSize;
m_pShm->sbc.syncRequired = (m_pShm->sbc.syncRequired || sbcSyncRequired) ?
TRUE : FALSE;
sbcSyncRequired = FALSE;
m_pShm->sbc.fCachingEnabled = (sbcCachingOn ? TRUE : FALSE);
m_pShm->sbc.caps.GlyphSupportLevel = sbcGlyphSupportLevel;
m_pShm->sbc.caps.brushSupportLevel = sbcBrushSupportLevel;
m_pShm->sbc.newCapsData = (m_pShm->sbc.newCapsData || sbcNewCapsData) ?
TRUE : FALSE;
sbcNewCapsData = FALSE;
// Offscreen cache
m_pShm->sbc.offscreenCacheInfo.supportLevel = sbcOffscreenCacheInfo.supportLevel;
m_pShm->sbc.offscreenCacheInfo.cacheSize = sbcOffscreenCacheInfo.cacheSize;
m_pShm->sbc.offscreenCacheInfo.cacheEntries = sbcOffscreenCacheInfo.cacheEntries;
m_pShm->sbc.fDisableOffscreen = sbcDisableOffscreenCaching;
#ifdef DRAW_NINEGRID
// DrawNineGrid cache
m_pShm->sbc.drawNineGridCacheInfo.supportLevel = sbcDrawNineGridCacheInfo.supportLevel;
m_pShm->sbc.drawNineGridCacheInfo.cacheSize = sbcDrawNineGridCacheInfo.cacheSize;
m_pShm->sbc.drawNineGridCacheInfo.cacheEntries = sbcDrawNineGridCacheInfo.cacheEntries;
m_pShm->sbc.fDisableDrawNineGrid = sbcDisableDrawNineGridCaching;
#endif
#ifdef DRAW_GDIPLUS
m_pShm->sbc.drawGdiplusInfo.supportLevel = sbcDrawGdiplusInfo.supportLevel;
m_pShm->sbc.drawGdiplusInfo.GdipVersion = sbcDrawGdiplusInfo.GdipVersion;
m_pShm->sbc.drawGdiplusInfo.GdipCacheLevel = sbcDrawGdiplusInfo.GdipCacheLevel;
m_pShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries =
sbcDrawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries;
m_pShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries =
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries;
m_pShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries = sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries;
m_pShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries =
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries;
m_pShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries =
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries;
m_pShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipGraphicsCacheChunkSize =
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipGraphicsCacheChunkSize;
m_pShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipObjectBrushCacheChunkSize =
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectBrushCacheChunkSize;
m_pShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipObjectPenCacheChunkSize =
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectPenCacheChunkSize;
m_pShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize =
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize;
m_pShm->sbc.drawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheChunkSize =
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheChunkSize;
m_pShm->sbc.drawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheTotalSize =
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheTotalSize;
m_pShm->sbc.drawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheMaxSize =
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheMaxSize;
m_pShm->sbc.fDisableDrawGdiplus = sbcDisableDrawGdiplus;
#endif // DRAW_GDIPLUS
m_pShm->sbc.fAllowCacheWaitingList = sbcCurrentBitmapCaps.bAllowCacheWaitingList;
#ifdef DC_HICOLOR
m_pShm->sbc.clientBitsPerPel = sbcClientBitsPerPel;
#endif
TRC_NRM((TB, "syncRequired(%u) fCachingEnabled(%u) newCapsData(%u)",
m_pShm->sbc.syncRequired,
m_pShm->sbc.fCachingEnabled,
m_pShm->sbc.newCapsData));
DC_END_FN();
}
/****************************************************************************/
// SBCRedetermineBitmapCacheSize: Enumerates all the people in the share and
// redetermines the overall capabilities.
//
// Returns: TRUE if caching should be enabled, FALSE otherwise.
/****************************************************************************/
BOOLEAN RDPCALL SHCLASS SBCRedetermineBitmapCacheSize(void)
{
BOOLEAN rc = TRUE;
unsigned i;
DC_BEGIN_FN("SBCRedetermineBitmapCacheSize");
#ifdef DC_HICOLOR
// Need to update the bpp as this affects the size of the caches
sbcClientBitsPerPel = m_desktopBpp;
#endif
// Set the initial local max/min caps to defaults.
sbcCurrentBitmapCaps = sbcDefaultBitmapCaps;
// First attempt to enumerate rev2 capabilities, if present.
CPC_EnumerateCapabilities(TS_CAPSETTYPE_BITMAPCACHE_REV2, NULL,
SBCEnumBitmapCacheCaps);
// Then enumerate rev1 caps if present.
CPC_EnumerateCapabilities(TS_CAPSETTYPE_BITMAPCACHE, NULL,
SBCEnumBitmapCacheCaps);
// Trace the results and check to see if we negotiated any of the
// cell caches to zero, in which case bitmap caching becomes disabled.
TRC_NRM((TB,"New caps: bPersistentLists=%s, NumCellCaches=%u",
(sbcCurrentBitmapCaps.bPersistentKeysExpected ? "TRUE" : "FALSE"),
sbcCurrentBitmapCaps.NumCellCaches));
if (sbcCurrentBitmapCaps.NumCellCaches > 0) {
for (i = 0; i < sbcCurrentBitmapCaps.NumCellCaches; i++) {
TRC_NRM((TB, " Cell cache %u: Persistent=%s, NumEntries=%u",
i, sbcCurrentBitmapCaps.CellCacheInfo[i].bSendBitmapKeys ?
"TRUE" : "FALSE",
sbcCurrentBitmapCaps.CellCacheInfo[i].NumEntries));
if (sbcCurrentBitmapCaps.CellCacheInfo[i].NumEntries == 0) {
// Set the number of cell caches to zero as a signal for flag-
// setting when the DD calls to get the new caps.
sbcCurrentBitmapCaps.NumCellCaches = 0;
// Return FALSE so that caching is disabled.
TRC_ERR((TB, "Zero NumEntries on cache %u, caching disabled",
i));
rc = FALSE;
break;
}
}
}
else {
// Return FALSE to disable caching.
TRC_ERR((TB,"Zero caches, disabling caching"));
rc = FALSE;
}
DC_END_FN();
return rc;
}
/****************************************************************************/
// SBCEnumBitmapCaps: Callback function passed to CPC_EnumerateCapabilities.
// It will be called with a capability structure for each person in the share
// corresponding to the TS_CAPSETTYPE_BITMAPCACHE and _REV2 capability
// structures.
//
// Params:
// personID - ID of person with these capabilities.
// pProtCaps - pointer to capabilities structure for this person. This
// pointer is only valid within the call to this function.
/****************************************************************************/
void RDPCALL SHCLASS SBCEnumBitmapCacheCaps(
LOCALPERSONID locPersonID,
UINT_PTR UserData,
PTS_CAPABILITYHEADER pCapHdr)
{
unsigned i;
#ifdef DC_HICOLOR
unsigned shadowerBpp;
unsigned scaleNum = 1;
unsigned scaleDenom = 1;
#endif
DC_BEGIN_FN("SBCEnumBitmapCacheCaps");
DC_IGNORE_PARAMETER(UserData);
if (pCapHdr->capabilitySetType == TS_CAPSETTYPE_BITMAPCACHE_REV2) {
TS_BITMAPCACHE_CAPABILITYSET_REV2 *pCaps;
// We can receive a zero size for the capability if we didn't receive
// any rev2 caps from any client.
if (pCapHdr->lengthCapability >=
sizeof(TS_BITMAPCACHE_CAPABILITYSET_REV2)) {
pCaps = (PTS_BITMAPCACHE_CAPABILITYSET_REV2)pCapHdr;
// Cache version defaults to rev2, we don't need to change
// sbcCurrentBitmapCaps.capabilitySetType.
TRC_NRM((TB,"[%ld]: Rec'd REV2 caps, # caches=%d",
locPersonID, pCaps->NumCellCaches));
// Now we look at each capability parameter and take the max or min
// of the local and remote settings, as appropriate.
sbcCurrentBitmapCaps.bPersistentKeysExpected =
pCaps->bPersistentKeysExpected;
sbcCurrentBitmapCaps.bAllowCacheWaitingList =
min(sbcCurrentBitmapCaps.bAllowCacheWaitingList,
pCaps->bAllowCacheWaitingList);
sbcCurrentBitmapCaps.NumCellCaches =
min(pCaps->NumCellCaches, sbcCurrentBitmapCaps.NumCellCaches);
for (i = 0; i < sbcCurrentBitmapCaps.NumCellCaches; i++) {
// If all parties in a share are rev2, and any client wants keys,
// send them.
if (!sbcCurrentBitmapCaps.CellCacheInfo[i].bSendBitmapKeys)
sbcCurrentBitmapCaps.CellCacheInfo[i].bSendBitmapKeys =
pCaps->CellCacheInfo[i].bSendBitmapKeys;
#ifdef DC_HICOLOR
sbcCurrentBitmapCaps.CellCacheInfo[i].NumEntries =
min(((pCaps->CellCacheInfo[i].NumEntries * scaleNum)
/ scaleDenom),
sbcCurrentBitmapCaps.CellCacheInfo[i].NumEntries);
#else
sbcCurrentBitmapCaps.CellCacheInfo[i].NumEntries =
min(pCaps->CellCacheInfo[i].NumEntries,
sbcCurrentBitmapCaps.CellCacheInfo[i].NumEntries);
#endif
}
}
else {
TRC_NRM((TB,"[%ld]: No rev2 caps received", locPersonID));
TRC_ASSERT((pCapHdr->lengthCapability == 0),
(TB, "[%ld]: Rev2 capability length (%u) too small",
locPersonID, pCapHdr->lengthCapability));
}
}
else {
TS_BITMAPCACHE_CAPABILITYSET *pOldCaps;
TRC_ASSERT((pCapHdr->capabilitySetType == TS_CAPSETTYPE_BITMAPCACHE),
(TB,"Received caps that are neither rev1 nor rev2!"));
// We can receive a zero size for the capability if we didn't receive
// any rev1 caps from any client.
if (pCapHdr->lengthCapability >=
sizeof(TS_BITMAPCACHE_CAPABILITYSET)) {
// Rev 1 (Hydra 4.0 release) bitmap caching caps. Map to the
// rev2 caps structure, taking min of the cell sizes and numbers
// of entries.
TRC_NRM((TB,"[%ld]: Rec'd REV1 caps", locPersonID));
// We now have to use rev1 protocol to all clients.
sbcCurrentBitmapCaps.capabilitySetType = TS_BITMAPCACHE_REV1;
pOldCaps = (TS_BITMAPCACHE_CAPABILITYSET *)pCapHdr;
sbcCurrentBitmapCaps.bPersistentKeysExpected = FALSE;
sbcCurrentBitmapCaps.bAllowCacheWaitingList = FALSE;
sbcCurrentBitmapCaps.NumCellCaches =
min(3, sbcCurrentBitmapCaps.NumCellCaches);
sbcCurrentBitmapCaps.CellCacheInfo[0].bSendBitmapKeys = FALSE;
if (pOldCaps->Cache1MaximumCellSize == SBC_CellSizeFromCacheID(0)) {
sbcCurrentBitmapCaps.CellCacheInfo[0].NumEntries =
min(pOldCaps->Cache1Entries,
sbcCurrentBitmapCaps.CellCacheInfo[0].NumEntries);
}
else {
// Did not receive the required size from the client. This is
// nonstandard behavior on RDP 4.0, so no problem to disable
// caching. Set the NumEntries to zero to turn off caching.
sbcCurrentBitmapCaps.CellCacheInfo[0].NumEntries = 0;
}
sbcCurrentBitmapCaps.CellCacheInfo[1].bSendBitmapKeys = FALSE;
if (pOldCaps->Cache2MaximumCellSize == SBC_CellSizeFromCacheID(1)) {
sbcCurrentBitmapCaps.CellCacheInfo[1].NumEntries =
min(pOldCaps->Cache2Entries,
sbcCurrentBitmapCaps.CellCacheInfo[1].NumEntries);
}
else {
// Did not receive the required size from the client. This is
// nonstandard behavior on RDP 4.0, so no problem to disable
// caching. Set the NumEntries to zero to turn off caching.
sbcCurrentBitmapCaps.CellCacheInfo[1].NumEntries = 0;
}
sbcCurrentBitmapCaps.CellCacheInfo[2].bSendBitmapKeys = FALSE;
if (pOldCaps->Cache3MaximumCellSize == SBC_CellSizeFromCacheID(2)) {
sbcCurrentBitmapCaps.CellCacheInfo[2].NumEntries =
min(pOldCaps->Cache3Entries,
sbcCurrentBitmapCaps.CellCacheInfo[2].NumEntries);
}
else {
// Did not receive the required size from the client. This is
// nonstandard behavior on RDP 4.0, so no problem to disable
// caching. Set the NumEntries to zero to turn off caching.
sbcCurrentBitmapCaps.CellCacheInfo[2].NumEntries = 0;
}
}
else {
TRC_NRM((TB,"No rev1 caps received"));
TRC_ASSERT((pCapHdr->lengthCapability == 0),
(TB, "Rev1 capability length (%u) too small",
pCapHdr->lengthCapability));
}
}
DC_END_FN();
}
/****************************************************************************/
/* FUNCTION: SBCRedetermineBrushSupport */
/* */
/* Enumerates all the people in the share and redetermines the brush */
/* support level depending on their and the local receive capabilities. */
/* */
/* RETURNS: the share brush support level */
/****************************************************************************/
BOOLEAN RDPCALL SHCLASS SBCRedetermineBrushSupport(void)
{
unsigned i;
BOOLEAN rc = TRUE;
DC_BEGIN_FN("SBCRedetermineBrushSupport");
/************************************************************************/
/* Start by setting brush support to the highest supported */
/************************************************************************/
sbcBrushSupportLevel = TS_BRUSH_COLOR8x8;
TRC_NRM((TB, "Initial brush support level: %ld", sbcBrushSupportLevel));
/************************************************************************/
/* Enumerate all the brush support capabilities of all the parties. */
/* Brush support is set to the lowest common denominator. */
/************************************************************************/
CPC_EnumerateCapabilities(TS_CAPSETTYPE_BRUSH, NULL, SBCEnumBrushCaps);
if (sbcBrushSupportLevel == TS_BRUSH_DEFAULT)
rc = FALSE;
TRC_NRM((TB, "Enumerated brush support level: %ld", sbcBrushSupportLevel));
DC_END_FN();
return rc;
}
/****************************************************************************/
/* FUNCTION: SBCEnumBrushCaps */
/* */
/* Function passed to CPC_EnumerateCapabilities. It will be called with a */
/* capability structure for each person in the share corresponding to the */
/* TS_CAPSETTYPE_BRUSH capability structure. */
/* */
/* PARAMETERS: */
/* */
/* personID - ID of person with these capabilities. */
/* */
/* pProtCaps - pointer to capabilities structure for this person. This */
/* pointer is only valid within the call to this function. */
/****************************************************************************/
void RDPCALL SHCLASS SBCEnumBrushCaps(
LOCALPERSONID locPersonID,
UINT_PTR UserData,
PTS_CAPABILITYHEADER pCapabilities)
{
PTS_BRUSH_CAPABILITYSET pBrushCaps;
unsigned i;
DC_BEGIN_FN("SBCEnumBrushCaps");
DC_IGNORE_PARAMETER(UserData);
pBrushCaps = (PTS_BRUSH_CAPABILITYSET)pCapabilities;
/************************************************************************/
/* Set the brush support level to the lowest common denominator of all */
/* the parties in the call. */
/************************************************************************/
if (pCapabilities->lengthCapability >= sizeof(TS_BRUSH_CAPABILITYSET)) {
pBrushCaps = (PTS_BRUSH_CAPABILITYSET)pCapabilities;
TRC_NRM((TB, "Brush Support Level[ID=%u]: %ld", locPersonID,
pBrushCaps->brushSupportLevel));
sbcBrushSupportLevel = min(sbcBrushSupportLevel,
pBrushCaps->brushSupportLevel);
}
else {
sbcBrushSupportLevel = TS_BRUSH_DEFAULT;
TRC_NRM((TB, "[%ld]: Brush Support Level Unknown", locPersonID));
}
TRC_NRM((TB, "[%ld]: Negotiated brush level: %ld", locPersonID,
sbcBrushSupportLevel));
DC_END_FN();
}
/****************************************************************************/
/* FUNCTION: SBCEnumOffscreenCaps */
/* */
/* Function passed to CPC_EnumerateCapabilities. It will be called with a */
/* capability structure for each person in the share corresponding to the */
/* TS_CAPSETTYPE_OFFSCREEN capability structure. */
/* */
/* PARAMETERS: */
/* */
/* personID - ID of person with these capabilities. */
/* */
/* pProtCaps - pointer to capabilities structure for this person. This */
/* pointer is only valid within the call to this function. */
/****************************************************************************/
void RDPCALL SHCLASS SBCEnumOffscreenCaps(
LOCALPERSONID locPersonID,
UINT_PTR UserData,
PTS_CAPABILITYHEADER pCapabilities)
{
PTS_OFFSCREEN_CAPABILITYSET pOffscreenCaps;
DC_BEGIN_FN("SBCEnumOffscreenCaps");
DC_IGNORE_PARAMETER(UserData);
pOffscreenCaps = (PTS_OFFSCREEN_CAPABILITYSET)pCapabilities;
/************************************************************************/
/* Set the offscr support level to the lowest common denominator of all */
/* the parties in the call. */
/************************************************************************/
if (pCapabilities->lengthCapability >= sizeof(TS_OFFSCREEN_CAPABILITYSET)) {
pOffscreenCaps = (PTS_OFFSCREEN_CAPABILITYSET)pCapabilities;
TRC_NRM((TB, "Offscreen Support Level[ID=%u]: %ld", locPersonID,
pOffscreenCaps->offscreenSupportLevel));
sbcOffscreenCacheInfo.supportLevel = min(sbcOffscreenCacheInfo.supportLevel,
pOffscreenCaps->offscreenSupportLevel);
sbcOffscreenCacheInfo.cacheSize = min(sbcOffscreenCacheInfo.cacheSize,
pOffscreenCaps->offscreenCacheSize);
sbcOffscreenCacheInfo.cacheEntries = min(sbcOffscreenCacheInfo.cacheEntries,
pOffscreenCaps->offscreenCacheEntries);
}
else {
sbcOffscreenCacheInfo.supportLevel = TS_OFFSCREEN_DEFAULT;
TRC_NRM((TB, "[%ld]: Offscreen Support Level Unknown", locPersonID));
}
if (sbcOffscreenCacheInfo.cacheSize == 0 ||
sbcOffscreenCacheInfo.cacheEntries == 0) {
sbcOffscreenCacheInfo.supportLevel = TS_OFFSCREEN_DEFAULT;
}
TRC_NRM((TB, "[%ld]: Negotiated offscreen level: %ld", locPersonID,
sbcOffscreenCacheInfo.supportLevel));
DC_END_FN();
}
/****************************************************************************/
/* FUNCTION: SBCRedetermineOffscreenSupport */
/* */
/* Enumerates all the people in the share and redetermines the offscreen */
/* support level depending on their and the local receive capabilities. */
/* */
/* RETURNS: the share offscreen support level */
/****************************************************************************/
BOOLEAN RDPCALL SHCLASS SBCRedetermineOffscreenSupport(void)
{
unsigned i;
BOOLEAN rc = TRUE;
DC_BEGIN_FN("SBCRedetermineOffscreenSupport");
/************************************************************************/
/* Start by setting offscreen support to the highest supported */
/************************************************************************/
sbcOffscreenCacheInfo.supportLevel = TS_OFFSCREEN_SUPPORTED;
sbcOffscreenCacheInfo.cacheSize = TS_OFFSCREEN_CACHE_SIZE_SERVER_DEFAULT;
sbcOffscreenCacheInfo.cacheEntries = TS_OFFSCREEN_CACHE_ENTRIES_DEFAULT;
TRC_NRM((TB, "Initial offscreen support level: %ld",
sbcOffscreenCacheInfo.supportLevel));
/************************************************************************/
/* Enumerate all the offscr support capabilities of all the parties. */
/* Offscr support is set to the lowest common denominator. */
/************************************************************************/
CPC_EnumerateCapabilities(TS_CAPSETTYPE_OFFSCREENCACHE, NULL,
SBCEnumOffscreenCaps);
if (sbcOffscreenCacheInfo.supportLevel == TS_OFFSCREEN_DEFAULT)
rc = FALSE;
TRC_NRM((TB, "Enumerated offscreen support level: %ld",
sbcOffscreenCacheInfo.supportLevel));
DC_END_FN();
return rc;
}
#ifdef DRAW_NINEGRID
/****************************************************************************/
// FUNCTION: SBCEnumDrawNineGridCaps
//
// Function passed to CPC_EnumerateCapabilities. It will be called with a
// capability structure for each person in the share corresponding to the
// TS_CAPSETTYPE_DRAWNINEGRID capability structure.
//
// PARAMETERS:
//
// personID - ID of person with these capabilities.
//
// pProtCaps - pointer to capabilities structure for this person. This
// pointer is only valid within the call to this function.
/****************************************************************************/
void RDPCALL SHCLASS SBCEnumDrawNineGridCaps(
LOCALPERSONID locPersonID,
UINT_PTR UserData,
PTS_CAPABILITYHEADER pCapabilities)
{
PTS_DRAW_NINEGRID_CAPABILITYSET pDrawNineGridCaps;
DC_BEGIN_FN("SBCEnumDrawNineGridCaps");
DC_IGNORE_PARAMETER(UserData);
pDrawNineGridCaps = (PTS_DRAW_NINEGRID_CAPABILITYSET)pCapabilities;
/************************************************************************/
// Set the drawninegrid support level to the lowest common denominator of all
// the parties in the call.
/************************************************************************/
if (pCapabilities->lengthCapability >= sizeof(TS_DRAW_NINEGRID_CAPABILITYSET)) {
pDrawNineGridCaps = (PTS_DRAW_NINEGRID_CAPABILITYSET)pCapabilities;
TRC_NRM((TB, "DrawNineGrid Support Level[ID=%u]: %ld", locPersonID,
pDrawNineGridCaps->drawNineGridSupportLevel));
sbcDrawNineGridCacheInfo.supportLevel = min(sbcDrawNineGridCacheInfo.supportLevel,
pDrawNineGridCaps->drawNineGridSupportLevel);
sbcDrawNineGridCacheInfo.cacheSize = min(sbcDrawNineGridCacheInfo.cacheSize,
pDrawNineGridCaps->drawNineGridCacheSize);
sbcDrawNineGridCacheInfo.cacheEntries = min(sbcDrawNineGridCacheInfo.cacheEntries,
pDrawNineGridCaps->drawNineGridCacheEntries);
}
else {
sbcDrawNineGridCacheInfo.supportLevel = TS_DRAW_NINEGRID_DEFAULT;
TRC_NRM((TB, "[%ld]: DrawNineGrid Support Level Unknown", locPersonID));
}
if (sbcDrawNineGridCacheInfo.cacheSize == 0 ||
sbcDrawNineGridCacheInfo.cacheEntries == 0) {
sbcDrawNineGridCacheInfo.supportLevel = TS_DRAW_NINEGRID_DEFAULT;
}
TRC_NRM((TB, "[%ld]: Negotiated drawninegrid level: %ld", locPersonID,
sbcDrawNineGridCacheInfo.supportLevel));
DC_END_FN();
}
/****************************************************************************/
// FUNCTION: SBCRedetermineDrawNineGridSupport
//
// Enumerates all the people in the share and redetermines the drawninegrid
// support level depending on their and the local receive capabilities.
//
// RETURNS: the share drawninegrid support level
/****************************************************************************/
BOOLEAN RDPCALL SHCLASS SBCRedetermineDrawNineGridSupport(void)
{
unsigned i;
BOOLEAN rc = TRUE;
DC_BEGIN_FN("SBCRedetermineDrawNineGridSupport");
/************************************************************************/
// Start by setting drawninegrid support to the highest supported
/************************************************************************/
sbcDrawNineGridCacheInfo.supportLevel = TS_DRAW_NINEGRID_SUPPORTED_REV2;
sbcDrawNineGridCacheInfo.cacheSize = TS_DRAW_NINEGRID_CACHE_SIZE_DEFAULT;
sbcDrawNineGridCacheInfo.cacheEntries = TS_DRAW_NINEGRID_CACHE_ENTRIES_DEFAULT;
TRC_NRM((TB, "Initial DrawNineGrid support level: %ld",
sbcDrawNineGridCacheInfo.supportLevel));
/************************************************************************/
// Enumerate all the DrawNineGrid support capabilities of all the parties.
// drawninegrid support is set to the lowest common denominator.
/************************************************************************/
CPC_EnumerateCapabilities(TS_CAPSETTYPE_DRAWNINEGRIDCACHE, NULL,
SBCEnumDrawNineGridCaps);
if (sbcDrawNineGridCacheInfo.supportLevel == TS_DRAW_NINEGRID_DEFAULT)
rc = FALSE;
TRC_NRM((TB, "Enumerated drawninegrid support level: %ld",
sbcDrawNineGridCacheInfo.supportLevel));
DC_END_FN();
return rc;
}
#endif
#ifdef DRAW_GDIPLUS
/****************************************************************************/
// FUNCTION: SBCEnumDrawGdiplusCaps
//
// Function passed to CPC_EnumerateCapabilities. It will be called with a
// capability structure for each person in the share corresponding to the
// TS_DRAW_GDIPLUS_CAPABILITYSET capability structure.
//
// PARAMETERS:
//
// personID - ID of person with these capabilities.
//
// pProtCaps - pointer to capabilities structure for this person. This
// pointer is only valid within the call to this function.
/****************************************************************************/
void RDPCALL SHCLASS SBCEnumDrawGdiplusCaps(
LOCALPERSONID locPersonID,
UINT_PTR UserData,
PTS_CAPABILITYHEADER pCapabilities)
{
PTS_DRAW_GDIPLUS_CAPABILITYSET pDrawGdiplusCaps;
DC_BEGIN_FN("SBCEnumDrawGdiplusCaps");
DC_IGNORE_PARAMETER(UserData);
pDrawGdiplusCaps = (PTS_DRAW_GDIPLUS_CAPABILITYSET)pCapabilities;
/************************************************************************/
// Set the drawgdiplus support level to the lowest common denominator of all
// the parties in the call.
/************************************************************************/
if (pCapabilities->lengthCapability >= sizeof(TS_DRAW_GDIPLUS_CAPABILITYSET)) {
pDrawGdiplusCaps = (PTS_DRAW_GDIPLUS_CAPABILITYSET)pCapabilities;
TRC_NRM((TB, "DrawGdiplus Support Level[ID=%u]: %ld", locPersonID,
pDrawGdiplusCaps->drawGdiplusSupportLevel));
TRC_NRM((TB, "Gdip version is [ID=%u]: 0x%x, 0x%x", locPersonID,
pDrawGdiplusCaps->GdipVersion, sbcDrawGdiplusInfo.GdipVersion));
sbcDrawGdiplusInfo.supportLevel = min(sbcDrawGdiplusInfo.supportLevel,
pDrawGdiplusCaps->drawGdiplusSupportLevel);
sbcDrawGdiplusInfo.GdipVersion = min(sbcDrawGdiplusInfo.GdipVersion,
pDrawGdiplusCaps->GdipVersion);
sbcDrawGdiplusInfo.GdipCacheLevel = min(sbcDrawGdiplusInfo.GdipCacheLevel,
pDrawGdiplusCaps->drawGdiplusCacheLevel);
sbcDrawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries = min(sbcDrawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries,
pDrawGdiplusCaps->GdipCacheEntries.GdipGraphicsCacheEntries);
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries = min(sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries,
pDrawGdiplusCaps->GdipCacheEntries.GdipObjectBrushCacheEntries);
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries = min(sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries,
pDrawGdiplusCaps->GdipCacheEntries.GdipObjectPenCacheEntries);
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries = min(sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries,
pDrawGdiplusCaps->GdipCacheEntries.GdipObjectImageCacheEntries);
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries = min(sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries,
pDrawGdiplusCaps->GdipCacheEntries.GdipObjectImageAttributesCacheEntries);
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipGraphicsCacheChunkSize = min(sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipGraphicsCacheChunkSize,
pDrawGdiplusCaps->GdipCacheChunkSize.GdipGraphicsCacheChunkSize);
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectBrushCacheChunkSize = min(sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectBrushCacheChunkSize,
pDrawGdiplusCaps->GdipCacheChunkSize.GdipObjectBrushCacheChunkSize);
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectPenCacheChunkSize = min(sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectPenCacheChunkSize,
pDrawGdiplusCaps->GdipCacheChunkSize.GdipObjectPenCacheChunkSize);
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize = min(sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize,
pDrawGdiplusCaps->GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize);
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheChunkSize = min(sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheChunkSize,
pDrawGdiplusCaps->GdipImageCacheProperties.GdipObjectImageCacheChunkSize);
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheTotalSize = min(sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheTotalSize,
pDrawGdiplusCaps->GdipImageCacheProperties.GdipObjectImageCacheTotalSize);
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheMaxSize = min(sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheMaxSize,
pDrawGdiplusCaps->GdipImageCacheProperties.GdipObjectImageCacheMaxSize);
}
else {
sbcDrawGdiplusInfo.supportLevel = TS_DRAW_GDIPLUS_DEFAULT;
sbcDrawGdiplusInfo.GdipVersion = TS_GDIPVERSION_DEFAULT;
TRC_ERR((TB, "[%ld]: DrawGdiplus Support Level Unknown", locPersonID));
}
TRC_NRM((TB, "[%ld]: Negotiated drawgdiplus level: %ld", locPersonID,
sbcDrawGdiplusInfo.supportLevel));
DC_END_FN();
}
BOOLEAN RDPCALL SHCLASS SBCRedetermineDrawGdiplusSupport(void)
{
BOOLEAN rc = TRUE;
DC_BEGIN_FN("SBCRedetermineDrawGdiplusSupport");
/************************************************************************/
// Start by setting drawgdiplus support to the highest supported
/************************************************************************/
sbcDrawGdiplusInfo.supportLevel = TS_DRAW_GDIPLUS_SUPPORTED;
sbcDrawGdiplusInfo.GdipVersion = 0xFFFFFFFF;
sbcDrawGdiplusInfo.GdipCacheLevel = TS_DRAW_GDIPLUS_CACHE_LEVEL_ONE;
sbcDrawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries = TS_GDIP_GRAPHICS_CACHE_ENTRIES_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries = TS_GDIP_BRUSH_CACHE_ENTRIES_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries = TS_GDIP_PEN_CACHE_ENTRIES_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries = TS_GDIP_IMAGE_CACHE_ENTRIES_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries = TS_GDIP_IMAGEATTRIBUTES_CACHE_ENTRIES_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipGraphicsCacheChunkSize = TS_GDIP_GRAPHICS_CACHE_CHUNK_SIZE_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectBrushCacheChunkSize = TS_GDIP_BRUSH_CACHE_CHUNK_SIZE_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectPenCacheChunkSize = TS_GDIP_PEN_CACHE_CHUNK_SIZE_DEFAULT;
sbcDrawGdiplusInfo.GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize = TS_GDIP_IMAGEATTRIBUTES_CACHE_CHUNK_SIZE_DEFAULT;
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheChunkSize = TS_GDIP_IMAGE_CACHE_CHUNK_SIZE_DEFAULT;
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheTotalSize = TS_GDIP_IMAGE_CACHE_TOTAL_SIZE_DEFAULT;
sbcDrawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheMaxSize = TS_GDIP_IMAGE_CACHE_MAX_SIZE_DEFAULT;
CPC_EnumerateCapabilities(TS_CAPSETTYPE_DRAWGDIPLUS, NULL,
SBCEnumDrawGdiplusCaps);
if (sbcDrawGdiplusInfo.supportLevel == TS_DRAW_GDIPLUS_DEFAULT)
rc = FALSE;
TRC_NRM((TB, "Enumerated drawgdiplus support level: %ld",
sbcDrawGdiplusInfo.supportLevel));
DC_END_FN();
return rc;
}
#endif // DRAW_GDIPLUS
/****************************************************************************/
// SBCRedetermineGlyphCacheSize: Enumerates all the people in the share and
// redetermines the size of the glyph cache depending on their and the local
// receive capabilities.
//
// Returns: TRUE if glyph caching should be enabled, FALSE otherwise.
/****************************************************************************/
BOOLEAN RDPCALL SHCLASS SBCRedetermineGlyphCacheSize(void)
{
BOOLEAN rc = TRUE;
unsigned i;
DC_BEGIN_FN("SBCRedetermineGlyphCacheSize");
/************************************************************************/
/* Enumerate all the glyph cache receive capabilities of all the */
/* parties. The usable size of the send glyph cache is the minimum of */
/* all the remote receive caches and the local send cache size. */
/************************************************************************/
/************************************************************************/
/* Start by setting the size of the local send bitmap cache to the */
/* local default values. We DO need to do this, or we end up */
/* negotiating our glyph cache down to zero! */
/************************************************************************/
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++) {
sbcGlyphCacheSizes[i].cEntries = sbcMaxGlyphCacheSizes[i].cEntries;
sbcGlyphCacheSizes[i].cbCellSize = sbcMaxGlyphCacheSizes[i].cbCellSize;
}
sbcFragCacheSizes[0].cEntries = sbcMaxFragCacheSizes[0].cEntries;
sbcFragCacheSizes[0].cbCellSize = sbcMaxFragCacheSizes[0].cbCellSize;
/************************************************************************/
/* Now enumerate all the parties in the share and set our send glyph */
/* sizes appropriately. */
/************************************************************************/
CPC_EnumerateCapabilities(TS_CAPSETTYPE_GLYPHCACHE, NULL,
SBCEnumGlyphCacheCaps);
if (sbcGlyphSupportLevel == CAPS_GLYPH_SUPPORT_NONE)
rc = FALSE;
DC_END_FN();
return rc;
}
/****************************************************************************/
// SBCEnumGlyphCacheCaps: Function passed to CPC_EnumerateCapabilities. It
// will be called with a capability structure for each person in the share
// corresponding to the TS_CAPSETTYPE_BITMAPCACHE capability structure.
//
// Params:
// personID - ID of person with these capabilities.
// pProtCaps - pointer to capabilities structure for this person. This
// pointer is only valid within the call to this function.
/****************************************************************************/
void CALLBACK SHCLASS SBCEnumGlyphCacheCaps(
LOCALPERSONID locPersonID,
UINT_PTR UserData,
PTS_CAPABILITYHEADER pCapabilities)
{
unsigned i;
PTS_GLYPHCACHE_CAPABILITYSET pGlyphCacheCaps;
DC_BEGIN_FN("SBCEnumGlyphCacheCaps");
DC_IGNORE_PARAMETER(UserData);
if (pCapabilities->lengthCapability >=
sizeof(TS_GLYPHCACHE_CAPABILITYSET)) {
pGlyphCacheCaps = (PTS_GLYPHCACHE_CAPABILITYSET)pCapabilities;
for (i = 0; i<SBC_NUM_GLYPH_CACHES; i++) {
TRC_NRM((TB, "[%u]: Cache %d: MaximumCellSize(%u) Entries(%u)",
locPersonID,
i,
pGlyphCacheCaps->GlyphCache[i].CacheMaximumCellSize,
pGlyphCacheCaps->GlyphCache[i].CacheEntries));
/************************************************************************/
/* Set the size of the glyph cache to the minimum of its current size */
/* and this party's receive glyph cache size. */
/************************************************************************/
sbcGlyphCacheSizes[i].cEntries =
min(sbcGlyphCacheSizes[i].cEntries,
pGlyphCacheCaps->GlyphCache[i].CacheEntries);
sbcGlyphCacheSizes[i].cbCellSize =
min(sbcGlyphCacheSizes[i].cbCellSize,
pGlyphCacheCaps->GlyphCache[i].CacheMaximumCellSize);
TRC_NRM((TB,
"[%u]: Negotiated glyph cache %u size: cEntries(%u) cbCellSize(%u)",
locPersonID,
i,
sbcGlyphCacheSizes[i].cEntries,
sbcGlyphCacheSizes[i].cbCellSize));
}
/************************************************************************/
/* Set the size of the glyph cache to the minimum of its current size */
/* and this party's receive glyph cache size. */
/************************************************************************/
sbcFragCacheSizes[0].cEntries =
min(sbcFragCacheSizes[0].cEntries,
pGlyphCacheCaps->FragCache.CacheEntries);
sbcFragCacheSizes[0].cbCellSize =
min(sbcFragCacheSizes[0].cbCellSize,
pGlyphCacheCaps->FragCache.CacheMaximumCellSize);
/************************************************************************/
/* Glyph support level */
/************************************************************************/
sbcGlyphSupportLevel = min(sbcGlyphSupportLevel,
pGlyphCacheCaps->GlyphSupportLevel);
}
else {
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++) {
sbcGlyphCacheSizes[i].cEntries = 0;
sbcGlyphCacheSizes[i].cbCellSize = 0;
}
sbcFragCacheSizes[0].cEntries = 0;
sbcFragCacheSizes[0].cbCellSize = 0;
sbcGlyphSupportLevel = CAPS_GLYPH_SUPPORT_NONE;
}
DC_END_FN();
}