This page attempts to describe how the DCE (Distributed Computing Environment) system works in ReactOS.
The DCE system is defined in subsystems/win32/win32k/ntuser/windc.c and subsystems/win32/win32k/include/dce.h . Most of it was taken from Wine but it hasn't been kept in sync and ReactOS has made private changes.
The DCE's are kept in a global single linked list that starts with the FirstDce global var. It should be protected by the DceListLock mutex (but isn't).
There are three types of DCE's:
- For windows that have the CS_OWNDC style, they get their own so called private DC.
- For classes whose windows have the CS_CLASSDC style, they get a DC that is shared between these windows. This is not implemented yet.
- This encompasses two types actually: DC's that have been requested for windows that have neither CS_OWNDC or CS_CLASSDC (or by using DCX_CACHE with GetDCEx). When these are released, they stay DCE_CACHE_DC's, but now they do not really belong to a window anymore. A DC a program gets this way is called a common DC.
Windows supports these DC types:
- Generic device context
- For drawing on a device, bypassing the window manager (the device would most likely be a printer)
- Window device context
- For drawing on or in windows.
- Information context
- like the generic device context, but you can't use it to draw. You can use it to query a device for information (like the size of paper a printer supports, or the resolution a video driver supports)
- Memory device context
- like the generic device context, but draws into a piece of memory (a device independent or dependent bitmap) instead.
- Metafile device context
- Special device context for recording and playing back metafiles (wmf).
A DCE is created in different situations:
- A window having the CS_OWNDC style is created
- A window having the CS_CLASSDC style is created and the class does not have a DCE yet.
- A program requests a DC and the window doesn't have CS_OWNDC or CS_CLASSDC, or the program states that it wants one from the cache (DCX_CACHE).
If the program requests a DC from the cache, it must release it again using ReleaseDC. It is then cleared and put in the cache to be used again (unless it was requested with DCX_NORESETATTRS, which we don't handle too).
A DCE is released when:
- The program releases it using ReleaseDC (or something similar like EndPaint) and it's a common DC; nothing happens for the other types.
- It's attached to a window (by means of CS_OWNDC or similar) and the window is destroyed
- It was requested by a program for a window and the window is destroyed. This causes a warning, as the DC was leaked. This is a pretty serious error, especially if the code should run on Win9x because these systems only have 5 common DC's available, and will just refuse new ones if they have been used up.
Common DC's do not get destroyed when they are released, they go to the cache instead. The other ones are destroyed when they are no longer in use.
What is in a DCE:
- A pointer to the next one, for the single linked list.
- A handle to the DC this DCE is for.
- A handle to the window the DC is for.
- Another handle that isn't used anywhere
- A handle to a clip region
- A description of the type it is
- Some flags about the state of the DCE
- A handle to itself.
Some of the flags are:
- This DCE does not contain a DC
- This DCE is in use by a window
- Destroy the DC if it is released.
- Do not destroy the clip region
- BeginPaint is in effect (this is set by user32). Apparently this is only for making sure the clip region is destroyed with the DCE.
Some things are done by using hooks, I didn't find out how that works exactly.
The DCE contains a clip region that must be kept up-to-date when windows move or the z-order changes.
The way Windows handles the DC cache is mostly undocumented. The good news is that because of this, few applications use most of the DC features. The bad news is that it's hard to create a compatible implementation.