[ros-dev] Gdi function Polygon

Timo Kreuzer timo.kreuzer at web.de
Fri Dec 1 03:45:23 CET 2006


Hi,

Recently I have started reading Feng Yuan - Windows Graphics Programming 
Win32 GDI and found that this is a very interesting part of Windows / 
ReactOS I'd like to take a closer look to.
I started to have a look at this when I noticed 2 things, that made my 
desk.cpl don't work correctly in ROS:

1.) SetDCPenColor is not implemented (I am currently working on a 
usermode implemenatation, I have finished GetDCPenColor, GetDCBrushColor 
is the same, Set... will follow soon.)

2.) Polygon() didn't work as expected. I used it to draw a tiny triangle 
on a button, but it doesn't look correct. I first thought it was because 
the triangle was simply too small (didn't show the lowest pixel), but it 
was because it is redirected to NtGdiPolygon. (instead of calling 
NtGdiPolyPolyDraw, wich is the way it works in windows. NtGdiPolygon 
doesn't seem to exist in Windows, so it seems it's currently only a 
Kernelmode implementation of Polygon and NtGdiPolyPolyDraw seems not to 
be implemented in ROS yet).
Polygon is exspected to automatically close the polygon, but 
NtGdiPolygon doesn't do this. I will have a closer look on this later 
and hope I can fix this. My questions:
Is there a reason it doesn't do it? Should the closing of the Polygon 
(simply by adding the first coordinates at the end?) be done in the 
usermode function (wich is not existing yet) or in the current 
implementation in win32k?

Looking at the gdi code I found out that some things (handle validation 
for example) seem to be different than in windows. F.e. the reuse 
counter seems to be ignored. I have written a small GdiTest app to 
analyse the diffences between Win and ROS (General app is ready, I will 
write test functions soon, maybe tomorrow) . I'll start by writing some 
test cases, that I think might fail on ROS. If there's someone who likes 
to help me writing tests I'd really appreaciate that, just let me know.

Then there's another thing that I thought about: Windows has one list of 
gdiobjects shared between kernel and all processes, although handles are 
only valid for the process that has created them (only Stockobjects are 
global). That seems to be a bad idea, I didn't try it yet, but what if a 
usermode app zeroes out the complete gdi handle table? I guess Windows 
would crash. And there might be more dangoerous risks, because of that. 
So why is the table not implemented locally?

Some thoughts:
Global handle list:
 + less memory needed
 - big chance of crashing windows by usermode apps

Local handle list
 - more memory needed
 + better chance of paging the memory (global list would never be paged 
as it is always in use)
 + no chance for a user app to crash windows or crash other apps by 
messing up the handle table
 + no more need to veryfy the process member in the handle table entry

A shared memory section seems to be a real risky thing. It's big enough 
to put binary data there and it might be possible to make another 
process with higher privaliges execute that code.I first thought of the 
DC's AbortProc, but that is probaly handled by the kernel to not exceed 
user limits(?).

Implementing the handle table locally would not beak any APIs. Only some 
system apps that use the GdiQueryTable and directly use the table would 
experience a slightly different behaviour: Only locally created handles 
would be accessable. Would there be a problem doing that?

At last my usermode implementation of GetDCPenColor, I would like some 
feedback:

#define GDI_HANDLE_UPPER_MASK 0xffff0000
#define GDI_HANDLE_GET_UPPER(h)     \
    (((ULONG_PTR)(h)) & GDI_HANDLE_UPPER_MASK)

COLORREF
GetDCPenColor(HDC hDC)
{
   PGDI_TABLE_ENTRY pEntry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
   if(pEntry->KernelData != NULL)
   {
      ULONG Upper = GDI_HANDLE_GET_UPPER(hGdiObj)
      if ( Upper == GDI_HANDLE_GET_UPPER(pEntry->Type)
           && GDI_HANDLE_GET_TYPE(Upper) == GDI_OBJECT_TYPE_DC )
      {
         if((HANDLE)((ULONG_PTR)pEntry->ProcessId & ~0x1) == 
CurrentProcessId)
         {
            DC_ATTR* pDCData = (DC_ATTR*)pEntry->UserData
            if(pDCData)
            {
               return pDCData->crPenClr;
            }
         }
      }
   }
   return CLR_INVALID;
}

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.reactos.org/pipermail/ros-dev/attachments/20061201/4f0940f5/attachment.html 


More information about the Ros-dev mailing list