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.
922 lines
32 KiB
922 lines
32 KiB
/****************************************************************************/
|
|
// nddint.c
|
|
//
|
|
// RDP DD internal functions.
|
|
//
|
|
// Copyright (C) 1996-2000 Microsoft Corporation
|
|
/****************************************************************************/
|
|
|
|
#include <precmpdd.h>
|
|
#define hdrstop
|
|
|
|
#define TRC_FILE "nddint"
|
|
#include <adcg.h>
|
|
#include <atrcapi.h>
|
|
|
|
#include <nddapi.h>
|
|
#include <nsbcdisp.h>
|
|
#include <nbadisp.h>
|
|
#include <nshmapi.h>
|
|
#include <nwdwioct.h>
|
|
#include <nwdwapi.h>
|
|
#include <noadisp.h>
|
|
#include <nssidisp.h>
|
|
#include <abcapi.h>
|
|
#include <nchdisp.h>
|
|
#include <ncmdisp.h>
|
|
#include <noedisp.h>
|
|
#include <nschdisp.h>
|
|
#include <oe2.h>
|
|
|
|
#define DC_INCLUDE_DATA
|
|
#include <ndddata.c>
|
|
#undef DC_INCLUDE_DATA
|
|
|
|
|
|
/****************************************************************************/
|
|
// DDInitializeModeFields
|
|
//
|
|
// Initializes a bunch of fields in the pdev, devcaps (aka gdiinfo), and
|
|
// devinfo based on the requested mode. Returns FALSE on failure.
|
|
/****************************************************************************/
|
|
void RDPCALL DDInitializeModeFields(
|
|
PDD_PDEV ppdev,
|
|
GDIINFO *pGdiInfoOrg,
|
|
GDIINFO *pgdi,
|
|
DEVINFO *pdi,
|
|
DEVMODEW *pdm)
|
|
{
|
|
HPALETTE hpal;
|
|
|
|
DC_BEGIN_FN("DDInitializeModeFields");
|
|
|
|
TRC_NRM((TB, "Size of pdm: %d (should be %d)",
|
|
pdm->dmSize, sizeof(DEVMODEW)));
|
|
TRC_NRM((TB, "Requested mode..."));
|
|
TRC_NRM((TB, " Screen width -- %li", pdm->dmPelsWidth));
|
|
TRC_NRM((TB, " Screen height -- %li", pdm->dmPelsHeight));
|
|
TRC_NRM((TB, " Bits per pel -- %li", pdm->dmBitsPerPel));
|
|
TRC_NRM((TB, " Frequency -- %li", pdm->dmDisplayFrequency));
|
|
|
|
// Set up screen information from the DEVMODE structure.
|
|
ppdev->ulMode = 0;
|
|
ppdev->cxScreen = pdm->dmPelsWidth;
|
|
ppdev->cyScreen = pdm->dmPelsHeight;
|
|
ppdev->cClientBitsPerPel = pdm->dmBitsPerPel;
|
|
ppdev->cProtocolBitsPerPel = 8;
|
|
|
|
// Mark which functions we provide hooks for.
|
|
ppdev->flHooks = ( HOOK_TEXTOUT |
|
|
HOOK_STROKEPATH |
|
|
HOOK_BITBLT |
|
|
HOOK_COPYBITS |
|
|
HOOK_FILLPATH |
|
|
HOOK_LINETO |
|
|
HOOK_PAINT |
|
|
HOOK_STRETCHBLT |
|
|
HOOK_SYNCHRONIZEACCESS);
|
|
|
|
// Fill in the GDIINFO data structure with the default 8bpp values.
|
|
*pgdi = ddDefaultGdi;
|
|
|
|
// Now overwrite the defaults with the relevant information returned
|
|
// from the kernel driver:
|
|
pgdi->ulHorzRes = ppdev->cxScreen;
|
|
pgdi->ulVertRes = ppdev->cyScreen;
|
|
pgdi->ulPanningHorzRes = 0;
|
|
pgdi->ulPanningVertRes = 0;
|
|
|
|
pgdi->cBitsPixel = ppdev->cClientBitsPerPel;
|
|
pgdi->cPlanes = 1;
|
|
pgdi->ulVRefresh = 0;
|
|
|
|
pgdi->ulDACRed = 8;
|
|
pgdi->ulDACGreen = 8;
|
|
pgdi->ulDACBlue = 8;
|
|
|
|
pgdi->ulLogPixelsX = pdm->dmLogPixels;
|
|
pgdi->ulLogPixelsY = pdm->dmLogPixels;
|
|
|
|
#ifdef DC_HICOLOR
|
|
/************************************************************************/
|
|
/* Fill in the mask values. */
|
|
/************************************************************************/
|
|
if (pgdi->cBitsPixel == 24)
|
|
{
|
|
ppdev->flRed = TS_RED_MASK_24BPP;
|
|
ppdev->flGreen = TS_GREEN_MASK_24BPP;
|
|
ppdev->flBlue = TS_BLUE_MASK_24BPP;
|
|
}
|
|
else if (pgdi->cBitsPixel == 16)
|
|
{
|
|
ppdev->flRed = TS_RED_MASK_16BPP;
|
|
ppdev->flGreen = TS_GREEN_MASK_16BPP;
|
|
ppdev->flBlue = TS_BLUE_MASK_16BPP;
|
|
}
|
|
else if (pgdi->cBitsPixel == 15)
|
|
{
|
|
ppdev->flRed = TS_RED_MASK_15BPP;
|
|
ppdev->flGreen = TS_GREEN_MASK_15BPP;
|
|
ppdev->flBlue = TS_BLUE_MASK_15BPP;
|
|
}
|
|
else
|
|
{
|
|
ppdev->flRed = 0;
|
|
ppdev->flGreen = 0;
|
|
ppdev->flBlue = 0;
|
|
}
|
|
#else
|
|
ppdev->flRed = 0;
|
|
ppdev->flGreen = 0;
|
|
ppdev->flBlue = 0;
|
|
#endif
|
|
|
|
// Fill in the devinfo structure with the default 8bpp values, taking
|
|
// care not to trash the supplied hpalDefault (which allows us to
|
|
// query information about the real display driver's color format).
|
|
hpal = pdi->hpalDefault;
|
|
*pdi = ddDefaultDevInfo;
|
|
pdi->hpalDefault = hpal;
|
|
|
|
switch (ppdev->cClientBitsPerPel) {
|
|
case 8:
|
|
ppdev->iBitmapFormat = BMF_8BPP;
|
|
|
|
pgdi->ulNumColors = 20;
|
|
pgdi->ulNumPalReg = 256;
|
|
pgdi->ulHTOutputFormat = HT_FORMAT_8BPP;
|
|
|
|
pdi->iDitherFormat = BMF_8BPP;
|
|
break;
|
|
|
|
case 4:
|
|
ppdev->iBitmapFormat = BMF_4BPP;
|
|
|
|
pgdi->ulNumColors = 16;
|
|
pgdi->ulNumPalReg = 0;
|
|
pgdi->ulHTOutputFormat = HT_FORMAT_4BPP;
|
|
|
|
pdi->iDitherFormat = BMF_4BPP;
|
|
pdi->flGraphicsCaps &= ~GCAPS_PALMANAGED;
|
|
pgdi->ulDACRed = 4;
|
|
pgdi->ulDACGreen = 4;
|
|
pgdi->ulDACBlue = 4;
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
ppdev->iBitmapFormat = BMF_16BPP;
|
|
|
|
pgdi->ulHTOutputFormat = HT_FORMAT_16BPP;
|
|
|
|
pdi->iDitherFormat = BMF_16BPP;
|
|
pdi->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
|
|
break;
|
|
|
|
case 24:
|
|
// DIB conversions will only work if we have a standard RGB
|
|
// surface for 24bpp.
|
|
TRC_ASSERT((ppdev->flRed == 0x00ff0000), (TB,"Invalid red"));
|
|
TRC_ASSERT((ppdev->flGreen == 0x0000ff00), (TB,"Invalid green"));
|
|
TRC_ASSERT((ppdev->flBlue == 0x000000ff), (TB,"Invalid blue"));
|
|
|
|
ppdev->iBitmapFormat = BMF_24BPP;
|
|
|
|
pgdi->ulHTOutputFormat = HT_FORMAT_24BPP;
|
|
|
|
pdi->iDitherFormat = BMF_24BPP;
|
|
pdi->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
|
|
break;
|
|
|
|
case 32:
|
|
ppdev->iBitmapFormat = BMF_32BPP;
|
|
|
|
pgdi->ulHTOutputFormat = HT_FORMAT_32BPP;
|
|
|
|
pdi->iDitherFormat = BMF_32BPP;
|
|
pdi->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
|
|
break;
|
|
|
|
default:
|
|
// Unsupported bpp - pretend we are 8 bpp.
|
|
TRC_ERR((TB, "Unsupported bpp value: %d",
|
|
pGdiInfoOrg->cBitsPixel * pGdiInfoOrg->cPlanes));
|
|
break;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// DDInitializePalette
|
|
//
|
|
// Set up the default palette for the display driver. Returns FALSE on
|
|
// failure.
|
|
/****************************************************************************/
|
|
BOOL RDPCALL DDInitializePalette(PDD_PDEV ppdev, DEVINFO *pdi)
|
|
{
|
|
BOOL rc;
|
|
PALETTEENTRY *ppalTmp;
|
|
ULONG ulLoop;
|
|
BYTE jRed;
|
|
BYTE jGre;
|
|
BYTE jBlu;
|
|
HPALETTE hpal;
|
|
|
|
DC_BEGIN_FN("DDInitializePalette");
|
|
|
|
if (ppdev->iBitmapFormat == BMF_8BPP || ppdev->iBitmapFormat == BMF_4BPP) {
|
|
if (ppdev->iBitmapFormat == BMF_8BPP) {
|
|
// cColors == 256: Generate 256 (8*8*4) RGB combinations to fill
|
|
// the palette.
|
|
jRed = 0;
|
|
jGre = 0;
|
|
jBlu = 0;
|
|
|
|
ppalTmp = ppdev->Palette;
|
|
for (ulLoop = 256; ulLoop != 0; ulLoop--) {
|
|
// JPB: The values used in the default rainbow set of
|
|
// colors do not particularly matter. However, we do not
|
|
// want any of the entries to match entries in the default
|
|
// VGA colors. Therefore we tweak the color values
|
|
// slightly to ensure that there are no matches.
|
|
ppalTmp->peRed = ((jRed == 0) ? (jRed+1) : (jRed-1));
|
|
ppalTmp->peGreen = ((jGre == 0) ? (jGre+1) : (jGre-1));
|
|
ppalTmp->peBlue = ((jBlu == 0) ? (jBlu+1) : (jBlu-1));
|
|
ppalTmp->peFlags = 0;
|
|
|
|
ppalTmp++;
|
|
|
|
if (!(jRed += 32))
|
|
if (!(jGre += 32))
|
|
jBlu += 64;
|
|
}
|
|
|
|
// Fill in Windows reserved colors from the WIN 3.0 DDK. The
|
|
// Windows Manager reserved the first and last 10 colours for
|
|
// painting windows borders and for non-palette managed
|
|
// applications.
|
|
memcpy(ppdev->Palette, ddDefaultPalette, sizeof(PALETTEENTRY) *
|
|
10);
|
|
memcpy(&(ppdev->Palette[246]), &(ddDefaultPalette[10]),
|
|
sizeof(PALETTEENTRY) * 10);
|
|
|
|
// Create handle for palette.
|
|
hpal = EngCreatePalette(PAL_INDEXED, 256, (ULONG*)ppdev->Palette, 0,
|
|
0, 0);
|
|
}
|
|
else {
|
|
// Set up the new palette. The palette contains 256 colors, as
|
|
// that is the color depth of the protocol. For convenience,
|
|
// - copy entire 16-color palette into slots 0-15
|
|
// - copy high colors (8-15) into high end of palette (240-255)
|
|
// This means that we can use indices 0-15, or 0-7, 248-255
|
|
// later.
|
|
memcpy(ppdev->Palette, ddDefaultVgaPalette,
|
|
sizeof(ddDefaultVgaPalette));
|
|
|
|
// Zero the middle entries since the palette was uninitialized.
|
|
memset(&(ppdev->Palette[16]), 0, sizeof(PALETTEENTRY) * 208);
|
|
|
|
memcpy(&(ppdev->Palette[248]), &(ddDefaultVgaPalette[8]),
|
|
sizeof(*ddDefaultVgaPalette) * 8);
|
|
|
|
// Create handle for palette.
|
|
hpal = EngCreatePalette(PAL_INDEXED, 16, (ULONG*)ppdev->Palette, 0,
|
|
0, 0);
|
|
}
|
|
}
|
|
else {
|
|
TRC_ASSERT(((ppdev->iBitmapFormat == BMF_16BPP) ||
|
|
(ppdev->iBitmapFormat == BMF_24BPP) ||
|
|
(ppdev->iBitmapFormat == BMF_32BPP)),
|
|
(TB, "This case handles only 16, 24 or 32bpp"));
|
|
|
|
hpal = EngCreatePalette(PAL_BITFIELDS, 0, NULL, ppdev->flRed,
|
|
ppdev->flGreen, ppdev->flBlue);
|
|
}
|
|
|
|
ppdev->hpalDefault = hpal;
|
|
pdi->hpalDefault = hpal;
|
|
|
|
if (hpal != 0) {
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
rc = FALSE;
|
|
TRC_ERR((TB, "EngCreatePalette returned zero"));
|
|
}
|
|
|
|
// Note that we don't need to free the memory for the palette as that
|
|
// is always tidied up in the driver termination code
|
|
// (DrvDisableDriver).
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// DDGetModes
|
|
//
|
|
// Returns the list of modes supported. Sends an IOCtl to the miniport
|
|
// driver (the WD) to get the information. NOTE: the buffer must be freed up
|
|
// by the caller. Returns the number of entries in the videomode buffer.
|
|
// A return code of 0 is an error.
|
|
// A return code of -1 indicates that we are in chained mode.
|
|
/****************************************************************************/
|
|
INT32 RDPCALL DDGetModes(
|
|
HANDLE hDriver,
|
|
PVIDEO_MODE_INFORMATION *modeInformation,
|
|
PINT32 pModeSize)
|
|
{
|
|
ULONG ulTemp;
|
|
VIDEO_NUM_MODES modes;
|
|
INT32 rc = 0;
|
|
UINT32 bytesReturned;
|
|
NTSTATUS status;
|
|
|
|
DC_BEGIN_FN("DDGetModes");
|
|
|
|
// Get the number of modes supported by the mini-port.
|
|
if (!EngDeviceIoControl(hDriver, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES,
|
|
NULL, 0, &modes, sizeof(VIDEO_NUM_MODES), &ulTemp)) {
|
|
// When we're chained into the console session, our miniport will
|
|
// return 0 for the number of modes, indicating that we'll do whatever
|
|
// was specified in the registry when we got loaded.
|
|
if (modes.NumModes != 0) {
|
|
// Allocate the buffer to receive the modes from the miniport.
|
|
*pModeSize = modes.ModeInformationLength;
|
|
*modeInformation = (PVIDEO_MODE_INFORMATION)EngAllocMem(0,
|
|
modes.NumModes*modes.ModeInformationLength, DD_ALLOC_TAG);
|
|
|
|
|
|
if (*modeInformation != NULL) {
|
|
// Ask the mini-port to fill in the available modes.
|
|
if (!EngDeviceIoControl(hDriver, IOCTL_VIDEO_QUERY_AVAIL_MODES,
|
|
NULL, 0, *modeInformation,
|
|
modes.NumModes * modes.ModeInformationLength,
|
|
&ulTemp)) {
|
|
// Store the number of modes.
|
|
rc = modes.NumModes;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "getAvailableModes failed "
|
|
"VIDEO_QUERY_AVAIL_MODES"));
|
|
|
|
// Free the memory and quit.
|
|
EngFreeMem(*modeInformation);
|
|
*modeInformation = NULL;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "getAvailableModes failed EngAllocMem"));
|
|
}
|
|
}
|
|
else {
|
|
TRC_NRM((TB, "Num modes is 0 - chained"));
|
|
rc = -1;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "getAvailableModes failed VIDEO_QUERY_NUM_AVAIL_MODES"));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
// DDInit
|
|
//
|
|
// Initialize the display protocol components of RDPDD. Returns FALSE on
|
|
// failure.
|
|
/****************************************************************************/
|
|
#define PERSISTENT_CACHE_ENTRIES_DEFAULT 3072
|
|
|
|
BOOL RDPCALL DDInit(
|
|
PDD_PDEV pPDev,
|
|
BOOL reconnect,
|
|
BOOL reinit,
|
|
PTSHARE_VIRTUAL_MODULE_DATA pVirtModuleData,
|
|
UINT32 virtModuleDataLen)
|
|
{
|
|
TSHARE_DD_CONNECT_IN connIn;
|
|
TSHARE_DD_CONNECT_OUT *connOut = NULL;
|
|
ULONG connOutSize;
|
|
ULONG bytesReturned;
|
|
NTSTATUS status;
|
|
BOOL rc = FALSE;
|
|
UINT32 IOCtlCode;
|
|
|
|
DC_BEGIN_FN("DDInit");
|
|
|
|
// Set the reconnect flag for debugging purposes.
|
|
ddReconnected = reconnect;
|
|
|
|
// Clear the order encoding histories since the client just reset its
|
|
// history as well.
|
|
OE_ClearOrderEncoding();
|
|
SSI_ClearOrderEncoding();
|
|
OE2_Reset();
|
|
OE_Reset();
|
|
|
|
// For reconnect, pPDev can be NULL. For connect, it is required.
|
|
TRC_ASSERT((reconnect || pPDev || reinit), (TB,"Bad call %d, %p", reconnect, pPDev));
|
|
DD_UPD_STATE(DD_INIT_IN);
|
|
|
|
// Create shared memory (SHM).
|
|
if (SHM_Init(pPDev)) {
|
|
DD_UPD_STATE(DD_INIT_SHM_OUT);
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Failed to init SHM"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
// IOCtl to the WD.
|
|
connIn.pShm = pddShm;
|
|
connIn.DDShmSize = sizeof(SHM_SHARED_MEMORY);
|
|
|
|
// Following 3 fields have meaning only for reconnect - set them
|
|
// anyway, RDPWD doesn't look at them for connect.
|
|
connIn.pKickTimer = pddWdTimer;
|
|
connIn.desktopHeight = ddDesktopHeight;
|
|
connIn.desktopWidth = ddDesktopWidth;
|
|
|
|
#ifdef DC_HICOLOR
|
|
// Need to supply this on the 'in' parameter - but note that it is not
|
|
// updated until DrvEnableSurface is called.
|
|
connIn.desktopBpp = ddFrameBufBpp;
|
|
#endif
|
|
|
|
// Fields for shadow connect, NULL for normal connection processing
|
|
connIn.pVirtModuleData = pVirtModuleData;
|
|
connIn.virtModuleDataLen = virtModuleDataLen;
|
|
|
|
connOutSize = sizeof(TSHARE_DD_CONNECT_OUT) + sizeof(SBC_BITMAP_CACHE_KEY_INFO) +
|
|
(PERSISTENT_CACHE_ENTRIES_DEFAULT - 1) * sizeof(SBC_MRU_KEY);
|
|
connOut = (TSHARE_DD_CONNECT_OUT *)EngAllocMem(0, connOutSize, DD_ALLOC_TAG);
|
|
|
|
if (connOut == NULL) {
|
|
TRC_ERR((TB, "Failed to allocate memory for connOut"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
memset(connOut, 0, connOutSize);
|
|
connOut->primaryStatus = STATUS_SUCCESS;
|
|
connOut->secondaryStatus = STATUS_SUCCESS;
|
|
connOut->bitmapKeyDatabaseSize = sizeof(SBC_BITMAP_CACHE_KEY_INFO) +
|
|
(PERSISTENT_CACHE_ENTRIES_DEFAULT - 1) * sizeof(SBC_MRU_KEY);
|
|
|
|
if (pVirtModuleData == NULL)
|
|
IOCtlCode = (reconnect && !reinit)? IOCTL_WDTS_DD_RECONNECT :
|
|
IOCTL_WDTS_DD_CONNECT;
|
|
else
|
|
IOCtlCode = IOCTL_WDTS_DD_SHADOW_CONNECT;
|
|
|
|
bytesReturned = 0;
|
|
status = EngFileIoControl(ddWdHandle, IOCtlCode, &connIn,
|
|
sizeof(TSHARE_DD_CONNECT_IN), connOut,
|
|
connOutSize, &bytesReturned);
|
|
DD_UPD_STATE(DD_INIT_IOCTL_OUT);
|
|
|
|
// If the primary stack connected, then we can continue output
|
|
// regardless of whether or not the shadow stack came up.
|
|
status = connOut->primaryStatus;
|
|
if (connOut->primaryStatus == STATUS_SUCCESS) {
|
|
ddConnected = TRUE;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Primary stack failed to connect! -> %lx", status));
|
|
DD_UPD_STATE(DD_INIT_FAIL1);
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (bytesReturned && bytesReturned <= connOutSize) {
|
|
DD_UPD_STATE(DD_INIT_OK1);
|
|
|
|
// Save off the returned values that we need.
|
|
if (IOCtlCode != IOCTL_WDTS_DD_SHADOW_CONNECT)
|
|
pddTSWd = connOut->pTSWd;
|
|
else
|
|
pddTSWdShadow = connOut->pTSWd;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Wrong no %lu of bytes returned", bytesReturned));
|
|
DD_UPD_STATE(DD_INIT_FAIL2);
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Enable trace to WD, since the correct config will now be in SHM.
|
|
#ifdef DC_DEBUG
|
|
ddTrcToWD = TRUE;
|
|
#endif
|
|
|
|
#ifdef DC_COUNTERS
|
|
// Zero out the counters and cache statistics.
|
|
// We do not use counters unless specifically built to do so using
|
|
// DC_COUNTERS. However, even if we wanted to, there is a bad
|
|
// corruption problem owing to a timing problem where the counters are
|
|
// freed while the DD still believes they are present. This is Windows NT
|
|
// Bug #391762. If we want to have counters in production code we need
|
|
// to fix that Win32K timing bug. Enable DC_COUNTERS and special pool
|
|
// for rdpdd to make the bug come back.
|
|
pddProtStats = connOut->pProtocolStatus;
|
|
pddProtStats->Input.ProtocolType = PROTOCOL_ICA;
|
|
pddProtStats->Output.ProtocolType = PROTOCOL_ICA;
|
|
memset(pddCacheStats, 0, sizeof(ICA_CACHE));
|
|
memset(&(pddProtStats->Output.Specific),
|
|
0, sizeof(pddProtStats->Output.Specific));
|
|
memset(&(pddProtStats->Input.Specific),
|
|
0, sizeof(pddProtStats->Input.Specific));
|
|
#endif
|
|
|
|
TRC_ERR((TB, "Received pTSWD %p", pddTSWd));
|
|
ddDesktopHeight = connOut->desktopHeight;
|
|
ddDesktopWidth = connOut->desktopWidth;
|
|
|
|
// Once pddShm is set up, tracing should work - try it now.
|
|
TRC_NRM((TB, "Handshake with RDPWD complete"));
|
|
|
|
// Perform any other init that may be required for the wire protocol.
|
|
if (!reconnect && !reinit) {
|
|
TRC_NRM((TB, "Connect"));
|
|
DD_UPD_STATE(DD_INIT_CONNECT);
|
|
|
|
BA_DDInit();
|
|
OA_DDInit();
|
|
SSI_DDInit();
|
|
if (!CM_DDInit(pPDev)) {
|
|
TRC_ERR((TB, "CM Failed"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
SBC_DDInit(pPDev);
|
|
} /* !reconnect */
|
|
|
|
// RDPWD waits to receive all of ConfirmActivePDU, persistent bitmap
|
|
// cache keys, and font lists from the Client before returning from the
|
|
// IOCTL_WDTS_DD_(RE)CONNECT above. Hence, by the time we get here,
|
|
// the capabilities have been updated in SHM. We do this for connect and
|
|
// reconnect cases.
|
|
TRC_NRM((TB, "Update capabilities"));
|
|
OE_Update();
|
|
CM_Update();
|
|
|
|
// If bitmapKeyDatabaseSize is 0, then we failed to get the keydatabase
|
|
// or there is no persistent caching
|
|
if (connOut->bitmapKeyDatabaseSize) {
|
|
if (connOut->bitmapKeyDatabaseSize <= sizeof(SBC_BITMAP_CACHE_KEY_INFO) +
|
|
(PERSISTENT_CACHE_ENTRIES_DEFAULT - 1) * sizeof(SBC_MRU_KEY)) {
|
|
SBC_Update((SBC_BITMAP_CACHE_KEY_INFO *)(&(connOut->bitmapKeyDatabase)));
|
|
}
|
|
else {
|
|
PTSHARE_DD_BITMAP_KEYDATABASE_OUT pKeyDBOut;
|
|
unsigned keyDBOutSize;
|
|
unsigned bytesReturned;
|
|
|
|
// the buffer is too small, reallocate a big one and try once more
|
|
keyDBOutSize = sizeof(TSHARE_DD_BITMAP_KEYDATABASE_OUT) - 1+
|
|
connOut->bitmapKeyDatabaseSize;
|
|
|
|
pKeyDBOut = (PTSHARE_DD_BITMAP_KEYDATABASE_OUT)
|
|
EngAllocMem(0, keyDBOutSize, DD_ALLOC_TAG);
|
|
|
|
if (pKeyDBOut == NULL) {
|
|
TRC_ERR((TB, "Failed to allocate memory for connOut"));
|
|
SBC_Update(NULL);
|
|
}
|
|
else {
|
|
pKeyDBOut->bitmapKeyDatabaseSize = connOut->bitmapKeyDatabaseSize;
|
|
|
|
status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_GET_BITMAP_KEYDATABASE,
|
|
NULL, 0, pKeyDBOut,
|
|
keyDBOutSize, &bytesReturned);
|
|
|
|
if (status == STATUS_SUCCESS && pKeyDBOut->bitmapKeyDatabaseSize <=
|
|
connOut->bitmapKeyDatabaseSize) {
|
|
SBC_Update((SBC_BITMAP_CACHE_KEY_INFO *)(&(pKeyDBOut->bitmapKeyDatabase)));
|
|
}
|
|
else {
|
|
SBC_Update(NULL);
|
|
}
|
|
|
|
EngFreeMem(pKeyDBOut);
|
|
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
SBC_Update(NULL);
|
|
}
|
|
|
|
SSI_Update(pVirtModuleData != NULL);
|
|
|
|
// All OK for Primary Stack
|
|
ddInitialised = TRUE;
|
|
DD_UPD_STATE(DD_INIT_OK_ALL);
|
|
|
|
// If the shadow stack failed to init, then flag it so we disconnect
|
|
// the failed shadow stack via DrvShadowDisconnect
|
|
if (connOut->secondaryStatus != STATUS_SUCCESS) {
|
|
status = connOut->secondaryStatus;
|
|
TRC_ERR((TB, "Shadow stack failed to connect! -> %lx", status));
|
|
DD_UPD_STATE(DD_SHADOW_FAIL);
|
|
DC_QUIT;
|
|
}
|
|
|
|
// If we got here then absolutely everything went OK
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
if (connOut != NULL) {
|
|
EngFreeMem(connOut);
|
|
connOut = NULL;
|
|
}
|
|
DC_END_FN();
|
|
return rc;
|
|
} /* DDInit */
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: DDDisconnect */
|
|
/* */
|
|
/* Purpose: Terminate the share aspects of the DD. */
|
|
/* */
|
|
/* Params: bShadowDisconnect - TRUE is this is being done in preparation */
|
|
/* for a shadow session request. */
|
|
/* */
|
|
/* Operation: Terminates all sub-components, and then IOCtls to the WD to */
|
|
/* tell it that we're going. */
|
|
/* */
|
|
/* Finally it cleans up all refereces to WD data. */
|
|
/* */
|
|
/* NB This routine can be called on connect failure - so all the */
|
|
/* XX_Disc() APIs called by this routine must be robust to the */
|
|
/* component not having been initialized. */
|
|
/****************************************************************************/
|
|
void RDPCALL DDDisconnect(BOOL bShadowDisconnect)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG bytesReturned;
|
|
TSHARE_DD_DISCONNECT_IN disconnIn;
|
|
|
|
DC_BEGIN_FN("DDDisconnect");
|
|
DD_UPD_STATE(DD_DISCONNECT_IN);
|
|
|
|
// Call disconnect functions where needed.
|
|
CM_DDDisc();
|
|
|
|
// Now tell the WD we're disconnecting. We don't do anything with a
|
|
// failure here - there's no point - we're already disconnecting!
|
|
memset(&disconnIn, 0, sizeof(disconnIn));
|
|
disconnIn.pShm = pddShm;
|
|
disconnIn.bShadowDisconnect = bShadowDisconnect;
|
|
|
|
status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_DISCONNECT,
|
|
&disconnIn, sizeof(disconnIn), NULL, 0, &bytesReturned);
|
|
|
|
// Send Bitmap Cache. Must be destroyed after the IOCTL to allow the
|
|
// IOCTL to dump the cache contents for reconnect.
|
|
SBC_DDDisc();
|
|
|
|
// Finally, free SHM.
|
|
SHM_Term();
|
|
|
|
// If this is a real session disconnect, then blow away the WD ioctl
|
|
// handle since we will get a new on one DrvReconnect(). Otherwise
|
|
// we need to keep it since we will immediately reconnect back to the
|
|
// same stack.
|
|
if (!bShadowDisconnect)
|
|
ddWdHandle = NULL;
|
|
|
|
// Don't allow any drawing while we are disconnected!
|
|
ddConnected = FALSE;
|
|
|
|
TRC_NRM((TB, "Status on Disc IOCtl to WD %lu", status));
|
|
DD_UPD_STATE(DD_DISCONNECT_OUT);
|
|
|
|
DC_END_FN();
|
|
} /* DDDisconnect */
|
|
|
|
|
|
/****************************************************************************/
|
|
// DDTerm
|
|
//
|
|
// Terminate the output-remoting components of the DD.
|
|
/****************************************************************************/
|
|
void RDPCALL DDTerm(void)
|
|
{
|
|
BOOL rc;
|
|
NTSTATUS status;
|
|
|
|
DC_BEGIN_FN("DDTerm");
|
|
|
|
// Call terminate functions where needed.
|
|
SBC_DDTerm();
|
|
CM_DDTerm();
|
|
|
|
// Finally, free SHM.
|
|
SHM_Term();
|
|
|
|
ddWdHandle = NULL;
|
|
pddWdTimer = NULL;
|
|
|
|
if (pddFrameBuf != NULL) {
|
|
if (ddSectionObject != NULL) {
|
|
TRC_NRM((TB, "Freeing section mem frame buffer %p", pddFrameBuf));
|
|
rc = EngFreeSectionMem(ddSectionObject, pddFrameBuf);
|
|
if (!rc) {
|
|
TRC_ABORT((TB, "EngFreeSectionMem failed, section object will "
|
|
"leak"));
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
else {
|
|
// NT BUG 539912 - Instance count section memory objects
|
|
dbg_ddSectionAllocs--;
|
|
TRC_DBG(( TB, "DDTerm - %d outstanding surfaces allocated",
|
|
dbg_ddSectionAllocs ));
|
|
|
|
DBG_DD_FNCALL_HIST_ADD( DBG_DD_FREE_SECTIONOBJ_DDTERM,
|
|
dbg_ddSectionAllocs, 0, pddFrameBuf, ddSectionObject);
|
|
}
|
|
#endif // DC_DEBUG
|
|
ddSectionObject = NULL;
|
|
} else {
|
|
TRC_NRM((TB, "Freeing non-section frame buffer %p", pddFrameBuf));
|
|
EngFreeMem(pddFrameBuf);
|
|
}
|
|
pddFrameBuf = NULL;
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
if (0 != dbg_ddSectionAllocs) {
|
|
TRC_ABORT(( TB, "DDTerm - no section allocations should be outstanding" ));
|
|
}
|
|
#endif
|
|
|
|
// Reset the frame buffer size to 0
|
|
ddFrameBufX = ddFrameBufY = 0;
|
|
|
|
ddInitialised = FALSE;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
#define TS_GDIPLUS_LOCK_FALG 0x00000001
|
|
/****************************************************************************/
|
|
/* DdLock - see NT DDK documentation. */
|
|
/* */
|
|
/****************************************************************************/
|
|
DWORD DdLock(PDD_LOCKDATA lpLock)
|
|
{
|
|
DC_BEGIN_FN("DdLock");
|
|
|
|
TRC_NRM((TB, "DdLock"));
|
|
#ifdef DRAW_GDIPLUS
|
|
if (lpLock->dwFlags & DDLOCK_NODIRTYUPDATE) {
|
|
// The lock is from GDI+ through DCI
|
|
// set the flag
|
|
lpLock->lpDDSurface->dwReserved1 |= TS_GDIPLUS_LOCK_FALG;
|
|
}
|
|
else {
|
|
#endif
|
|
// We assume that DdLock and DdUnlock will be called in pair.
|
|
// If this is not the case, we return error in DdLock
|
|
if(ddLocked){
|
|
TRC_ERR((TB, "Error: DdLock is called twice in a row"));
|
|
lpLock->ddRVal = DDERR_GENERIC;
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
// Record the locked area
|
|
ddLockAreaLeft = lpLock->rArea.left;
|
|
ddLockAreaTop= lpLock->rArea.top;
|
|
ddLockAreaRight = lpLock->rArea.right;
|
|
ddLockAreaBottom = lpLock->rArea.bottom;
|
|
|
|
// Record that DdLock is called
|
|
ddLocked = TRUE;
|
|
#ifdef DRAW_GDIPLUS
|
|
}
|
|
#endif
|
|
|
|
return(DDHAL_DRIVER_NOTHANDLED );
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* DdUnlock - see NT DDK documentation. */
|
|
/* */
|
|
/****************************************************************************/
|
|
DWORD DdUnlock(PDD_UNLOCKDATA lpUnlock)
|
|
{
|
|
PDD_PDEV pPDev;
|
|
RECTL rLockArea;
|
|
|
|
DC_BEGIN_FN("DdUnlock");
|
|
|
|
TRC_NRM((TB, "DdUnlock"));
|
|
|
|
pPDev = (PDD_PDEV)lpUnlock->lpDD->dhpdev;
|
|
#ifdef DRAW_GDIPLUS
|
|
if (lpUnlock->lpDDSurface->dwReserved1 & TS_GDIPLUS_LOCK_FALG) {
|
|
// The lock is from GDI+ through DCI
|
|
}
|
|
else {
|
|
#endif
|
|
// We assume that DdLock and DdUnlock will be called in pair.
|
|
// If this is not the case, we return error in DdLock
|
|
if(!ddLocked){
|
|
TRC_ERR((TB, "Error: DdUnlock is called before DdLock"));
|
|
lpUnlock->ddRVal = DDERR_GENERIC;
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
// Reset the lock flag
|
|
ddLocked = FALSE;
|
|
|
|
// Sometimes, we're called after being disconnected.
|
|
if (ddConnected && pddShm != NULL) {
|
|
rLockArea.left = ddLockAreaLeft;
|
|
rLockArea.right = ddLockAreaRight;
|
|
rLockArea.top = ddLockAreaTop;
|
|
rLockArea.bottom = ddLockAreaBottom;
|
|
|
|
|
|
// Send changed rectangle of framebuffer to the client
|
|
OEClipAndAddScreenDataArea(&rLockArea, NULL);
|
|
|
|
// Have scheduler consider sending output
|
|
SCH_DDOutputAvailable(pPDev, FALSE);
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Called when disconnected"));
|
|
}
|
|
#ifdef DRAW_GDIPLUS
|
|
}
|
|
#endif
|
|
|
|
return(DDHAL_DRIVER_NOTHANDLED );
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine********************************/
|
|
/* DdMapMemory - see NT DDK documentation. */
|
|
/* */
|
|
/* This is a new DDI call specific to Windows NT that is used to map */
|
|
/* or unmap all the application modifiable portions of the frame buffer */
|
|
/* into the specified process's address space. */
|
|
/****************************************************************************/
|
|
DWORD DdMapMemory(PDD_MAPMEMORYDATA lpMapMemory)
|
|
{
|
|
PDD_PDEV pPDev;
|
|
PVOID pMapped = NULL;
|
|
NTSTATUS Status;
|
|
BOOL bEngMap;
|
|
|
|
DC_BEGIN_FN("DdMapMemory");
|
|
|
|
TRC_NRM((TB, "DdMapMemory"));
|
|
|
|
pPDev = (PDD_PDEV) lpMapMemory->lpDD->dhpdev;
|
|
|
|
// In case the section object is null our frame buffer is not allocated
|
|
// as section mem. We don't support DDraw in this case.
|
|
if (NULL == pPDev->SectionObject) {
|
|
TRC_ERR((TB,"Null SectionObject"));
|
|
lpMapMemory->ddRVal = DDERR_GENERIC;
|
|
DC_QUIT;
|
|
}
|
|
|
|
if(lpMapMemory->bMap) //Map the meory
|
|
pMapped = NULL;
|
|
else //Unmap the memory
|
|
pMapped = (PVOID)lpMapMemory->fpProcess;
|
|
|
|
bEngMap = EngMapSection(
|
|
pPDev->SectionObject,
|
|
lpMapMemory->bMap,
|
|
lpMapMemory->hProcess,
|
|
&pMapped);
|
|
|
|
if(lpMapMemory->bMap && bEngMap)
|
|
lpMapMemory->fpProcess = (FLATPTR)pMapped;
|
|
|
|
if(bEngMap)
|
|
lpMapMemory->ddRVal = DD_OK;
|
|
else
|
|
lpMapMemory->ddRVal = DDERR_GENERIC;
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|