451 lines
13 KiB
C++
451 lines
13 KiB
C++
#include "precomp.h"
|
|
|
|
|
|
//
|
|
// SSI.CPP
|
|
// Save Screenbits Interceptor
|
|
//
|
|
// Copyright(c) Microsoft 1997-
|
|
//
|
|
|
|
#define MLZ_FILE_ZONE ZONE_CORE
|
|
|
|
|
|
|
|
|
|
//
|
|
// SSI_HostStarting()
|
|
//
|
|
// Called when we start to host, figures out the max save bitmap bits size
|
|
// etc.
|
|
//
|
|
BOOL ASHost::SSI_HostStarting(void)
|
|
{
|
|
DebugEntry(ASHost::SSI_HostStarting);
|
|
|
|
m_pShare->SSI_RecalcCaps(TRUE);
|
|
|
|
DebugExitBOOL(ASHost::SSI_HostStarting, TRUE);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SSI_ViewStarted()
|
|
//
|
|
// Called when someone we are viewing has started to host. Creates save bits
|
|
// bitmap for them.
|
|
//
|
|
BOOL ASShare::SSI_ViewStarting(ASPerson * pasPerson)
|
|
{
|
|
BOOL rc = FALSE;
|
|
HDC hdcScreen = NULL;
|
|
|
|
DebugEntry(ASShare::SSI_ViewStarting);
|
|
|
|
ValidateView(pasPerson);
|
|
|
|
//
|
|
// ASSERT that this persons' variables are clear.
|
|
//
|
|
ASSERT(pasPerson->m_pView->m_ssiBitmapHeight == 0);
|
|
ASSERT(pasPerson->m_pView->m_ssiBitmap == NULL);
|
|
ASSERT(pasPerson->m_pView->m_ssiOldBitmap == NULL);
|
|
|
|
//
|
|
// Does this person support savebits?
|
|
//
|
|
if (!pasPerson->cpcCaps.orders.capsSendSaveBitmapSize)
|
|
{
|
|
// No receive SSI capability, bail out now.
|
|
rc = TRUE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Store the height of this host's bitmap.
|
|
//
|
|
pasPerson->m_pView->m_ssiBitmapHeight = (int)
|
|
(pasPerson->cpcCaps.orders.capsSendSaveBitmapSize / TSHR_SSI_BITMAP_WIDTH);
|
|
|
|
//
|
|
// If the calculated bitmap size is not exactly divisible by the bitmap
|
|
// width increase the bitmap height to fit in the partial row.
|
|
//
|
|
if (pasPerson->cpcCaps.orders.capsSendSaveBitmapSize % TSHR_SSI_BITMAP_WIDTH)
|
|
{
|
|
pasPerson->m_pView->m_ssiBitmapHeight += pasPerson->cpcCaps.orders.capsSaveBitmapYGranularity;
|
|
}
|
|
|
|
TRACE_OUT(("Person [%d] SSI Bitmap height %d",
|
|
pasPerson->mcsID,
|
|
pasPerson->m_pView->m_ssiBitmapHeight));
|
|
|
|
//
|
|
// Create this host's save screen bitmap.
|
|
//
|
|
hdcScreen = GetDC(NULL);
|
|
if (hdcScreen == NULL)
|
|
{
|
|
ERROR_OUT(( "Failed to get screen surface"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Create the save screen bitmap DC.
|
|
//
|
|
ASSERT(pasPerson->m_pView->m_ssiDC == NULL);
|
|
pasPerson->m_pView->m_ssiDC = CreateCompatibleDC(hdcScreen);
|
|
if (!pasPerson->m_pView->m_ssiDC)
|
|
{
|
|
ERROR_OUT(("Failed to create SSI DC"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Create the save screen bitmap.
|
|
//
|
|
ASSERT(pasPerson->m_pView->m_ssiBitmap == NULL);
|
|
pasPerson->m_pView->m_ssiBitmap = CreateCompatibleBitmap(hdcScreen,
|
|
TSHR_SSI_BITMAP_WIDTH, pasPerson->m_pView->m_ssiBitmapHeight);
|
|
if (!pasPerson->m_pView->m_ssiBitmap)
|
|
{
|
|
ERROR_OUT(("SSI_ViewStarting: can't create bitmap for person %x",
|
|
pasPerson->mcsID));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Select the save screen bitmap into the DC
|
|
//
|
|
ASSERT(pasPerson->m_pView->m_ssiOldBitmap == NULL);
|
|
pasPerson->m_pView->m_ssiOldBitmap = SelectBitmap(pasPerson->m_pView->m_ssiDC,
|
|
pasPerson->m_pView->m_ssiBitmap);
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
if (hdcScreen != NULL)
|
|
{
|
|
ReleaseDC(NULL, hdcScreen);
|
|
}
|
|
|
|
DebugExitBOOL(ASShare::SSI_ViewStarting, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SSI_ViewEnded()
|
|
//
|
|
// Called when someone we are viewing has stopped hosting, so we can clean
|
|
// up our view data for them.
|
|
//
|
|
void ASShare::SSI_ViewEnded(ASPerson * pasPerson)
|
|
{
|
|
DebugEntry(ASShare::SSI_ViewEnded);
|
|
|
|
ValidateView(pasPerson);
|
|
|
|
//
|
|
// Deselect the save screen bitmap if there is one
|
|
//
|
|
if (pasPerson->m_pView->m_ssiOldBitmap != NULL)
|
|
{
|
|
SelectBitmap(pasPerson->m_pView->m_ssiDC, pasPerson->m_pView->m_ssiOldBitmap);
|
|
pasPerson->m_pView->m_ssiOldBitmap = NULL;
|
|
}
|
|
|
|
//
|
|
// Delete the save screen bitmap
|
|
//
|
|
if (pasPerson->m_pView->m_ssiBitmap != NULL)
|
|
{
|
|
DeleteBitmap(pasPerson->m_pView->m_ssiBitmap);
|
|
pasPerson->m_pView->m_ssiBitmap = NULL;
|
|
}
|
|
|
|
//
|
|
// Delete the save screen DC
|
|
//
|
|
if (pasPerson->m_pView->m_ssiDC != NULL)
|
|
{
|
|
DeleteDC(pasPerson->m_pView->m_ssiDC);
|
|
pasPerson->m_pView->m_ssiDC = NULL;
|
|
}
|
|
|
|
DebugExitVOID(ASShare::SSI_ViewEnded);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SSI_SyncOutgoing()
|
|
// Called when NEW (3.0) dude starts to share, a share is created, or
|
|
// someone new joins the share.
|
|
// Resets save state for OUTGOING save/restore orders.
|
|
//
|
|
void ASHost::SSI_SyncOutgoing(void)
|
|
{
|
|
OSI_ESCAPE_HEADER request;
|
|
|
|
DebugEntry(ASHost::SSI_SyncOutgoing);
|
|
|
|
//
|
|
// Discard any saved bitmaps. This ensures that the subsequent
|
|
// datastream will not refer to any previously sent data.
|
|
//
|
|
//
|
|
// Make sure the display driver resets the save level. Note we don't
|
|
// really care what happens in the display driver, so don't bother with
|
|
// a special request block - use a standard request header.
|
|
//
|
|
OSI_FunctionRequest(SSI_ESC_RESET_LEVEL, &request, sizeof(request));
|
|
|
|
DebugExitVOID(ASHost::SSI_SyncOutgoing);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// FUNCTION: SSI_SaveBitmap
|
|
//
|
|
// DESCRIPTION:
|
|
// Replays a SaveBitmap order by saving or restoring a specified area of
|
|
// the user's desktop bitmap.
|
|
//
|
|
//
|
|
void ASShare::SSI_SaveBitmap
|
|
(
|
|
ASPerson * pasPerson,
|
|
LPSAVEBITMAP_ORDER pSaveBitmap
|
|
)
|
|
{
|
|
RECT screenBitmapRect;
|
|
RECT saveBitmapRect;
|
|
int xSaveBitmap;
|
|
int ySaveBitmap;
|
|
int xScreenBitmap;
|
|
int yScreenBitmap;
|
|
int cxTile;
|
|
int cyTile;
|
|
|
|
DebugEntry(ASShare::SSI_SaveBitmap);
|
|
|
|
ValidateView(pasPerson);
|
|
|
|
if ((pSaveBitmap->Operation != SV_SAVEBITS) &&
|
|
(pSaveBitmap->Operation != SV_RESTOREBITS))
|
|
{
|
|
ERROR_OUT(("SSI_SaveBitmap: unrecognized SV_ value %d",
|
|
pSaveBitmap->Operation));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Calculate the (x,y) start position from the pel start position
|
|
// given in the order.
|
|
//
|
|
ySaveBitmap = (pSaveBitmap->SavedBitmapPosition /
|
|
(TSHR_SSI_BITMAP_WIDTH *
|
|
(UINT)pasPerson->cpcCaps.orders.capsSaveBitmapYGranularity)) *
|
|
pasPerson->cpcCaps.orders.capsSaveBitmapYGranularity;
|
|
|
|
xSaveBitmap = (pSaveBitmap->SavedBitmapPosition -
|
|
(ySaveBitmap *
|
|
(UINT)TSHR_SSI_BITMAP_WIDTH)) /
|
|
pasPerson->cpcCaps.orders.capsSaveBitmapYGranularity;
|
|
|
|
|
|
screenBitmapRect.left = pSaveBitmap->nLeftRect
|
|
- pasPerson->m_pView->m_dsScreenOrigin.x;
|
|
screenBitmapRect.top = pSaveBitmap->nTopRect
|
|
- pasPerson->m_pView->m_dsScreenOrigin.y;
|
|
screenBitmapRect.right = pSaveBitmap->nRightRect + 1
|
|
- pasPerson->m_pView->m_dsScreenOrigin.x;
|
|
screenBitmapRect.bottom = pSaveBitmap->nBottomRect + 1
|
|
- pasPerson->m_pView->m_dsScreenOrigin.y;
|
|
saveBitmapRect.left = 0;
|
|
saveBitmapRect.top = 0;
|
|
saveBitmapRect.right = TSHR_SSI_BITMAP_WIDTH;
|
|
saveBitmapRect.bottom = pasPerson->m_pView->m_ssiBitmapHeight;
|
|
|
|
//
|
|
// Start tiling in the top left corner of the Screen Bitmap rectangle.
|
|
//
|
|
xScreenBitmap = screenBitmapRect.left;
|
|
yScreenBitmap = screenBitmapRect.top;
|
|
|
|
//
|
|
// The height of the tile is the vertical granularity (or less - if
|
|
// the Screen Bitmap rect is thinner than the granularity).
|
|
//
|
|
cyTile = min(screenBitmapRect.bottom - yScreenBitmap,
|
|
(int)pasPerson->cpcCaps.orders.capsSaveBitmapYGranularity );
|
|
|
|
//
|
|
// Repeat while there are more tiles in the Screen Bitmap rect to
|
|
// process.
|
|
//
|
|
while (yScreenBitmap < screenBitmapRect.bottom)
|
|
{
|
|
//
|
|
// The width of the tile is the minimum of:
|
|
//
|
|
// - the width of the remaining rectangle in the current strip of
|
|
// the Screen Bitmap rectangle
|
|
//
|
|
// - the width of the remaining empty space in the current strip of
|
|
// the Save Bitmap
|
|
//
|
|
//
|
|
cxTile = min( saveBitmapRect.right - xSaveBitmap,
|
|
screenBitmapRect.right - xScreenBitmap );
|
|
|
|
TRACE_OUT(( "screen(%d,%d) save(%d,%d) cx(%d) cy(%d)",
|
|
xScreenBitmap,
|
|
yScreenBitmap,
|
|
xSaveBitmap,
|
|
ySaveBitmap,
|
|
cxTile,
|
|
cyTile ));
|
|
|
|
//
|
|
// Save or Restore this tile
|
|
//
|
|
if (pSaveBitmap->Operation == SV_SAVEBITS)
|
|
{
|
|
//
|
|
// Save user's desktop area to SSI bitmap
|
|
//
|
|
BitBlt(pasPerson->m_pView->m_ssiDC,
|
|
xSaveBitmap, ySaveBitmap, cxTile, cyTile,
|
|
pasPerson->m_pView->m_usrDC,
|
|
xScreenBitmap, yScreenBitmap, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Restore user's desktop area from SSI bitmap
|
|
//
|
|
BitBlt(pasPerson->m_pView->m_usrDC,
|
|
xScreenBitmap, yScreenBitmap, cxTile, cyTile,
|
|
pasPerson->m_pView->m_ssiDC,
|
|
xSaveBitmap, ySaveBitmap, SRCCOPY);
|
|
}
|
|
|
|
//
|
|
// Move to the next tile in the Screen Bitmap rectangle.
|
|
//
|
|
xScreenBitmap += cxTile;
|
|
if (xScreenBitmap >= screenBitmapRect.right)
|
|
{
|
|
xScreenBitmap = screenBitmapRect.left;
|
|
yScreenBitmap += cyTile;
|
|
cyTile = min( screenBitmapRect.bottom - yScreenBitmap,
|
|
(int)pasPerson->cpcCaps.orders.capsSaveBitmapYGranularity );
|
|
}
|
|
|
|
//
|
|
// Move to the next free space in the Save Bitmap.
|
|
//
|
|
xSaveBitmap += ROUNDUP(cxTile, pasPerson->cpcCaps.orders.capsSaveBitmapXGranularity);
|
|
if (xSaveBitmap >= saveBitmapRect.right)
|
|
{
|
|
xSaveBitmap = saveBitmapRect.left;
|
|
ySaveBitmap += ROUNDUP(cyTile, pasPerson->cpcCaps.orders.capsSaveBitmapYGranularity);
|
|
}
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(ASShare::SSI_SaveBitmap);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SSI_RecalcCaps()
|
|
//
|
|
// Called when we are hosting and someone joins/leaves the share.
|
|
//
|
|
// When 2.x COMPAT IS GONE, THIS IS OBSOLETE
|
|
//
|
|
void ASShare::SSI_RecalcCaps(BOOL fJoiner)
|
|
{
|
|
ASPerson * pasT;
|
|
SSI_NEW_CAPABILITIES newCapabilities;
|
|
|
|
DebugEntry(ASShare::SSI_RecalcCaps);
|
|
|
|
if (!m_pHost)
|
|
{
|
|
//
|
|
// Nothing to do. Note that we recalc when someone joins AND
|
|
// when someone leaves, like SBC.
|
|
//
|
|
DC_QUIT;
|
|
}
|
|
|
|
ValidatePerson(m_pasLocal);
|
|
|
|
//
|
|
// Enumerate all the save screen bitmap receive capabilities of the
|
|
// parties in the share. The usable size of the send save screen
|
|
// bitmap is then the minimum of all the remote receive sizes and the
|
|
// local send size.
|
|
//
|
|
|
|
//
|
|
// Copy the locally registered send save screen bitmap size capability
|
|
// to our global variable used to communicate with the enumeration
|
|
// function SSIEnumBitmapCacheCaps().
|
|
//
|
|
m_pHost->m_ssiSaveBitmapSize = m_pasLocal->cpcCaps.orders.capsReceiveSaveBitmapSize;
|
|
|
|
//
|
|
// Now enumerate all the parties in the share and set our send bitmap
|
|
// size appropriately.
|
|
//
|
|
if (m_scShareVersion < CAPS_VERSION_30)
|
|
{
|
|
TRACE_OUT(("In share with 2.x nodes; must recalc SSI caps"));
|
|
|
|
for (pasT = m_pasLocal->pasNext; pasT != NULL; pasT = pasT->pasNext)
|
|
{
|
|
//
|
|
// Set the size of the local send save screen bitmap to the minimum of
|
|
// its current size and this party's receive save screen bitmap size.
|
|
//
|
|
m_pHost->m_ssiSaveBitmapSize = min(m_pHost->m_ssiSaveBitmapSize,
|
|
pasT->cpcCaps.orders.capsReceiveSaveBitmapSize);
|
|
}
|
|
|
|
TRACE_OUT(("Recalced SSI caps: SS bitmap size 0x%08x",
|
|
m_pHost->m_ssiSaveBitmapSize));
|
|
}
|
|
|
|
//
|
|
// Set up the new capabilities structure...
|
|
//
|
|
newCapabilities.sendSaveBitmapSize = m_pHost->m_ssiSaveBitmapSize;
|
|
|
|
newCapabilities.xGranularity = TSHR_SSI_BITMAP_X_GRANULARITY;
|
|
|
|
newCapabilities.yGranularity = TSHR_SSI_BITMAP_Y_GRANULARITY;
|
|
|
|
//
|
|
// ... and pass it through to the driver.
|
|
//
|
|
if (!OSI_FunctionRequest(SSI_ESC_NEW_CAPABILITIES, (LPOSI_ESCAPE_HEADER)&newCapabilities,
|
|
sizeof(newCapabilities)))
|
|
{
|
|
ERROR_OUT(("SSI_ESC_NEW_CAPABILITIES failed"));
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(ASHost::SSI_RecalcCaps);
|
|
}
|