Enumerate the records in a metafile in C#


The example Display a Windows metafile (wmf) in C# shows how to draw a metafile. This example shows how to enumerate the records in the metafile that represent its drawing commands and draw only some of them.

When you enter a metafile’s name and click the Enumerate button, the following code lists the metafile’s records in the ListBox on the program’s left.

// Enumerate the metafile to list its records.
private void btnEnumerate_Click(object sender, EventArgs e)
    // Clear the record list.

    // Clear the PictureBox.
    Bitmap bm = new Bitmap(picResults.ClientSize.Width,
    using (Graphics gr = Graphics.FromImage(bm))
        picResults.Image = bm;

    // Enumerate the metafile records.
        Metafile mf = new Metafile(txtFileName.Text);

            mf, new PointF(0, 0),

        btnDraw.Enabled = true;
    catch (Exception ex)

The program clears the ListBox, makes a Bitmap to fit the drawing area, and clears it. It then opens the metafile.

Normally you use the Graphics class to draw a metafile. That class provides the EnumerateMetafile method, so the program creates a Graphics object and calls EnumerateMetafile, passing it the metafile, the point that the metafile should use as an origin (which isn’t really used while we are just enumerating the records), and a callback method. The EnumerateMetafile method calls the callback method ListRecords for each metafile record.

The following code shows the ListRecords method.

// Add this record to the list.
private bool ListRecords(EmfPlusRecordType record_type, int flags,
    int data_size, IntPtr data, PlayRecordCallback callback_data)
    return true;

This code simply adds each metafile record’s name to the program’s ListBox. It returns true to make the enumeration continue. (If the method returned false, the enumeration would stop before listing all of the records.)

After you list the records, you can select some of them in the ListBox. Then when you click the Draw button, the program again enumerates the metafile’s records, this time using the following DrawRecords method as the callback method.

private int NextRecordNumber;

// Draw the record if it is not selected in the list.
private bool DrawRecords(EmfPlusRecordType record_type, int flags,
    int data_size, IntPtr data, PlayRecordCallback callback_data)
    // See if this record is selected.
    if (lstRecords.SelectedIndices.Contains(NextRecordNumber))
        Console.WriteLine("Skipping " + record_type.ToString());
        return true;

    byte[] data_array = null;
    if (! data.Equals(IntPtr.Zero))
        // Copy the unmanaged record data into a managed
        // byte buffer that we can pass to PlayRecord.
        data_array = new byte[data_size];
        Marshal.Copy(data, data_array, 0, data_size);

    // Play the record.
    TheMetafile.PlayRecord(record_type, flags,
        data_size, data_array);

    // Continue the enumeration.
    return true;

The NextRecordNumber variable tracks the index of the next metafile record. The DrawRecords method starts by checking whether that record number is selected in the ListBox. If the record is selected, the method displays a message in the console window and skips drawing it.

If the metafile record is not selected, the code uses the metafile’s PlayMetafile method to draw the current metafile record. (The NextRecordNumber and TheMetafile variables are initialized in the code that calls EnumerateMetafile.)

This lets you explore a metafile to find out what records it contains.

The epitrochoid used by this example contains almost 900 records, most of which are used to draw the shape. If you want to see a noticeable change in the image, you needd to select a lot of drawing records in the list box.

Download Example   Follow me on Twitter   RSS feed   Donate

This entry was posted in algorithms, graphics and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.