tags:

views:

70

answers:

2

I need a little help in defining the following Windows GDI type in C#. I have the data in the form of a byte[] in C#, and I need to somehow marshal or cast it as the following in C#.

This is the type:

http://java.freehep.org/vectorgraphics/apidocs/org/freehep/graphicsio/emf/gdi/PolyPolygon16.html

http://msdn.microsoft.com/en-us/library/cc230665%28PROT.10%29.aspx

Edit: I have been able to get this far, close but not quite:

                    UInt32 rectLeft = BitConverter.ToUInt32(dataArray, 0);
                UInt32 rectTop = BitConverter.ToUInt32(dataArray, 4);
                UInt32 rectRight = BitConverter.ToUInt32(dataArray, 8);
                UInt32 rectBottom = BitConverter.ToUInt32(dataArray, 12);
                UInt32 rectNumberOfPolygons = BitConverter.ToUInt32(dataArray, 16);
                // Number of points in each polygon
                int l_nIndex = 20;
                UInt32[] lengths = new UInt32[rectNumberOfPolygons];
                for (int i = 0; i < lengths.Length; i++)
                {
                    lengths[i] = BitConverter.ToUInt32(dataArray, l_nIndex);
                    l_nIndex += 4;
                }
                // Extract points
                foreach (int l_nPolygonLength in lengths)
                {
                    List<Point> l_lstPoints = new List<Point>();
                    for (int i = 0; i < l_nIndex + l_nPolygonLength; i++)
                    {
                        UInt16 pointX = BitConverter.ToUInt16(dataArray, l_nIndex);
                        UInt16 pointY = BitConverter.ToUInt16(dataArray, l_nIndex + 2);
                        l_lstPoints.Add(new Point((int)pointX, (int)pointY));
                        l_nIndex += 4;
                    }
                }
A: 

That seems to be the method signature of Windows GDI function (not a type). It's second argument is a pointer to an array of points, you want to have drawn. Third argument is a pointer to an array of integers specifying how many points there are in each polygon, and the last argument is the number of polygons.

I could not find a Windows GDI function exactly named PolyPolygon16 when searching on Google, but I did find this.

driis
Thank you for looking. Maybe this will help? http://stackoverflow.com/questions/1773953/gdi-c-marshal-type
GdiHelp
A: 

RectL Object:

public static Rectangle ReadRectangle32(this BinaryReader reader)
{
    // Left (4 bytes)
    int left = reader.ReadInt32();

    // Top (4 bytes)
    int top = reader.ReadInt32();

    // Right (4 bytes)
    int right = reader.ReadInt32();

    // Bottom (4 bytes)
    int bottom = reader.ReadInt32();

    return Rectangle.FromLTRB(left, top, right, bottom);
}

PointS Object:

public static Point ReadPoint16(this BinaryReader reader)
{
    // x (2 bytes)
    int x = reader.ReadUInt16();

    // y (2 bytes)
    int y = reader.ReadUInt16();

    return new Point(x, y);
}

EMR_POLYPOLYGON16 Record (without type and size):

public static PolyPolygon ReadPolyPolygon16(this BinaryReader reader)
{
    // Bounds (16 bytes)
    Rectangle bounds = reader.ReadRectangle32();

    // NumberOfPolygons (4 bytes)
    int numberOfPolygons = reader.ReadInt32();

    // Count (4 bytes)
    int count = reader.ReadInt32();

    // PolygonPointCount (variable):
    //      A NumberOfPolygons length array of 32-bit unsigned integers
    var polygonPointCount = new int[numberOfPolygons];
    for (int i = 0; i < polygonPointCount.Length; i++)
    {
        polygonPointCount[i] = reader.ReadInt32();
    }

    // aPoints (variable):
    //      A Count length array of WMF PointS objects
    var points = new Point[count];
    for (int i = 0; i < points.Length; i++)
    {
        points[i] = reader.ReadPoint16();
    }

    return new PolyPolygon(bounds, numberOfPolygons, polygonPointCount, points);
}

Usage:

byte[] buffer;
using (var stream = new MemoryStream(buffer))
using (var reader = new BinaryReader(stream))
{
    var polypolygon = reader.ReadPolyPolygon16();
}

(Untested)

dtb
That does indeed seem close. I added a hex dump of the byte[] above. The code here results in errors in most cases, and invalid data in others. I really wish I knew how you got so good at marshaling these types (referring to all of these posts you have helped me with). Have any other ideas on how to approach this one? Maybe the definition above is not correct? Thank you!
GdiHelp
Further detail that may help. count is coming up with incredibly high values most of the time (example: count 65535 int).
GdiHelp
I did some digging, and it looks like this may be the correct definition: http://msdn.microsoft.com/en-us/library/cc230665%28PROT.10%29.aspx Would you mind an example based on this one? Many thanks.
GdiHelp
Further details. Using this definition http://java.freehep.org/vectorgraphics/apidocs/org/freehep/graphicsio/emf/gdi/PolyPolygon16.htmland some code you showed in a previous questions I got this far:UInt32 rectLeft = BitConverter.ToUInt32(dataArray, 0); UInt32 rectTop = BitConverter.ToUInt32(dataArray, 4); UInt32 rectRight = BitConverter.ToUInt32(dataArray, 8); UInt32 rectBottom = BitConverter.ToUInt32(dataArray, 12); UInt32 rectNumberOfPolygons = BitConverter.ToUInt32(dataArray, 16);
GdiHelp
It's actually quite simple if you have the documentation. The documentation tells you which bytes have which meaning, how many bytes make up a field, and in which order the fields are stored in the byte array. I've added code that uses the definition you linked with some comments, so you can see how the documentation maps to the code.
dtb
I recommended you follow the pattern I've outlined by using a BinaryReader for reading the fields from the byte array. This way the only thing you have to worry about is to read the fields in the right order.
dtb
dtb: The binaryreader method is absolutely amazing. I will use it to prototype the other 30 or 40 emf record types I have to go through :)What you gave me is just about perfect. At the end of each call, the binaryreader is at the end of the stream, so it read all the data without going over bounds. My only issue is some points are a bit "off". What I mean is say the dimensions are 200x200. a number of Points will be within bounds (4,5 4,25), then there will be a bunch where the Point is way off, example 4,65332. The Y component is far too high, is this because it is being read as a UInt16?
GdiHelp
I tried using: // x (2 bytes) int x = reader.ReadInt16(); // y (2 bytes) int y = reader.ReadInt16(); This resulted in alot smaller numbers, but some negative numbers which were not correct either. Any ideas?
GdiHelp
Another update. I tested using ReadInt16(), and whats interesting is the partial image i re-create is upside down and and offset from center a bit. This is a bit puzzling. Would it help is I provided a simple way to invoke the EnumerateMetafileProc i am using and an example EMF image file? Thanks for working on one of the longest StackOverflow questions.
GdiHelp
Ok, I think your code with the change to ReadInt16 is perfect. Somehow 0,0 represents the exact middle of the canvas, which is just strange. This must be a EMF format thing. I will research that more. Thanks for going above the normal call of duty here.
GdiHelp
Update, I fixed the offset issue, now i can draw the entire image. Now I am trying to figure out why it is upside down and backwards :)
GdiHelp