/****************************************************************************/ // nddint.c // // RDP DD internal functions. // // Copyright (C) 1996-2000 Microsoft Corporation /****************************************************************************/ #include #define hdrstop #define TRC_FILE "nddint" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DC_INCLUDE_DATA #include #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); }