views:

95

answers:

0

I have an application that works with Enhanced Metafiles.

I am able to create them, save them to disk as .emf and load them again no problem.

I do this by using the gdi32.dll methods and the DLLImport attribute.

However, to enable Version Tolerant Serialization I want to save the metafile in an object along with other data.

This essentially means that I need to serialize the metafile data as a byte array and then deserialize it again in order to reconstruct the metafile.

The problem I have is that the deserialized data would appear to be corrupted in some way, since the method that I use to reconstruct the Metafile raises a "Parameter not valid exception".

At the very least the pixel format and resolutions have changed.

Code use is below.

 [DllImport("gdi32.dll")]
    public static extern uint GetEnhMetaFileBits(IntPtr hemf, uint cbBuffer, byte[] lpbBuffer);
    [DllImport("gdi32.dll")]
    public static extern IntPtr SetEnhMetaFileBits(uint cbBuffer, byte[] lpBuffer);
    [DllImport("gdi32.dll")]
    public static extern bool DeleteEnhMetaFile(IntPtr hemf);

The application creates a metafile image and passes it to the method below.

    private byte[] ConvertMetaFileToByteArray(Image image)
    {
        byte[] dataArray = null;

        Metafile mf = (Metafile)image;

        IntPtr enhMetafileHandle = mf.GetHenhmetafile();

        uint bufferSize = GetEnhMetaFileBits(enhMetafileHandle, 0, null);


        if (enhMetafileHandle != IntPtr.Zero)
        {
            dataArray = new byte[bufferSize];

            GetEnhMetaFileBits(enhMetafileHandle, bufferSize, dataArray);
        }

        DeleteEnhMetaFile(enhMetafileHandle);

        return dataArray;
    }

At this point the dataArray is inserted into an object and serialized using a BinaryFormatter.

The saved file is then deserialized again using a BinaryFormatter and the dataArray retrieved from the object.

The dataArray is then used to reconstruct the original Metafile using the following method.

    public static Image ConvertByteArrayToMetafile(byte[] data)
    {
        Metafile mf = null;

        try
        {
            IntPtr hemf = SetEnhMetaFileBits((uint)data.Length, data);

            mf = new Metafile(hemf, true);

        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message);
        }

        return (Image)mf;
    }

The reconstructed metafile is then saved saved to disk as a .emf (Model) at which point it can be accessed by the Presenter for display.

    private static void SaveFile(Image image, String filepath)
    {
        try
        {
            byte[] buffer = ConvertMetafileToByteArray(image);

            File.WriteAllBytes(filepath, buffer); //will overwrite file if it exists
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message);
        }

    }

The problem is that the save to disk fails. If this same method is used to save the original Metafile before it is serialized everything is OK. So something is happening to the data during serialization/deserializtion.

Indeed if I check the Metafile properties in the debugger I can see that the ImageFlags, PropertyID, resolution and pixelformats change.

Original Format32bppRgb changes to Format32bppArgb

Original Resolution 81 changes to 96

I've trawled though google and SO and this has helped me get this far but Im now stuck.

Does any one have enough experience with Metafiles / serialization to help..?

EDIT: If I serialize/deserialize the byte array directly (without embedding in another object) I get the same problem.