|
|
#include "precomp.h"
//
// HET.C
// Hosted Entity Tracker, NT Display Driver version
//
// Copyright(c)Microsoft 1997-
//
#include <limits.h>
//
// HET_DDTerm()
//
void HET_DDTerm(void) { LPHET_WINDOW_MEMORY pMem;
DebugEntry(HET_DDTerm);
//
// Clean up any window/graphics tracking stuff
//
g_hetDDDesktopIsShared = FALSE; HETDDViewing(NULL, FALSE); HETDDUnshareAll();
//
// Loop through the memory list blocks, freeing each. Then clear
// the Window and Free lists.
//
while (pMem = COM_BasedListFirst(&g_hetMemoryList, FIELD_OFFSET(HET_WINDOW_MEMORY, chain))) { TRACE_OUT(("HET_DDTerm: Freeing memory block %lx", pMem));
COM_BasedListRemove(&(pMem->chain)); EngFreeMem(pMem); }
//
// Clear the window linked lists since they contain elements in
// the now free memory block.
//
COM_BasedListInit(&g_hetFreeWndList); COM_BasedListInit(&g_hetWindowList);
DebugExitVOID(HET_DDTerm); }
//
// HET_DDProcessRequest - see host.h
//
ULONG HET_DDProcessRequest(SURFOBJ *pso, UINT cjIn, void * pvIn, UINT cjOut, void * pvOut) { ULONG rc = TRUE; LPOSI_ESCAPE_HEADER pHeader;
DebugEntry(HET_DDProcessRequest);
pHeader = pvIn; TRACE_OUT(( "Request %#x", pHeader->escapeFn)); switch (pHeader->escapeFn) { case HET_ESC_SHARE_WINDOW: { if ((cjIn != sizeof(HET_SHARE_WINDOW)) || (cjOut != sizeof(HET_SHARE_WINDOW))) { ERROR_OUT(("HET_DDProcessRequest: Invalid sizes %d, %d for HET_ESC_SHARE_WINDOW", cjIn, cjOut)); rc = FALSE; DC_QUIT; }
((LPHET_SHARE_WINDOW)pvOut)->result = HETDDShareWindow(pso, (LPHET_SHARE_WINDOW)pvIn); } break;
case HET_ESC_UNSHARE_WINDOW: { if ((cjIn != sizeof(HET_UNSHARE_WINDOW)) || (cjOut != sizeof(HET_UNSHARE_WINDOW))) { ERROR_OUT(("HET_DDProcessRequest: Invalid sizes %d, %d for HET_ESC_UNSHARE_WINDOW", cjIn, cjOut)); rc = FALSE; DC_QUIT; }
HETDDUnshareWindow((LPHET_UNSHARE_WINDOW)pvIn); } break;
case HET_ESC_UNSHARE_ALL: { if ((cjIn != sizeof(HET_UNSHARE_ALL)) || (cjOut != sizeof(HET_UNSHARE_ALL))) { ERROR_OUT(("HET_DDProcessRequest: Invalid sizes %d, %d for HET_ESC_UNSHARE_ALL", cjIn, cjOut)); rc = FALSE; DC_QUIT; }
HETDDUnshareAll(); } break;
case HET_ESC_SHARE_DESKTOP: { if ((cjIn != sizeof(HET_SHARE_DESKTOP)) || (cjOut != sizeof(HET_SHARE_DESKTOP))) { ERROR_OUT(("HET_DDProcessRequest: Invalid sizes %d, %d for HET_ESC_SHARE_DESKTOP", cjIn, cjOut)); rc = FALSE; DC_QUIT; }
g_hetDDDesktopIsShared = TRUE; } break;
case HET_ESC_UNSHARE_DESKTOP: { if ((cjIn != sizeof(HET_UNSHARE_DESKTOP)) || (cjOut != sizeof(HET_UNSHARE_DESKTOP))) { ERROR_OUT(("HET_DDProcessRequest: Invalid sizes %d, %d for HET_ESC_UNSHARE_DESKTOP", cjIn, cjOut)); rc = FALSE; DC_QUIT; }
g_hetDDDesktopIsShared = FALSE; HETDDViewing(NULL, FALSE); } break;
case HET_ESC_VIEWER: { //
// We may turn OFF viewing but keep stuff shared and the windows
// tracked -- hosting a meeting and sharing something, for
// example.
//
if ((cjIn != sizeof(HET_VIEWER)) || (cjOut != sizeof(HET_VIEWER))) { ERROR_OUT(("HET_DDProcessRequest: Invalid sizes %d, %d for HET_ESC_VIEWER", cjIn, cjOut)); rc = FALSE; DC_QUIT; }
HETDDViewing(pso, (((LPHET_VIEWER)pvIn)->viewersPresent != 0)); break; }
default: { ERROR_OUT(( "Unknown request type %#x", pHeader->escapeFn)); rc = FALSE; } break; }
DC_EXIT_POINT: DebugExitDWORD(HET_DDProcessRequest, rc); return(rc); }
//
// HET_DDOutputIsHosted - see host.h
//
BOOL HET_DDOutputIsHosted(POINT pt) { BOOL rc = FALSE; UINT j; LPHET_WINDOW_STRUCT pWnd;
DebugEntry(HET_DDOutputIsHosted);
//
// Now check to see if the desktop is shared - if it is then simply
// return TRUE.
//
if (g_hetDDDesktopIsShared) { rc = TRUE; DC_QUIT; }
//
// Search through the window list
//
pWnd = COM_BasedListFirst(&g_hetWindowList, FIELD_OFFSET(HET_WINDOW_STRUCT, chain)); while (pWnd != NULL) { //
// Search each enumerated rectangle
//
TRACE_OUT(( "Window %#x has %u rectangle(s)", pWnd, pWnd->rects.c)); for (j = 0; j < pWnd->rects.c; j++) { //
// See whether the point passed in is within this rectangle.
// Note that at this point we are dealing with exclusive
// co-ordinates.
//
if ((pt.x >= pWnd->rects.arcl[j].left) && (pt.x < pWnd->rects.arcl[j].right) && (pt.y >= pWnd->rects.arcl[j].top) && (pt.y < pWnd->rects.arcl[j].bottom)) { TRACE_OUT(( "Pt {%d, %d}, in win %#x rect %u {%ld, %ld, %ld, %ld}", pt.x, pt.y, pWnd->hwnd, j, pWnd->rects.arcl[j].left, pWnd->rects.arcl[j].right, pWnd->rects.arcl[j].top, pWnd->rects.arcl[j].bottom ));
//
// Found it! Re-order the list, most recently used first
//
COM_BasedListRemove(&(pWnd->chain)); COM_BasedListInsertAfter(&g_hetWindowList, &(pWnd->chain));
//
// Stop looking
//
rc = TRUE; DC_QUIT; }
TRACE_OUT(( "Pt not in win %#x rect %u {%ld, %ld, %ld, %ld}", pWnd->hwnd, j, pWnd->rects.arcl[j].left, pWnd->rects.arcl[j].right, pWnd->rects.arcl[j].top, pWnd->rects.arcl[j].bottom ));
} // for all rectangles
//
// Move on to next window
//
pWnd = COM_BasedListNext(&g_hetWindowList, pWnd, FIELD_OFFSET(HET_WINDOW_STRUCT, chain)); }
DC_EXIT_POINT: DebugExitBOOL(HET_DDOutputIsHosted, rc); return(rc); }
//
// HET_DDOutputRectIsHosted - see host.h
//
BOOL HET_DDOutputRectIsHosted(LPRECT pRect) { BOOL rc = FALSE; UINT j; LPHET_WINDOW_STRUCT pWnd; RECT rectIntersect;
DebugEntry(HET_DDOutputRectIsHosted);
//
// Now check to see if the desktop is shared - if it is then simply
// return TRUE.
//
if (g_hetDDDesktopIsShared) { rc = TRUE; DC_QUIT; }
//
// Search through the window list
//
pWnd = COM_BasedListFirst(&g_hetWindowList, FIELD_OFFSET(HET_WINDOW_STRUCT, chain)); while (pWnd != NULL) { //
// Search each enumerated rectangle
//
TRACE_OUT(( "Window %#x has %u rectangle(s)", pWnd, pWnd->rects.c)); for (j = 0; j < pWnd->rects.c; j++) { //
// See whether the rect passed in intersects this rectangle.
// Note that at this point we are dealing with exclusive
// co-ordinates.
//
rectIntersect.left = max( pRect->left, pWnd->rects.arcl[j].left ); rectIntersect.top = max( pRect->top, pWnd->rects.arcl[j].top ); rectIntersect.right = min( pRect->right, pWnd->rects.arcl[j].right ); rectIntersect.bottom = min( pRect->bottom, pWnd->rects.arcl[j].bottom );
//
// If the intersection rectangle is well-ordered and non-NULL
// then we have an intersection.
//
// The rects that we are dealing with are exclusive.
//
if ((rectIntersect.left < rectIntersect.right) && (rectIntersect.top < rectIntersect.bottom)) { TRACE_OUT(( "Rect {%d, %d, %d, %d} intersects win %#x rect %u {%ld, %ld, %ld, %ld}", pRect->left, pRect->top, pRect->right, pRect->bottom, pWnd, j, pWnd->rects.arcl[j].left, pWnd->rects.arcl[j].right, pWnd->rects.arcl[j].top, pWnd->rects.arcl[j].bottom ));
//
// Found it! Re-order the list, most recently used first
//
COM_BasedListRemove(&(pWnd->chain)); COM_BasedListInsertAfter(&g_hetWindowList, &(pWnd->chain));
//
// Stop looking
//
rc = TRUE; DC_QUIT; }
TRACE_OUT(( "Rect not in win %#x rect %u {%ld, %ld, %ld, %ld}", pWnd, j, pWnd->rects.arcl[j].left, pWnd->rects.arcl[j].right, pWnd->rects.arcl[j].top, pWnd->rects.arcl[j].bottom ));
} // for all rectangles
//
// Move on to next window
//
pWnd = COM_BasedListNext(&g_hetWindowList, pWnd, FIELD_OFFSET(HET_WINDOW_STRUCT, chain)); }
DC_EXIT_POINT: DebugExitBOOL(HET_DDOutputRectIsHosted, rc); return(rc); }
//
//
// Name: HETDDVisRgnCallback
//
// Description: WNDOBJ Callback
//
// Params: pWo - pointer to the WNDOBJ which has changed
// fl - flags (se NT DDK documentation)
//
// Returns: none
//
// Operation:
//
//
VOID CALLBACK HETDDVisRgnCallback(PWNDOBJ pWo, FLONG fl) { ULONG count; int size; LPHET_WINDOW_STRUCT pWnd; RECTL rectl; UINT i;
DebugEntry(HETDDVisRgnCallback);
//
// Some calls pass a NULL pWo - exit now in this case
//
if (pWo == NULL) { DC_QUIT; }
//
// Find the window structure for this window
//
pWnd = pWo->pvConsumer; if (pWnd == NULL) { ERROR_OUT(( "Wndobj %x (fl %x) has no window structure", pWo, fl)); DC_QUIT; }
//
// Check for window deletion
//
if (fl & WOC_DELETE) { TRACE_OUT(( "Wndobj %x (structure %x) deleted", pWo, pWo->pvConsumer));
// ASSERT the window is valid
ASSERT(pWnd->hwnd != NULL);
//
// Move the window from the active to the free list
//
COM_BasedListRemove(&(pWnd->chain)); COM_BasedListInsertAfter(&g_hetFreeWndList, &(pWnd->chain));
#ifdef DEBUG
// Check if this has reentrancy problems
pWnd->hwnd = NULL; #endif
//
// Do any processing if this is the last window to be unshared.
//
// If we are not keeping track of any windows, the first pointer in
// the list will point to itself, ie list head->next == 0
//
if (g_hetWindowList.next == 0) { HETDDViewing(NULL, FALSE); }
//
// Exit now
//
DC_QUIT; }
//
// If we get here, this callback must be for a new visible region on a
// tracked window.
//
//
// Start the enumeration. This function is supposed to count the
// rectangles, but it always returns 0.
//
WNDOBJ_cEnumStart(pWo, CT_RECTANGLES, CD_ANY, 200);
//
// BOGUS BUGBUG LAURABU (perf opt for NT):
//
// NT will enum up to HET_WINDOW_RECTS at a time. Note that the enum
// function returns FALSE if, after obtaining the current batch, none
// are left to grab the next time.
//
// If the visrgn is composed of more than that, we will wipe out the
// previous set of rects, then ensure that the bounding box of the
// preceding rects is the last rect in the list.
//
// This is bad in several cases. For example if there are n visrgn piece
// rects, and n == c*HET_WINDOW_RECTS + 1, we will end up with 2 entries:
// * The last piece rect
// * The bounding box of the previous n-1 piece rects
// A lot of output may be accumulated in deadspace as a result.
//
// A better algorithm may be to fill the first HET_WINDOW_RECTS-1 slots,
// then union the rest into the last rectangle. That way we make use of
// all the slots. But this could be awkward, since we need a scratch
// ENUM_RECT struct rather than using the HET_WINDOW_STRUCT directly.
//
//
// First time through, enumerate HET_WINDOW_RECTS rectangles.
// Subsequent times, enumerate HET_WINDOW_RECTS-1 (see bottom of loop).
// This guarantees that there will be room to store a combined
// rectangle when we finally finish enumerating them.
//
pWnd->rects.c = HET_WINDOW_RECTS; rectl.left = LONG_MAX; rectl.top = LONG_MAX; rectl.right = 0; rectl.bottom = 0;
//
// Enumerate the rectangles
// NOTE that WNDOBJ_bEnum returns FALSE when there is nothing left
// to enumerate AFTER grabbing this set.
//
while (WNDOBJ_bEnum(pWo, sizeof(pWnd->rects), (ULONG *)&pWnd->rects)) { #ifdef _DEBUG
{ char trcStr[200]; UINT j;
sprintf(trcStr, "WNDOBJ %p %d: ", pWo, pWnd->rects.c);
for (j = 0; j < pWnd->rects.c; j++) { sprintf(trcStr, "%s {%ld, %ld, %ld, %ld} ", trcStr, pWnd->rects.arcl[j].left, pWnd->rects.arcl[j].top, pWnd->rects.arcl[j].right, pWnd->rects.arcl[j].bottom); if ((j & 3) == 3) // output every 4th rect
{ TRACE_OUT(( "%s", trcStr)); strcpy(trcStr, " "); } } if ((j & 3) != 0) // if any rects left
{ TRACE_OUT(( "%s", trcStr)); } } #endif
//
// Combine the preceding rectangles into one bounding rectangle
//
for (i = 0; i < pWnd->rects.c; i++) { if (pWnd->rects.arcl[i].left < rectl.left) { rectl.left = pWnd->rects.arcl[i].left; } if (pWnd->rects.arcl[i].top < rectl.top) { rectl.top = pWnd->rects.arcl[i].top; } if (pWnd->rects.arcl[i].right > rectl.right) { rectl.right = pWnd->rects.arcl[i].right; } if (pWnd->rects.arcl[i].bottom > rectl.bottom) { rectl.bottom = pWnd->rects.arcl[i].bottom; } } TRACE_OUT(( "Combined into {%ld, %ld, %ld, %ld}", rectl.left, rectl.top, rectl.right, rectl.bottom));
//
// Second & subsequent times, enumerate HET_WINDOW_RECTS-1
//
pWnd->rects.c = HET_WINDOW_RECTS - 1; }
//
// If any combining was done, save the combined rectangle now.
//
if (rectl.right != 0) { pWnd->rects.arcl[pWnd->rects.c] = rectl; pWnd->rects.c++; TRACE_OUT(( "Add combined rectangle to list")); }
//
// On the assumption that this WNDOBJ is the most likely to be the
// target of the next output command, move it to the top of the list.
//
COM_BasedListRemove(&(pWnd->chain)); COM_BasedListInsertAfter(&g_hetWindowList, &(pWnd->chain));
//
// Return to caller
//
DC_EXIT_POINT: DebugExitVOID(HETDDVisRgnCallback); }
//
//
// Name: HETDDShareWindow
//
// Description: Share a window (DD processing)
//
// Params: pso - SURFOBJ
// pReq - request received from DrvEscape
//
//
BOOL HETDDShareWindow(SURFOBJ *pso, LPHET_SHARE_WINDOW pReq) { PWNDOBJ pWo; FLONG fl = WO_RGN_CLIENT | WO_RGN_UPDATE_ALL | WO_RGN_WINDOW; LPHET_WINDOW_STRUCT pWnd; BOOL rc = FALSE;
DebugEntry(HETDDShareWindow);
ASSERT(!g_hetDDDesktopIsShared);
//
// Try to track the window
//
pWo = EngCreateWnd(pso, (HWND)pReq->winID, HETDDVisRgnCallback, fl, 0);
//
// Failed to track window - exit now
//
if (pWo == 0) { ERROR_OUT(( "Failed to track window %#x", pReq->winID)); DC_QUIT; }
//
// Window is already tracked. This happens when an invisible window is
// shown in a process the USER shared, and we caught its create.
//
if (pWo == (PWNDOBJ)-1) { //
// No more to do here
//
TRACE_OUT(( "Window %#x already tracked", pReq->winID)); rc = TRUE; DC_QUIT; }
//
// Add window into our list.
//
//
// Find free window structure
//
pWnd = COM_BasedListFirst(&g_hetFreeWndList, FIELD_OFFSET(HET_WINDOW_STRUCT, chain));
//
// If no free structures, grow the list
//
if (pWnd == NULL) { if (!HETDDAllocWndMem()) { ERROR_OUT(( "Unable to allocate new window structures")); DC_QUIT; }
pWnd = COM_BasedListFirst(&g_hetFreeWndList, FIELD_OFFSET(HET_WINDOW_STRUCT, chain)); }
//
// Fill in the structure
//
TRACE_OUT(( "Fill in details for new window")); pWnd->hwnd = (HWND)pReq->winID; pWnd->wndobj = pWo;
//
// Set this to zero. There's a brief period between the time we put
// this in our tracked list and the time we get called back to recalc
// the visrgn (because the ring 3 code invalidates the window completely).
// We might get graphical output and we don't want to parse garbage
// from this window's record.
//
pWnd->rects.c = 0;
//
// Move the window structure from free to active list
//
COM_BasedListRemove(&(pWnd->chain)); COM_BasedListInsertAfter(&g_hetWindowList, &(pWnd->chain));
//
// Save backwards pointer in the WNDOBJ
// THIS MUST BE LAST since our callback can happen anytime afterwards.
//
// NOTE that the window's visrgn rects get into our list because the
// ring3 code completely invalidates the window, causing the callback
// to get called.
//
TRACE_OUT(( "Save pointer %#lx in Wndobj %#x", pWnd, pWo)); WNDOBJ_vSetConsumer(pWo, pWnd);
rc = TRUE;
DC_EXIT_POINT: DebugExitBOOL(HETDDShareWindow, rc); return(rc); }
//
//
// Name: HETDDUnshareWindow
//
// Description: Unshare a window (DD processing)
//
//
//
void HETDDUnshareWindow(LPHET_UNSHARE_WINDOW pReq) { LPHET_WINDOW_STRUCT pWnd, pNextWnd;
DebugEntry(HETDDUnshareWindow);
TRACE_OUT(( "Unshare %x", pReq->winID)); //
// Scan window list for this window and its descendants
//
pWnd = COM_BasedListFirst(&g_hetWindowList, FIELD_OFFSET(HET_WINDOW_STRUCT, chain)); while (pWnd != NULL) { //
// If this window is being unshared, free it
//
pNextWnd = COM_BasedListNext(&g_hetWindowList, pWnd, FIELD_OFFSET(HET_WINDOW_STRUCT, chain));
if (pWnd->hwnd == (HWND)pReq->winID) { TRACE_OUT(( "Unsharing %x", pReq->winID));
//
// Stop tracking the window
//
HETDDDeleteAndFreeWnd(pWnd); }
//
// Go on to (previously saved) next window
//
pWnd = pNextWnd; }
//
// Return to caller
//
DebugExitVOID(HETDDUnshareWindow); }
//
//
// Name: HETDDUnshareAll
//
// Description: Unshare all windows (DD processing) (what did you expect)
//
//
void HETDDUnshareAll(void) { LPHET_WINDOW_STRUCT pWnd;
DebugEntry(HETDDUnshareAll);
//
// Clear all window structures
//
while (pWnd = COM_BasedListFirst(&g_hetWindowList, FIELD_OFFSET(HET_WINDOW_STRUCT, chain))) { TRACE_OUT(( "Unshare Window structure %x", pWnd));
//
// Stop tracking the window
//
HETDDDeleteAndFreeWnd(pWnd); }
//
// Return to caller
//
DebugExitVOID(HETDDUnshareAll); }
//
//
// Name: HETDDAllocWndMem
//
// Description: Allocate memory for a (new) window list
//
// Parameters: None
//
//
BOOL HETDDAllocWndMem(void) { BOOL rc = FALSE; int i; LPHET_WINDOW_MEMORY pNew;
DebugEntry(HETDDAllocWndMem);
//
// Allocate a new strucure
//
pNew = EngAllocMem(FL_ZERO_MEMORY, sizeof(HET_WINDOW_MEMORY), OSI_ALLOC_TAG); if (pNew == NULL) { ERROR_OUT(("HETDDAllocWndMem: unable to allocate memory")); DC_QUIT; }
//
// Add this memory block to the list of memory blocks
//
COM_BasedListInsertAfter(&g_hetMemoryList, &(pNew->chain));
//
// Add all new entries to free list
//
TRACE_OUT(("HETDDAllocWndMem: adding new entries to free list")); for (i = 0; i < HET_WINDOW_COUNT; i++) { COM_BasedListInsertAfter(&g_hetFreeWndList, &(pNew->wnd[i].chain)); }
rc = TRUE;
DC_EXIT_POINT: DebugExitBOOL(HETDDAllocWndMem, rc); return(rc); }
//
//
// Name: HETDDDeleteAndFreeWnd
//
// Description: Delete and window and free its window structure
//
// Parameters: pWnd - pointer to window structure to delete & free
//
// Returns: none
//
// Operation: Ths function stops tracking a window and frees its memory
//
//
void HETDDDeleteAndFreeWnd(LPHET_WINDOW_STRUCT pWnd) { DebugEntry(HETDDDeleteAndFreeWnd);
//
// Stop tracking the window
//
EngDeleteWnd(pWnd->wndobj);
//
// NOTE LAURABU! EngDeleteWnd() will call the VisRgnCallback with
// WO_DELETE, which will cause us to exectute a duplicate of exactly
// the code below. So why do it twice (which is scary anyway), especially
// the stop hosting code?
//
ASSERT(pWnd->hwnd == NULL);
//
// Return to caller
//
DebugExitVOID(HETDDDeleteAndFreeWnd); }
//
// HETDDViewers()
//
// Called when viewing of our shared apps starts/stops. Naturally, no longer
// sharing anything stops viewing also.
//
void HETDDViewing ( SURFOBJ * pso, BOOL fViewers ) { DebugEntry(HETDDViewers);
if (g_oeViewers != fViewers) { g_oeViewers = fViewers; CM_DDViewing(pso, fViewers);
if (g_oeViewers) { //
// Force palette grab.
//
g_asSharedMemory->pmPaletteChanged = TRUE; } }
DebugExitVOID(HETDDViewing); }
|