mirror of
https://github.com/reactos/wine.git
synced 2025-01-12 06:31:15 +00:00
d471965c9e
Mon Dec 11 19:08:55 1995 Alexandre Julliard <julliard@sunsite.unc.edu> * [misc/lstr.c] Replaced wine_strncpy() by a 32-bit version of lstrcpyn(), since they do the same job. * [tools/build.c] Fixed __attribute__((stdcall)) to make it compile with gcc versions under 2.7. Doesn't mean it will run OK though... Sat Dec 09 13:22:58 1995 Cameron Heide <heide@ee.ualberta.ca> * [include/kernel32.h] [include/winerror.h] Added file attribute definitions and more error codes. * [win32/error.c] Added some rudimentary errno-to-Win32 error conversion code. * [win32/file.c] Added to GetFileInformationByHandle, filled in some known error codes, and switched to dprintf_win32. * [win32/time.c] Added GetLocalTime. Fri Dec 8 14:37:39 1995 Jim Peterson <jspeter@birch.ee.vt.edu> * [controls/combo.c] Converted functions of the type LONG _(HWND,WORD,LONG) to the type LRESULT _(HWND,WPARAM,LPARAM) where needed. * [include/libres.h] Restructured libres prototypes to closer match the windows API. * [include/windows.h] Changed several API prototypes' parameter types from 'short' to INT, which is #defined as short in the emulator, but is a normal int in WINELIB32. Also changed SEGPTR from DWORD to void* when WINELIB32. (This creates a lot of warnings at library-compile time, but less warnings at app-compile time. I'll remove the warnings soon.) * [loader/resource.c] Fixed parameter mismatch in call to LIBRES_FindResource(). Changed various implementations of the LIBRES_* API functions. * [loader/signal.c] Deleted local 'i' from win_fault(), since it was unused. * [objects/bitblt.c] Mirrored changes to include/windows.h mentioned above. * [toolkit/hello3.c] Changed LoadMenuIndirect() call to LoadMenu() to test the new resource registration technique. * [toolkit/libres.c] Removed definition of 'struct resource' and fixed bugs in the resource implementation. Implemented LIBRES_FindResource. * [windows/graphics.c] Mirrored changes to include/windows.h mentioned above. Thu Dec 7 23:15:56 1995 Martin von Loewis <loewis@informatik.hu-berlin.de> * [controls/edit.c] LOCAL_HeapExists: Changed parameter to HANDLE. For WineLib, return true * [controls/listbox.c] CreateListBoxStruct: Initialize HeapSel to 0 for WineLib * [include/listbox.h] change HeapSel from WORD to HANDLE * [include/resource.h][rc/winerc.c] struct ResourceTable: removed struct resource: moved to header file autoregister resources if supported by compiler * [memory/local.h] LOCAL_GetHeap: expect HANDLE rather than WORD * [toolkit/Makefile.in] Add ALLCFLAGS to make hello3 * [toolkit/heap.c] LocalFree, HEAP_Free: handle 0 parameter gracefully Wed Dec 06 15:34:23 1995 Greg Cooper <cooper@ima-inc.com> * [misc/winsocket.c] Fixed the msgsnd and msgrcv errors that winsock programs get. Wed Dec 06 12:47:23 MET 1995 Sven Verdoolaege <skimo@dns.ufsia.ac.be> * [if1632/kernel.spec] Fixed _hread and _hwrite return type * [if1632/relay32.c] [loader/pe_image.c] Hacked loading of PE-dll's in * [win32/advapi.c] Added stubs for RegCreateKeyEx, RegSetValueEx, RegQueryValueEx * [win32/file.c] Added stubs for OpenFileMapping, CreateFileMapping, MapViewOfFileEx * [win32/process.c] Added stubs for CreateMutexA, ReleaseMutex, CreateEventA, WaitForSingleObject, DuplicateHandle, GetCurrentProcess Mon Dec 04 13:06:37 1995 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de> * [include/wine.h] [misc/lstr.c] Define wine_strncpy(). This function does not pad the buffer with zeroes like GNU strncpy(), which might break some Windows programs that pass bogus size arguments. * [loader/module.c]: GetModuleFileName(), [misc/commdlg.c]: GetFileTitle(), [misc/keyboard.c], [misc/lstr.c]: lstrcpyn(), [misc/ole2nls.c], [misc/profile.c], [multimedia/mcistring.c], [multimedia/mmsystem.c], [objects/font.c]: Use wine_strncpy() where strings are returned to Windows programs. * [objects/metafile.c] PlayMetafile(): Clear the handle table before using it. * [misc/shell.c] [misc/main.c] Rename SHELL_RegCheckForRoot() to SHELL_Init() and call it from main(). * [misc/profile.c] load(): Need to handle comments. * [toolkit/libres.c] Make it compile. * [windows/nonclient.c] Use MAKE_SEGPTR macro in two places where a user heap block used to be allocated instead. Sat Dec 02 16:43:43 1995 Ramon Garcia <ramon@ie3.clubs.etsit.upm.es> * [windows/winpos.c] In function SetWindowPos: do not redraw the parent of a window if the specified window is placed on the top. This avoids that ShowWindow(hwnd,1) hides hwnd instead of showing it. Sat Dec 02 11:00:00 1995 Alex Korobka <alex@phm30.pharm.sunysb.edu> * [windows/scroll.c] Now it can scroll children along with the client region of parent window. Tried to optimize update region calculation. * [windows/mdi.c] ScrollChildren function, more other features added. Basically a rewrite. * [windows/winpos.c] [windows/focus.c] Reimplemented window activation and focus handling. * [windows/nonclient.c] Added new flag WIN_NCACTIVATED. * [windows/message.c] [loader/task.c] Small changes (to maintain linked list of message queues). Wed Nov 29 15:51:48 1995 Daniel Schepler <daniel@shep13.wustl.edu> * [include/options.h] [misc/main.c] [windows/defwnd.c] [windows/event.c] [windows/nonclient.c] [windows/win.c] [Wine.man] Implemented a -managed option to replace the standard Windows frame of top-level windows with the window manager's decorations. If a top-level window makes its own frame, this will still show up, inside the window manager decorations (I believe ctl3dv2.dll would do this, although I can't test this).
451 lines
13 KiB
C
451 lines
13 KiB
C
/*
|
|
* USER DCE functions
|
|
*
|
|
* Copyright 1993 Alexandre Julliard
|
|
*
|
|
static char Copyright[] = "Copyright Alexandre Julliard, 1993";
|
|
*/
|
|
|
|
#include "dce.h"
|
|
#include "class.h"
|
|
#include "win.h"
|
|
#include "gdi.h"
|
|
#include "user.h"
|
|
#include "sysmetrics.h"
|
|
#include "stddebug.h"
|
|
/* #define DEBUG_DC */
|
|
#include "debug.h"
|
|
|
|
#define NB_DCE 5 /* Number of DCEs created at startup */
|
|
|
|
static HANDLE firstDCE = 0;
|
|
static HDC defaultDCstate = 0;
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_AllocDCE
|
|
*
|
|
* Allocate a new DCE.
|
|
*/
|
|
HANDLE DCE_AllocDCE( DCE_TYPE type )
|
|
{
|
|
DCE * dce;
|
|
HANDLE handle = USER_HEAP_ALLOC( sizeof(DCE) );
|
|
if (!handle) return 0;
|
|
dce = (DCE *) USER_HEAP_LIN_ADDR( handle );
|
|
if (!(dce->hdc = CreateDC( "DISPLAY", NULL, NULL, NULL )))
|
|
{
|
|
USER_HEAP_FREE( handle );
|
|
return 0;
|
|
}
|
|
dce->hwndCurrent = 0;
|
|
dce->type = type;
|
|
dce->inUse = (type != DCE_CACHE_DC);
|
|
dce->xOrigin = 0;
|
|
dce->yOrigin = 0;
|
|
dce->hNext = firstDCE;
|
|
firstDCE = handle;
|
|
return handle;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_FreeDCE
|
|
*/
|
|
void DCE_FreeDCE( HANDLE hdce )
|
|
{
|
|
DCE * dce;
|
|
HANDLE *handle = &firstDCE;
|
|
|
|
if (!(dce = (DCE *) USER_HEAP_LIN_ADDR( hdce ))) return;
|
|
while (*handle && (*handle != hdce))
|
|
{
|
|
DCE * prev = (DCE *) USER_HEAP_LIN_ADDR( *handle );
|
|
handle = &prev->hNext;
|
|
}
|
|
if (*handle == hdce) *handle = dce->hNext;
|
|
DeleteDC( dce->hdc );
|
|
USER_HEAP_FREE( hdce );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_Init
|
|
*/
|
|
void DCE_Init()
|
|
{
|
|
int i;
|
|
HANDLE handle;
|
|
DCE * dce;
|
|
|
|
for (i = 0; i < NB_DCE; i++)
|
|
{
|
|
if (!(handle = DCE_AllocDCE( DCE_CACHE_DC ))) return;
|
|
dce = (DCE *) USER_HEAP_LIN_ADDR( handle );
|
|
if (!defaultDCstate) defaultDCstate = GetDCState( dce->hdc );
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_GetVisRect
|
|
*
|
|
* Calc the visible rectangle of a window, i.e. the client or
|
|
* window area clipped by the client area of all ancestors.
|
|
* Return FALSE if the visible region is empty.
|
|
*/
|
|
static BOOL DCE_GetVisRect( WND *wndPtr, BOOL clientArea, RECT *lprect )
|
|
{
|
|
int xoffset, yoffset;
|
|
|
|
*lprect = clientArea ? wndPtr->rectClient : wndPtr->rectWindow;
|
|
xoffset = lprect->left;
|
|
yoffset = lprect->top;
|
|
|
|
if (!(wndPtr->dwStyle & WS_VISIBLE) || (wndPtr->flags & WIN_NO_REDRAW))
|
|
{
|
|
SetRectEmpty( lprect ); /* Clip everything */
|
|
return FALSE;
|
|
}
|
|
|
|
while (wndPtr->hwndParent)
|
|
{
|
|
WND *parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
|
|
if (!(parentPtr->dwStyle & WS_VISIBLE) ||
|
|
(parentPtr->flags & WIN_NO_REDRAW) ||
|
|
(parentPtr->dwStyle & WS_ICONIC))
|
|
{
|
|
SetRectEmpty( lprect ); /* Clip everything */
|
|
return FALSE;
|
|
}
|
|
xoffset += parentPtr->rectClient.left;
|
|
yoffset += parentPtr->rectClient.top;
|
|
OffsetRect( lprect, parentPtr->rectClient.left,
|
|
parentPtr->rectClient.top );
|
|
|
|
/* Warning!! we assume that IntersectRect() handles the case */
|
|
/* where the destination is the same as one of the sources. */
|
|
if (!IntersectRect( lprect, lprect, &parentPtr->rectClient ))
|
|
return FALSE; /* Visible rectangle is empty */
|
|
wndPtr = parentPtr;
|
|
}
|
|
OffsetRect( lprect, -xoffset, -yoffset );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_ClipWindows
|
|
*
|
|
* Go through the linked list of windows from hwndStart to hwndEnd,
|
|
* removing from the given region the rectangle of each window offset
|
|
* by a given amount. The new region is returned, and the original one
|
|
* is destroyed. Used to implement DCX_CLIPSIBLINGS and
|
|
* DCX_CLIPCHILDREN styles.
|
|
*/
|
|
static HRGN DCE_ClipWindows( HWND hwndStart, HWND hwndEnd,
|
|
HRGN hrgn, int xoffset, int yoffset )
|
|
{
|
|
HRGN hrgnTmp, hrgnNew;
|
|
WND *wndPtr;
|
|
|
|
if (!hwndStart) return hrgn;
|
|
for (; hwndStart != hwndEnd; hwndStart = wndPtr->hwndNext)
|
|
{
|
|
hrgnTmp = hrgnNew = 0;
|
|
wndPtr = WIN_FindWndPtr( hwndStart );
|
|
if (!(wndPtr->dwStyle & WS_VISIBLE)) continue;
|
|
if (!(hrgnTmp = CreateRectRgn( 0, 0, 0, 0 ))) break;
|
|
if (!(hrgnNew = CreateRectRgn( wndPtr->rectWindow.left + xoffset,
|
|
wndPtr->rectWindow.top + yoffset,
|
|
wndPtr->rectWindow.right + xoffset,
|
|
wndPtr->rectWindow.bottom + yoffset )))
|
|
break;
|
|
if (!CombineRgn( hrgnTmp, hrgn, hrgnNew, RGN_DIFF )) break;
|
|
DeleteObject( hrgn );
|
|
DeleteObject( hrgnNew );
|
|
hrgn = hrgnTmp;
|
|
}
|
|
if (hwndStart != hwndEnd) /* something went wrong */
|
|
{
|
|
if (hrgnTmp) DeleteObject( hrgnTmp );
|
|
if (hrgnNew) DeleteObject( hrgnNew );
|
|
if (hrgn) DeleteObject( hrgn );
|
|
return 0;
|
|
}
|
|
return hrgn;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_GetVisRgn
|
|
*
|
|
* Return the visible region of a window, i.e. the client or window area
|
|
* clipped by the client area of all ancestors, and then optionally
|
|
* by siblings and children.
|
|
*/
|
|
HRGN DCE_GetVisRgn( HWND hwnd, WORD flags )
|
|
{
|
|
RECT rect;
|
|
HRGN hrgn;
|
|
int xoffset, yoffset;
|
|
WND *wndPtr = WIN_FindWndPtr( hwnd );
|
|
|
|
/* Get visible rectangle and create a region with it */
|
|
|
|
if (!DCE_GetVisRect( wndPtr, !(flags & DCX_WINDOW), &rect ))
|
|
{
|
|
return CreateRectRgn( 0, 0, 0, 0 ); /* Visible region is empty */
|
|
}
|
|
if (!(hrgn = CreateRectRgnIndirect( &rect ))) return 0;
|
|
|
|
/* Clip all children from the visible region */
|
|
|
|
if (flags & DCX_CLIPCHILDREN)
|
|
{
|
|
if (flags & DCX_WINDOW)
|
|
{
|
|
xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
|
|
yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
|
|
}
|
|
else xoffset = yoffset = 0;
|
|
hrgn = DCE_ClipWindows( wndPtr->hwndChild, 0, hrgn, xoffset, yoffset );
|
|
if (!hrgn) return 0;
|
|
}
|
|
|
|
/* Clip siblings placed above this window */
|
|
|
|
if (flags & DCX_WINDOW)
|
|
{
|
|
xoffset = -wndPtr->rectWindow.left;
|
|
yoffset = -wndPtr->rectWindow.top;
|
|
}
|
|
else
|
|
{
|
|
xoffset = -wndPtr->rectClient.left;
|
|
yoffset = -wndPtr->rectClient.top;
|
|
}
|
|
if (flags & DCX_CLIPSIBLINGS)
|
|
{
|
|
hrgn = DCE_ClipWindows( GetWindow( wndPtr->hwndParent, GW_CHILD ),
|
|
hwnd, hrgn, xoffset, yoffset );
|
|
if (!hrgn) return 0;
|
|
}
|
|
|
|
/* Clip siblings of all ancestors that have the WS_CLIPSIBLINGS style */
|
|
|
|
while (wndPtr->dwStyle & WS_CHILD)
|
|
{
|
|
hwnd = wndPtr->hwndParent;
|
|
wndPtr = WIN_FindWndPtr( hwnd );
|
|
xoffset -= wndPtr->rectClient.left;
|
|
yoffset -= wndPtr->rectClient.top;
|
|
hrgn = DCE_ClipWindows( GetWindow( wndPtr->hwndParent, GW_CHILD ),
|
|
hwnd, hrgn, xoffset, yoffset );
|
|
if (!hrgn) return 0;
|
|
}
|
|
return hrgn;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_SetDrawable
|
|
*
|
|
* Set the drawable, origin and dimensions for the DC associated to
|
|
* a given window.
|
|
*/
|
|
static void DCE_SetDrawable( WND *wndPtr, DC *dc, WORD flags )
|
|
{
|
|
if (!wndPtr) /* Get a DC for the whole screen */
|
|
{
|
|
dc->w.DCOrgX = 0;
|
|
dc->w.DCOrgY = 0;
|
|
dc->u.x.drawable = rootWindow;
|
|
XSetSubwindowMode( display, dc->u.x.gc, IncludeInferiors );
|
|
}
|
|
else
|
|
{
|
|
if (flags & DCX_WINDOW)
|
|
{
|
|
dc->w.DCOrgX = wndPtr->rectWindow.left;
|
|
dc->w.DCOrgY = wndPtr->rectWindow.top;
|
|
}
|
|
else
|
|
{
|
|
dc->w.DCOrgX = wndPtr->rectClient.left;
|
|
dc->w.DCOrgY = wndPtr->rectClient.top;
|
|
}
|
|
while (!wndPtr->window)
|
|
{
|
|
wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
|
|
dc->w.DCOrgX += wndPtr->rectClient.left;
|
|
dc->w.DCOrgY += wndPtr->rectClient.top;
|
|
}
|
|
dc->w.DCOrgX -= wndPtr->rectWindow.left;
|
|
dc->w.DCOrgY -= wndPtr->rectWindow.top;
|
|
dc->u.x.drawable = wndPtr->window;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetDCEx (USER.359)
|
|
*/
|
|
/* Unimplemented flags: DCX_LOCKWINDOWUPDATE
|
|
*/
|
|
HDC GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
|
|
{
|
|
HANDLE hdce;
|
|
HRGN hrgnVisible;
|
|
HDC hdc = 0;
|
|
DCE * dce;
|
|
DC * dc;
|
|
WND * wndPtr;
|
|
|
|
if (hwnd)
|
|
{
|
|
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
|
|
}
|
|
else wndPtr = NULL;
|
|
|
|
if (flags & DCX_USESTYLE)
|
|
{
|
|
/* Set the flags according to the window style. */
|
|
/* Not sure if this is the real meaning of the DCX_USESTYLE flag... */
|
|
flags &= ~(DCX_CACHE | DCX_CLIPCHILDREN |
|
|
DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
|
|
if (wndPtr)
|
|
{
|
|
if (!(WIN_CLASS_STYLE(wndPtr) & (CS_OWNDC | CS_CLASSDC)))
|
|
flags |= DCX_CACHE;
|
|
if (WIN_CLASS_STYLE(wndPtr) & CS_PARENTDC) flags |= DCX_PARENTCLIP;
|
|
if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN;
|
|
if (wndPtr->dwStyle & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
|
|
}
|
|
else flags |= DCX_CACHE;
|
|
}
|
|
|
|
/* Can only use PARENTCLIP on child windows */
|
|
if (!wndPtr || !(wndPtr->dwStyle & WS_CHILD)) flags &= ~DCX_PARENTCLIP;
|
|
|
|
/* Whole window DC implies using cache DC and not clipping children */
|
|
if (flags & DCX_WINDOW) flags = (flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
|
|
|
|
if (flags & DCX_CACHE)
|
|
{
|
|
for (hdce = firstDCE; (hdce); hdce = dce->hNext)
|
|
{
|
|
if (!(dce = (DCE *) USER_HEAP_LIN_ADDR( hdce ))) return 0;
|
|
if ((dce->type == DCE_CACHE_DC) && (!dce->inUse)) break;
|
|
}
|
|
}
|
|
else hdce = wndPtr->hdce;
|
|
|
|
if (!hdce) return 0;
|
|
dce = (DCE *) USER_HEAP_LIN_ADDR( hdce );
|
|
dce->hwndCurrent = hwnd;
|
|
dce->inUse = TRUE;
|
|
hdc = dce->hdc;
|
|
|
|
/* Initialize DC */
|
|
|
|
if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
|
|
|
|
DCE_SetDrawable( wndPtr, dc, flags );
|
|
if (hwnd)
|
|
{
|
|
if (flags & DCX_PARENTCLIP) /* Get a VisRgn for the parent */
|
|
{
|
|
WND *parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
|
|
DWORD newflags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
|
|
DCX_WINDOW);
|
|
if (parentPtr->dwStyle & WS_CLIPSIBLINGS)
|
|
newflags |= DCX_CLIPSIBLINGS;
|
|
hrgnVisible = DCE_GetVisRgn( wndPtr->hwndParent, newflags );
|
|
if (flags & DCX_WINDOW)
|
|
OffsetRgn( hrgnVisible, -wndPtr->rectWindow.left,
|
|
-wndPtr->rectWindow.top );
|
|
else OffsetRgn( hrgnVisible, -wndPtr->rectClient.left,
|
|
-wndPtr->rectClient.top );
|
|
}
|
|
else hrgnVisible = DCE_GetVisRgn( hwnd, flags );
|
|
}
|
|
else /* Get a VisRgn for the whole screen */
|
|
{
|
|
hrgnVisible = CreateRectRgn( 0, 0, SYSMETRICS_CXSCREEN,
|
|
SYSMETRICS_CYSCREEN);
|
|
}
|
|
|
|
/* Intersect VisRgn with the given region */
|
|
|
|
if ((flags & DCX_INTERSECTRGN) || (flags & DCX_EXCLUDERGN))
|
|
{
|
|
HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
|
|
if (hrgn)
|
|
{
|
|
CombineRgn( hrgn, hrgnVisible, hrgnClip,
|
|
(flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
|
|
DeleteObject( hrgnVisible );
|
|
hrgnVisible = hrgn;
|
|
}
|
|
}
|
|
SelectVisRgn( hdc, hrgnVisible );
|
|
DeleteObject( hrgnVisible );
|
|
|
|
dprintf_dc(stddeb, "GetDCEx("NPFMT","NPFMT",0x%lx): returning "NPFMT"\n",
|
|
hwnd, hrgnClip, flags, hdc);
|
|
return hdc;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetDC (USER.66)
|
|
*/
|
|
HDC GetDC( HWND hwnd )
|
|
{
|
|
return GetDCEx( hwnd, 0, DCX_USESTYLE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetWindowDC (USER.67)
|
|
*/
|
|
HDC GetWindowDC( HWND hwnd )
|
|
{
|
|
int flags = DCX_CACHE | DCX_WINDOW;
|
|
if (hwnd)
|
|
{
|
|
WND * wndPtr;
|
|
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
|
|
/* if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN; */
|
|
if (wndPtr->dwStyle & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
|
|
}
|
|
return GetDCEx( hwnd, 0, flags );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ReleaseDC (USER.68)
|
|
*/
|
|
int ReleaseDC( HWND hwnd, HDC hdc )
|
|
{
|
|
HANDLE hdce;
|
|
DCE * dce = NULL;
|
|
|
|
dprintf_dc(stddeb, "ReleaseDC: "NPFMT" "NPFMT"\n", hwnd, hdc );
|
|
|
|
for (hdce = firstDCE; (hdce); hdce = dce->hNext)
|
|
{
|
|
if (!(dce = (DCE *) USER_HEAP_LIN_ADDR( hdce ))) return 0;
|
|
if (dce->inUse && (dce->hdc == hdc)) break;
|
|
}
|
|
if (!hdce) return 0;
|
|
|
|
if (dce->type == DCE_CACHE_DC)
|
|
{
|
|
SetDCState( dce->hdc, defaultDCstate );
|
|
dce->inUse = FALSE;
|
|
}
|
|
return 1;
|
|
}
|