A few days ago when I was building the MS-OLEDS file for AutoCAD, I needed to create a Metafile as part of it. However, I encountered some small problems when using the built-in API.

The Problem with Built-in API


In System.Drawing.Imaging has a Metafile Class that allows us do a sequence of graphics operations on it.Here is my code and the test file in the HEX editor.

 public static void GenerateMetafile(Image image, string filePath)
 {
     Metafile metafile = null;
     using (Graphics graphics = Graphics.FromImage(image))
     {
         var hdc = graphics.GetHdc();
         metafile = new Metafile(filePath, hdc);
         graphics.ReleaseHdc(hdc);
     }
     using (Graphics graphics = Graphics.FromImage(metafile))
     {
         graphics.DrawImage(image, 0, 0);
     }
 }

Bulit-in api

Everything looks fine,but when I save it into MS-OLEDS and open it with AutoCAD,I got nothing.In the end I found out that the built-in API does not have a wmf encoder.

When you use the Save method to save a graphic image as a Windows Metafile Format (WMF) or Enhanced Metafile Format (EMF) file, the resulting file is saved as a Portable Network Graphics (PNG) file instead. 
This behavior occurs because the GDI+ component of the .NET Framework does not have an encoder that you can use to save files as .wmf or .emf files.

The Solution with Win32 API


Finally, I found a solution using Win32 API with the correct encoder.Here is the solution code,You can use the GenerateMetafile method to get the matefile stream.

 public class MetafileUtils
 {
     [Flags]
     private enum EmfToWmfBitsFlags
     {
         EmfToWmfBitsFlagsDefault = 0x00000000,
         EmfToWmfBitsFlagsEmbedEmf = 0x00000001,
         EmfToWmfBitsFlagsIncludePlaceable = 0x00000002,
         EmfToWmfBitsFlagsNoXORClip = 0x00000004
     }

     private static int MM_ISOTROPIC = 7;
     private static int MM_ANISOTROPIC = 8;

     [DllImport("gdiplus.dll")]
     private static extern uint GdipEmfToWmfBits(IntPtr hEmf, uint bufferSize, byte[] buffer, int mappingMode, EmfToWmfBitsFlags flags);

     [DllImport("gdi32.dll")]
     private static extern bool DeleteEnhMetaFile(IntPtr hEmf);

     public static MemoryStream GenerateMetafile(Image image)
     {
         Metafile metafile = null;
         using (Graphics graphics = Graphics.FromImage(image))
         {
             var hdc = graphics.GetHdc();
             metafile = new Metafile(hdc, EmfType.EmfOnly);
             graphics.ReleaseHdc(hdc);
         }
         using (Graphics graphics = Graphics.FromImage(metafile))
         {
             graphics.DrawImage(image, 0, 0);
         }
         IntPtr hEmf = metafile.GetHenhmetafile();
         uint bufferSize = GdipEmfToWmfBits(hEmf, 0, null, MM_ANISOTROPIC,
             EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
         byte[] buffer = new byte[bufferSize];
         GdipEmfToWmfBits(hEmf, bufferSize, buffer, MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
         DeleteEnhMetaFile(hEmf);

         var stream = new MemoryStream();
         stream.Write(buffer, 0, (int)bufferSize);
         stream.Seek(0, 0);
         return stream;
     }
 }

Win32 API