#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); }