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.
1127 lines
30 KiB
1127 lines
30 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: dciman.c *
|
|
* *
|
|
* Client side stubs for DCIMAN functions. *
|
|
* *
|
|
* Created: 07-Sep-1994 *
|
|
* Author: Andre Vachon [andreva] *
|
|
* *
|
|
* Copyright (c) 1994-1998 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stddef.h>
|
|
#include <windows.h>
|
|
#include <winspool.h>
|
|
#include <wingdip.h>
|
|
#include <ddrawp.h>
|
|
#include <winddi.h>
|
|
#include "dciddi.h"
|
|
#include "dciman.h"
|
|
#include <ddrawi.h>
|
|
#include <ddrawgdi.h>
|
|
|
|
#if DBG
|
|
|
|
#define RIP(x) {DbgPrint(x); DbgBreakPoint();}
|
|
#define ASSERTGDI(x,y) if(!(x)) RIP(y)
|
|
#define WARNING(x) {DbgPrint(x);}
|
|
|
|
#else
|
|
|
|
#define ASSERTGDI(x,y)
|
|
#define WARNING(x)
|
|
|
|
#endif
|
|
|
|
typedef struct _WINWATCH *PWINWATCH;
|
|
|
|
typedef struct _WINWATCH {
|
|
|
|
PWINWATCH pWinWatchNext;
|
|
HWND hwnd;
|
|
BOOL changed;
|
|
ULONG lprgndataSize;
|
|
LPRGNDATA lprgndata;
|
|
|
|
} WINWATCH, *PWINWATCH;
|
|
|
|
//
|
|
// The following structure incorporates the DirectDraw structures required
|
|
// to identify a surface. It is allocated before the start of the
|
|
// DCISURFACEINFO structure.
|
|
//
|
|
|
|
typedef struct _DCIMAN_SURF
|
|
{
|
|
BOOL SurfaceLost; // True if the surface can no
|
|
// longer be accessed because
|
|
// a mode change occured
|
|
DDRAWI_DIRECTDRAW_GBL DirectDrawGlobal; // Identifies device
|
|
DDRAWI_DDRAWSURFACE_GBL SurfaceGlobal; // Identifies surface
|
|
DDRAWI_DDRAWSURFACE_LCL SurfaceLocal; // Identifies surface
|
|
DDHAL_DDCALLBACKS DDCallbacks; // Contains address of CreateSurface
|
|
// call for BeginAccess
|
|
DDHAL_DDSURFACECALLBACKS DDSurfaceCallbacks;// Contains addresses of Lock, Unlock,
|
|
// and DestroySurface calls for
|
|
// BeginAccess and EndAccess
|
|
} DCIMAN_SURF, *PDCIMAN_SURF;
|
|
|
|
//
|
|
// We maintain a linked list of all winwatch's so that we can notify their
|
|
// owners whenever we notice that the clippping has changed. The list may
|
|
// be accessed only while holding the gcsWinWatchLock critical section.
|
|
//
|
|
|
|
CRITICAL_SECTION gcsWinWatchLock;
|
|
|
|
PWINWATCH gpWinWatchList = NULL;
|
|
|
|
/******************************Private*Routine*****************************\
|
|
* dciCreateSurface
|
|
*
|
|
* History: 1-Aug-1998 Jerry Van Aken [jvanaken] wrote it.
|
|
\**************************************************************************/
|
|
|
|
static BOOL bCreateSurface(PDCIMAN_SURF pPrivate)
|
|
{
|
|
DDSURFACEDESC ddsd;
|
|
DDHAL_CREATESURFACEDATA csd;
|
|
LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal = &pPrivate->SurfaceLocal;
|
|
|
|
//
|
|
// Fill in DDSURFACEDESC struct for CreateSurface call.
|
|
//
|
|
|
|
ZeroMemory(&ddsd, sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
ddsd.dwFlags = DDSD_CAPS;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
|
|
|
|
//
|
|
// Fill in DDHAL_CREATESURFACEDATA struct for CreateSurface call.
|
|
//
|
|
|
|
csd.lpDD = pPrivate->SurfaceGlobal.lpDD;
|
|
csd.lpDDSurfaceDesc = &ddsd;
|
|
csd.lplpSList = &pSurfaceLocal;
|
|
csd.dwSCnt = 1;
|
|
csd.ddRVal = DDERR_GENERIC;
|
|
csd.CreateSurface = pPrivate->DDCallbacks.CreateSurface;
|
|
|
|
if ((pPrivate->DDCallbacks.dwFlags & DDHAL_CB32_CREATESURFACE) &&
|
|
(csd.CreateSurface != NULL) &&
|
|
((*csd.CreateSurface)(&csd) == DDHAL_DRIVER_HANDLED) &&
|
|
(csd.ddRVal == DD_OK))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************Private*Routine*****************************\
|
|
* dciCreateSurface
|
|
*
|
|
* History: 1-Aug-1998 Jerry Van Aken [jvanaken] wrote it.
|
|
\**************************************************************************/
|
|
|
|
static BOOL bDestroySurface(PDCIMAN_SURF pPrivate)
|
|
{
|
|
DDHAL_DESTROYSURFACEDATA dsd;
|
|
|
|
dsd.lpDD = pPrivate->SurfaceGlobal.lpDD;
|
|
dsd.lpDDSurface = &pPrivate->SurfaceLocal;
|
|
dsd.ddRVal = DDERR_GENERIC;
|
|
dsd.DestroySurface = pPrivate->DDSurfaceCallbacks.DestroySurface;
|
|
|
|
if ((pPrivate->DDSurfaceCallbacks.dwFlags & DDHAL_SURFCB32_DESTROYSURFACE) &&
|
|
(dsd.DestroySurface != NULL) &&
|
|
((*dsd.DestroySurface)(&dsd) == DDHAL_DRIVER_HANDLED) &&
|
|
(dsd.ddRVal == DD_OK))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciOpenProvider
|
|
*
|
|
* History: 1-Aug-1998 Jerry Van Aken [jvanaken] added multimon support.
|
|
\**************************************************************************/
|
|
|
|
HDC
|
|
WINAPI
|
|
DCIOpenProvider(
|
|
void
|
|
)
|
|
{
|
|
HANDLE h;
|
|
DWORD iDevice;
|
|
BOOL (WINAPI *pfnEnum)(LPVOID, DWORD, DISPLAY_DEVICEW *, DWORD);
|
|
int cMonitors = GetSystemMetrics(SM_CMONITORS);
|
|
|
|
if (cMonitors <= 1)
|
|
{
|
|
//
|
|
// This is a single-monitor system.
|
|
//
|
|
|
|
return CreateDCW(L"Display", NULL, NULL, NULL);
|
|
}
|
|
|
|
//
|
|
// This is a multimon system. Get the DC for the primary monitor.
|
|
//
|
|
|
|
h = GetModuleHandle("user32.dll");
|
|
|
|
(FARPROC)pfnEnum = GetProcAddress(h, "EnumDisplayDevicesW");
|
|
|
|
if (pfnEnum == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (iDevice = 0; iDevice < (DWORD)cMonitors; ++iDevice)
|
|
{
|
|
DISPLAY_DEVICEW dd;
|
|
|
|
ZeroMemory(&dd, sizeof(dd));
|
|
dd.cb = sizeof(dd);
|
|
|
|
if (!(*pfnEnum)(NULL, iDevice, &dd, 0))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
|
|
{
|
|
//
|
|
// Return the DC for the primary monitor.
|
|
//
|
|
|
|
return CreateDCW(NULL, dd.DeviceName, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciCloseProvider
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
void
|
|
WINAPI
|
|
DCICloseProvider(
|
|
HDC hdc
|
|
)
|
|
{
|
|
DeleteDC(hdc);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciEnum
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
int
|
|
WINAPI
|
|
DCIEnum(
|
|
HDC hdc,
|
|
LPRECT lprDst,
|
|
LPRECT lprSrc,
|
|
LPVOID lpFnCallback,
|
|
LPVOID lpContext
|
|
)
|
|
{
|
|
return DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciCreatePrimarySurface
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
int
|
|
WINAPI
|
|
DCICreatePrimary(
|
|
HDC hdc,
|
|
LPDCISURFACEINFO *lplpSurface
|
|
)
|
|
{
|
|
int iRet;
|
|
LPDCISURFACEINFO lpSurface;
|
|
PDCIMAN_SURF pPrivate;
|
|
DDHALINFO HalInfo;
|
|
DDHAL_DDCALLBACKS DDCallbacks;
|
|
DDHAL_DDPALETTECALLBACKS DDPaletteCallbacks;
|
|
BOOL NewMode;
|
|
|
|
*lplpSurface = NULL;
|
|
iRet = DCI_FAIL_GENERIC;
|
|
|
|
pPrivate = (PDCIMAN_SURF) LocalAlloc(LMEM_ZEROINIT, sizeof(DCIMAN_SURF)
|
|
+ sizeof(DCISURFACEINFO));
|
|
if (pPrivate != NULL)
|
|
{
|
|
//
|
|
// We store private DCIMAN information in the DCIMAN_SURF structure
|
|
// that immediately preceeds the DCISURFACEINFO structure we'll give
|
|
// out.
|
|
//
|
|
|
|
lpSurface = (LPDCISURFACEINFO) (pPrivate + 1);
|
|
|
|
if (DdCreateDirectDrawObject(&pPrivate->DirectDrawGlobal, hdc))
|
|
{
|
|
if (DdReenableDirectDrawObject(&pPrivate->DirectDrawGlobal, &NewMode) &&
|
|
DdQueryDirectDrawObject(&pPrivate->DirectDrawGlobal,
|
|
&HalInfo,
|
|
&pPrivate->DDCallbacks,
|
|
&pPrivate->DDSurfaceCallbacks,
|
|
&DDPaletteCallbacks,
|
|
NULL, NULL, NULL, NULL,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
//
|
|
// Build the required DirectDraw links for the 'global' and
|
|
// 'local' surfaces.
|
|
//
|
|
|
|
pPrivate->SurfaceLost = FALSE;
|
|
pPrivate->DirectDrawGlobal.vmiData = HalInfo.vmiData;
|
|
pPrivate->SurfaceLocal.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
pPrivate->SurfaceLocal.lpGbl = &pPrivate->SurfaceGlobal;
|
|
pPrivate->SurfaceLocal.hDDSurface = 0;
|
|
pPrivate->SurfaceGlobal.lpDD = &pPrivate->DirectDrawGlobal;
|
|
pPrivate->SurfaceGlobal.wHeight = (WORD) HalInfo.vmiData.dwDisplayHeight;
|
|
pPrivate->SurfaceGlobal.wWidth = (WORD) HalInfo.vmiData.dwDisplayWidth;
|
|
pPrivate->SurfaceGlobal.lPitch = HalInfo.vmiData.lDisplayPitch;
|
|
|
|
if (bCreateSurface(pPrivate))
|
|
{
|
|
//
|
|
// Associate an hwnd of '-1' with this surface to let the
|
|
// kernel know that the application may be drawing to any
|
|
// window, so Visrgn notifications should happen when any
|
|
// window changes.
|
|
//
|
|
|
|
if (DdResetVisrgn(&pPrivate->SurfaceLocal, (HWND) -1))
|
|
{
|
|
lpSurface->dwSize = sizeof(DCISURFACEINFO);
|
|
|
|
if (HalInfo.vmiData.ddpfDisplay.dwRGBBitCount <= 8)
|
|
{
|
|
lpSurface->dwCompression = BI_RGB;
|
|
}
|
|
else
|
|
{
|
|
lpSurface->dwCompression = BI_BITFIELDS;
|
|
}
|
|
|
|
lpSurface->dwDCICaps = DCI_PRIMARY | DCI_VISIBLE;
|
|
lpSurface->dwMask[0] = HalInfo.vmiData.ddpfDisplay.dwRBitMask;
|
|
lpSurface->dwMask[1] = HalInfo.vmiData.ddpfDisplay.dwGBitMask;
|
|
lpSurface->dwMask[2] = HalInfo.vmiData.ddpfDisplay.dwBBitMask;
|
|
lpSurface->dwWidth = HalInfo.vmiData.dwDisplayWidth;
|
|
lpSurface->dwHeight = HalInfo.vmiData.dwDisplayHeight;
|
|
lpSurface->lStride = HalInfo.vmiData.lDisplayPitch;
|
|
lpSurface->dwBitCount = HalInfo.vmiData.ddpfDisplay.dwRGBBitCount;
|
|
lpSurface->dwOffSurface = 0;
|
|
lpSurface->wSelSurface = 0;
|
|
lpSurface->wReserved = 0;
|
|
lpSurface->dwReserved1 = 0;
|
|
lpSurface->dwReserved2 = 0;
|
|
lpSurface->dwReserved3 = 0;
|
|
lpSurface->BeginAccess = NULL;
|
|
lpSurface->EndAccess = NULL;
|
|
lpSurface->DestroySurface = NULL;
|
|
|
|
*lplpSurface = lpSurface;
|
|
return(DCI_OK);
|
|
}
|
|
|
|
//
|
|
// The call to DdResetVisrgn failed.
|
|
//
|
|
|
|
bDestroySurface(pPrivate);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// DirectDraw is not supported on this device.
|
|
//
|
|
|
|
iRet = DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
DdDeleteDirectDrawObject(&pPrivate->DirectDrawGlobal);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// DirectDraw is not supported on this device.
|
|
//
|
|
|
|
iRet = DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
LocalFree(pPrivate);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Can't allocate memory for PDCIMAN_SURF struct.
|
|
//
|
|
|
|
iRet = DCI_ERR_OUTOFMEMORY;
|
|
}
|
|
|
|
*lplpSurface = NULL;
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GdiDciCreateOffscreenSurface
|
|
*
|
|
* Stub to call CreateOffscreenSurface
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
int
|
|
WINAPI
|
|
DCICreateOffscreen(
|
|
HDC hdc,
|
|
DWORD dwCompression,
|
|
DWORD dwRedMask,
|
|
DWORD dwGreenMask,
|
|
DWORD dwBlueMask,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
DWORD dwDCICaps,
|
|
DWORD dwBitCount,
|
|
LPDCIOFFSCREEN *lplpSurface
|
|
)
|
|
{
|
|
return DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciCreateOverlay
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
int
|
|
WINAPI
|
|
DCICreateOverlay(
|
|
HDC hdc,
|
|
LPVOID lpOffscreenSurf,
|
|
LPDCIOVERLAY FAR *lplpSurface
|
|
)
|
|
{
|
|
return DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* WinWatchOpen
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
HWINWATCH
|
|
WINAPI
|
|
WinWatchOpen(
|
|
HWND hwnd
|
|
)
|
|
{
|
|
HDC hdc;
|
|
PWINWATCH pwatch;
|
|
|
|
EnterCriticalSection(&gcsWinWatchLock);
|
|
|
|
pwatch = (PWINWATCH) LocalAlloc(LPTR, sizeof(WINWATCH));
|
|
|
|
if (pwatch)
|
|
{
|
|
pwatch->hwnd = hwnd;
|
|
pwatch->changed = FALSE;
|
|
pwatch->lprgndataSize = 0;
|
|
pwatch->lprgndata = NULL;
|
|
|
|
//
|
|
// Add this to the head of the list.
|
|
//
|
|
|
|
pwatch->pWinWatchNext = gpWinWatchList;
|
|
gpWinWatchList = pwatch;
|
|
}
|
|
|
|
LeaveCriticalSection(&gcsWinWatchLock);
|
|
|
|
return (HWINWATCH) (pwatch);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* WinWatchClose
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
void
|
|
WINAPI
|
|
WinWatchClose(
|
|
HWINWATCH hWW
|
|
)
|
|
{
|
|
PWINWATCH pwatch = (PWINWATCH) hWW;
|
|
PWINWATCH ptmp;
|
|
|
|
EnterCriticalSection(&gcsWinWatchLock);
|
|
|
|
if (gpWinWatchList == pwatch)
|
|
{
|
|
//
|
|
// The specified winwatch is at the head of the list.
|
|
//
|
|
|
|
gpWinWatchList = pwatch->pWinWatchNext;
|
|
LocalFree(pwatch->lprgndata);
|
|
LocalFree(pwatch);
|
|
}
|
|
else
|
|
{
|
|
for (ptmp = gpWinWatchList;
|
|
ptmp != NULL;
|
|
ptmp = ptmp->pWinWatchNext)
|
|
{
|
|
if (ptmp->pWinWatchNext == pwatch)
|
|
{
|
|
//
|
|
// We've found the specified winwatch in the list.
|
|
//
|
|
|
|
ptmp->pWinWatchNext = pwatch->pWinWatchNext;
|
|
LocalFree(pwatch->lprgndata);
|
|
LocalFree(pwatch);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&gcsWinWatchLock);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* WinWatchGetClipList
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
UINT
|
|
WINAPI
|
|
WinWatchGetClipList(
|
|
HWINWATCH hWW,
|
|
LPRECT prc, // May be NULL
|
|
UINT size,
|
|
LPRGNDATA prd
|
|
)
|
|
{
|
|
PWINWATCH pwatch = (PWINWATCH) hWW;
|
|
DWORD dwSize;
|
|
DWORD dwNewSize;
|
|
UINT dwRet;
|
|
|
|
//
|
|
// The first time after the VisRgn has changed, we download and
|
|
// cache a copy of the clipping region. We do this because the VisRgn
|
|
// can change under our implementation even between doing a BeginAccess/
|
|
// EndAccess, and we should at least maintain a consistent copy of what
|
|
// we think is the current VisRgn.
|
|
//
|
|
// Mostly, we do this so that the following scenario doesn't happen:
|
|
//
|
|
// 1. The app calls WinWatchGetClipList to ascertain the clip size;
|
|
// 2. The VisRgn gets more complex;
|
|
// 3. The app then calls WinWatchGetClipList with a buffer size
|
|
// allocated from the return code of step 1., and the call fails
|
|
// because now the buffer isn't long enough. The problem is that
|
|
// most applications probably wouldn't expect this second call to
|
|
// fail, and so would keep on using what is now a completely invalid
|
|
// region buffer.
|
|
//
|
|
|
|
if (pwatch->changed)
|
|
{
|
|
pwatch->changed = FALSE;
|
|
|
|
//
|
|
// Assume failure.
|
|
//
|
|
|
|
pwatch->lprgndataSize = 0;
|
|
|
|
dwSize = GetWindowRegionData(pwatch->hwnd,
|
|
0,
|
|
NULL);
|
|
|
|
if (dwSize != 0)
|
|
{
|
|
|
|
Try_Again:
|
|
|
|
if (pwatch->lprgndata != NULL)
|
|
{
|
|
LocalFree(pwatch->lprgndata);
|
|
}
|
|
|
|
pwatch->lprgndata = LocalAlloc(0, dwSize);
|
|
|
|
if (pwatch->lprgndata != NULL)
|
|
{
|
|
dwNewSize = GetWindowRegionData(pwatch->hwnd,
|
|
dwSize,
|
|
pwatch->lprgndata);
|
|
|
|
if (dwNewSize == dwSize)
|
|
{
|
|
//
|
|
// Success! (Note that the docs are wrong and NT does
|
|
// not return '1' for success -- it returns the size
|
|
// of the buffer.)
|
|
//
|
|
|
|
pwatch->lprgndataSize = dwSize;
|
|
}
|
|
else if (dwSize != 0)
|
|
{
|
|
//
|
|
// Since dwSize is not zero, which would indicate failure
|
|
// or success, then we know that the clipping region grew
|
|
// in size between the time we queried the size and the
|
|
// time we tried to download it. This is a pretty rare
|
|
// event, and the chances of it happening again are slight
|
|
// (it's more likely that it will shrink the second time,
|
|
// anyway), so we just try it again.
|
|
//
|
|
|
|
dwSize = dwNewSize;
|
|
|
|
goto Try_Again;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now use the cached copy to handle any queries.
|
|
//
|
|
|
|
dwRet = 0;
|
|
|
|
if (size < pwatch->lprgndataSize)
|
|
{
|
|
dwRet = pwatch->lprgndataSize;
|
|
}
|
|
else
|
|
{
|
|
if (pwatch->lprgndataSize != 0)
|
|
{
|
|
RtlCopyMemory(prd, pwatch->lprgndata, pwatch->lprgndataSize);
|
|
dwRet = 1;
|
|
}
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* WinWatchDidStatusChange
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WinWatchDidStatusChange(
|
|
HWINWATCH hWW
|
|
)
|
|
{
|
|
PWINWATCH pwatch = (PWINWATCH) hWW;
|
|
|
|
return pwatch->changed;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetWindowRegionData
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
WINAPI
|
|
GetWindowRegionData(
|
|
HWND hwnd,
|
|
DWORD size,
|
|
LPRGNDATA prd
|
|
)
|
|
{
|
|
HDC hdc;
|
|
DWORD dwRet = 0;
|
|
|
|
hdc = GetDC(hwnd);
|
|
if (hdc)
|
|
{
|
|
dwRet = GetDCRegionData(hdc, size, prd);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetDCRegionData
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
WINAPI GetDCRegionData(
|
|
HDC hdc,
|
|
DWORD size,
|
|
LPRGNDATA prd
|
|
)
|
|
{
|
|
HRGN hrgn;
|
|
DWORD num;
|
|
LPRGNDATA lpdata;
|
|
|
|
hrgn = CreateRectRgn(0, 0, 0, 0);
|
|
|
|
if (hrgn == NULL) {
|
|
WARNING("GetDCRegionData - CreateRectRgn failed.\n");
|
|
return 0;
|
|
}
|
|
|
|
GetRandomRgn(hdc, hrgn, 4);
|
|
|
|
num = GetRegionData(hrgn, size, prd);
|
|
|
|
DeleteObject(hrgn);
|
|
|
|
return num;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* WinWatchNotify
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
WinWatchNotify(
|
|
HWINWATCH hWW,
|
|
WINWATCHNOTIFYPROC NotifyCallback,
|
|
LPARAM NotifyParam
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************Private*Routine*****************************\
|
|
* bDisplayModeChanged
|
|
*
|
|
* History: 9-Feb-1999 John Stephens [johnstep] wrote it.
|
|
\**************************************************************************/
|
|
|
|
static BOOL bDisplayModeChanged(PDCIMAN_SURF pPrivate)
|
|
{
|
|
LPDCISURFACEINFO lpSurface;
|
|
DDHALINFO HalInfo;
|
|
|
|
lpSurface = (LPDCISURFACEINFO) (pPrivate + 1);
|
|
if (DdQueryDirectDrawObject(&pPrivate->DirectDrawGlobal,
|
|
&HalInfo,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL, NULL, NULL, NULL,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
|
|
return
|
|
(lpSurface->dwWidth != HalInfo.vmiData.dwDisplayWidth) ||
|
|
(lpSurface->dwHeight != HalInfo.vmiData.dwDisplayHeight) ||
|
|
(lpSurface->lStride != HalInfo.vmiData.lDisplayPitch) ||
|
|
(lpSurface->dwBitCount != HalInfo.vmiData.ddpfDisplay.dwRGBBitCount);
|
|
}
|
|
|
|
//
|
|
// If we cannot even query the DirectDraw object, then we cannot make any
|
|
// assumptions about the current display mode, so it may have changed.
|
|
//
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciBeginAccess
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
DCIRVAL
|
|
WINAPI
|
|
DCIBeginAccess(
|
|
LPDCISURFACEINFO lpSurface,
|
|
int x,
|
|
int y,
|
|
int dx,
|
|
int dy
|
|
)
|
|
{
|
|
DCIRVAL iRet;
|
|
PDCIMAN_SURF pPrivate;
|
|
DDHAL_LOCKDATA LockData;
|
|
BOOL NewMode;
|
|
PWINWATCH pwatch;
|
|
|
|
iRet = DCI_FAIL_GENERIC;
|
|
|
|
pPrivate = ((PDCIMAN_SURF) lpSurface) - 1;
|
|
|
|
__try
|
|
{
|
|
//
|
|
// Fail if the mode changed.
|
|
//
|
|
|
|
if (pPrivate->SurfaceLost)
|
|
{
|
|
return DCI_FAIL_INVALIDSURFACE;
|
|
}
|
|
|
|
LockData.lpDD = &pPrivate->DirectDrawGlobal;
|
|
LockData.lpDDSurface = &pPrivate->SurfaceLocal;
|
|
LockData.bHasRect = TRUE;
|
|
LockData.rArea.left = x;
|
|
LockData.rArea.top = y;
|
|
LockData.rArea.right = x + dx;
|
|
LockData.rArea.bottom = y + dy;
|
|
LockData.dwFlags = DDLOCK_SURFACEMEMORYPTR;
|
|
|
|
//
|
|
// The DCI specification says we could return DCI_STATUS_WASSTILLDRAWING
|
|
// if the accelerator was still busy, but the previous release of DCI on
|
|
// Windows NT 3.51 did not support that feature, so we will endeavor to
|
|
// remain backwards compatible and do the wait explicitly on behalf of
|
|
// the application.
|
|
//
|
|
|
|
Try_Again:
|
|
|
|
do {
|
|
|
|
//
|
|
// Hold the DCI critical section while calling the kernel to do the
|
|
// lock because the kernel surface lock API does not have waiting
|
|
// semantics; it will fail if another thread is currently in the
|
|
// kernel locking the same surface. This is the expected behaviour
|
|
// for DirectDraw, but some clients of DCI -- OpenGL in particular --
|
|
// do not expect this. So we will protect them against themselves
|
|
// by acquiring the WinWatch lock before calling the kernel.
|
|
//
|
|
// This lock is also needed for traversing the WinWatchList.
|
|
//
|
|
|
|
EnterCriticalSection(&gcsWinWatchLock);
|
|
|
|
do {
|
|
pPrivate->DDSurfaceCallbacks.Lock(&LockData);
|
|
|
|
} while (LockData.ddRVal == DDERR_WASSTILLDRAWING);
|
|
|
|
if (LockData.ddRVal == DDERR_VISRGNCHANGED)
|
|
{
|
|
if (!DdResetVisrgn(&pPrivate->SurfaceLocal, (HWND) -1))
|
|
{
|
|
WARNING("DCIBeginAccess - ResetVisRgn failed\n");
|
|
}
|
|
|
|
//
|
|
// The VisRgn has changed, and we can't be sure what window it
|
|
// was for. So we'll mark all WinWatches as having dirty VisRgns.
|
|
// This effect of this is that some of the WinWatches will have to
|
|
// re-download their clipping information when they don't really
|
|
// have to because their specific window has not changed.
|
|
//
|
|
// Note that the WinWatchLock must be held here.
|
|
//
|
|
|
|
for (pwatch = gpWinWatchList;
|
|
pwatch != NULL;
|
|
pwatch = pwatch->pWinWatchNext)
|
|
{
|
|
pwatch->changed = TRUE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&gcsWinWatchLock);
|
|
|
|
} while (LockData.ddRVal == DDERR_VISRGNCHANGED);
|
|
|
|
//
|
|
// 'Surface Lost' means that some sort of mode change occured, and
|
|
// we have to re-enable DirectDraw.
|
|
//
|
|
|
|
if (LockData.ddRVal == DDERR_SURFACELOST)
|
|
{
|
|
if (!DdReenableDirectDrawObject(&pPrivate->DirectDrawGlobal,
|
|
&NewMode))
|
|
{
|
|
//
|
|
// We're still in full-screen mode:
|
|
//
|
|
|
|
iRet = DCI_ERR_SURFACEISOBSCURED;
|
|
}
|
|
else
|
|
{
|
|
if (!bDisplayModeChanged(pPrivate))
|
|
{
|
|
//
|
|
// We switched back to the same mode. Now that we've re-enabled
|
|
// DirectDraw, we can try again:
|
|
//
|
|
|
|
bDestroySurface(pPrivate);
|
|
if (bCreateSurface(pPrivate) &&
|
|
DdResetVisrgn(&pPrivate->SurfaceLocal, (HWND) -1))
|
|
{
|
|
goto Try_Again;
|
|
}
|
|
else
|
|
{
|
|
WARNING("DCIBeginAccess - couldn't recreate surface.\n");
|
|
}
|
|
}
|
|
|
|
//
|
|
// We can't reenable the surface, perhaps because a resolution
|
|
// switch or colour depth change occured. Mark this surface as
|
|
// unusable -- the application will have to reinitialize:
|
|
//
|
|
|
|
pPrivate->SurfaceLost = TRUE;
|
|
iRet = DCI_FAIL_INVALIDSURFACE;
|
|
|
|
//
|
|
// Unmap the frame buffer now:
|
|
//
|
|
|
|
if (!bDestroySurface(pPrivate) ||
|
|
!DdDeleteDirectDrawObject(&pPrivate->DirectDrawGlobal))
|
|
{
|
|
WARNING("DCIBeginAccess - failed to delete surface.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (LockData.ddRVal == DD_OK)
|
|
{
|
|
//
|
|
// Return the pointer to the frame buffer in the DCI structure.
|
|
// We always return DCI_STATUS_POINTERCHANGED because it's possible
|
|
// that the Lock() call mapped the frame buffer to a different
|
|
// virtual address than it was previously.
|
|
//
|
|
|
|
lpSurface->wSelSurface = 0;
|
|
|
|
//
|
|
// DirectDraw has a goofy convention where it returns a pointer to
|
|
// the upper-left corner of the specified rectangle. We have to
|
|
// undo that for DCI:
|
|
//
|
|
|
|
lpSurface->dwOffSurface = (ULONG_PTR) LockData.lpSurfData
|
|
- (y * lpSurface->lStride)
|
|
- (x * (lpSurface->dwBitCount >> 3));
|
|
|
|
iRet = DCI_STATUS_POINTERCHANGED;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("DCIBeginAccess - exception caused by invalid surface pointer.\n");
|
|
return DCI_FAIL_GENERIC;
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciEndAccess
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
void
|
|
WINAPI
|
|
DCIEndAccess(
|
|
LPDCISURFACEINFO pdci
|
|
)
|
|
{
|
|
DDHAL_UNLOCKDATA UnlockData;
|
|
PDCIMAN_SURF pPrivate = ((PDCIMAN_SURF) pdci) - 1;
|
|
|
|
__try
|
|
{
|
|
if (!(pPrivate->SurfaceLost))
|
|
{
|
|
UnlockData.lpDD = &pPrivate->DirectDrawGlobal;
|
|
UnlockData.lpDDSurface = &pPrivate->SurfaceLocal;
|
|
|
|
//
|
|
// For the same reasons as stated in DCIBeginAccess, protect against
|
|
// two threads trying to unlock the same surface at the same time
|
|
// in kernel -- kernel would simply fail the call instead of waiting,
|
|
// and DCI apps won't expect that.
|
|
//
|
|
|
|
EnterCriticalSection(&gcsWinWatchLock);
|
|
|
|
pPrivate->DDSurfaceCallbacks.Unlock(&UnlockData);
|
|
|
|
LeaveCriticalSection(&gcsWinWatchLock);
|
|
|
|
if (UnlockData.ddRVal != DD_OK)
|
|
{
|
|
WARNING("DCIEndAccess - failed Unlock\n");
|
|
}
|
|
}
|
|
|
|
//
|
|
// The application shouldn't try to access the frame buffer after
|
|
// after having called EndAccess.
|
|
//
|
|
|
|
pdci->wSelSurface = 0;
|
|
pdci->dwOffSurface = 0;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("DCIEndAccess - exception caused by invalid surface pointer.\n");
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DciDestroy
|
|
*
|
|
* History:
|
|
\**************************************************************************/
|
|
|
|
void
|
|
WINAPI
|
|
DCIDestroy(
|
|
LPDCISURFACEINFO pdci
|
|
)
|
|
{
|
|
PDCIMAN_SURF pPrivate;
|
|
|
|
if (pdci != NULL)
|
|
{
|
|
pPrivate = ((PDCIMAN_SURF) pdci) - 1;
|
|
|
|
if (!(pPrivate->SurfaceLost))
|
|
{
|
|
DDHAL_DESTROYSURFACEDATA dsd;
|
|
|
|
dsd.lpDD = pPrivate->SurfaceGlobal.lpDD;
|
|
dsd.lpDDSurface = &pPrivate->SurfaceLocal;
|
|
dsd.ddRVal = DDERR_GENERIC;
|
|
dsd.DestroySurface = pPrivate->DDSurfaceCallbacks.DestroySurface;
|
|
|
|
if (!(pPrivate->DDSurfaceCallbacks.dwFlags & DDHAL_SURFCB32_DESTROYSURFACE) ||
|
|
(dsd.DestroySurface == NULL) ||
|
|
((*dsd.DestroySurface)(&dsd) != DDHAL_DRIVER_HANDLED) ||
|
|
!DdDeleteDirectDrawObject(&pPrivate->DirectDrawGlobal))
|
|
{
|
|
WARNING("DCIDestroy - failed to delete surface.\n");
|
|
}
|
|
}
|
|
|
|
LocalFree(pPrivate);
|
|
}
|
|
}
|
|
|
|
DCIRVAL
|
|
WINAPI
|
|
DCIDraw(
|
|
LPDCIOFFSCREEN pdci
|
|
)
|
|
{
|
|
return DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
DCIRVAL
|
|
WINAPI
|
|
DCISetClipList(
|
|
LPDCIOFFSCREEN pdci,
|
|
LPRGNDATA prd
|
|
)
|
|
{
|
|
return DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
DCIRVAL
|
|
WINAPI
|
|
DCISetDestination(
|
|
LPDCIOFFSCREEN pdci,
|
|
LPRECT dst,
|
|
LPRECT src
|
|
)
|
|
{
|
|
return DCI_FAIL_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
DCIRVAL
|
|
WINAPI
|
|
DCISetSrcDestClip(
|
|
LPDCIOFFSCREEN pdci,
|
|
LPRECT srcrc,
|
|
LPRECT destrc,
|
|
LPRGNDATA prd
|
|
)
|
|
{
|
|
return DCI_FAIL_UNSUPPORTED;
|
|
}
|