Topaz Filer: if you use e-mail for business, we can save you money and decrease your risk.
How do I copy metafiles to the clipboard so that I can paste them into Word, Wordpad, etc?
Messages   Related Types
This message was discovered on microsoft.public.dotnet.framework.windowsforms.
Responses highlighted in red are from those people who are likely to be able to contribute good, authoratitive information to this discussion. They include Microsoft employees, MVP's and others who IMHO contribute well to these kinds of discussions.

Niki Muller
GOOD ANSWER
The following looks OK, compiles OK.
The copied metafile can be pasted back into the same application, but not to
any <<other>> windows application, What am I missing?

// Create a memory stream for the metafile object to create from

MemoryStream ms = new MemoryStream();

// We need a graphics object because of it's device context handle

Graphics g = CreateGraphics();

// Get the device context handle

IntPtr hdc = g.GetHdc();

// Now we can create the metafile object

Metafile mf = new Metafile( ms, hdc, doc.GraphObject.SizingRectangle,
MetafileFrameUnit.GdiCompatible , EmfType.EmfPlusDual );

// Release handle to temporary device context.

g.ReleaseHdc(hdc);

// Dispose of temporary graphics object.

g.Dispose();

// Create a new graphics from the metafile object

Graphics mg = Graphics.FromImage( mf );

// Now do the drawings in the graphics metaFile.

doc.GraphObject.Draw( mg, doc.GraphObject.SizingRectangle, new
Margins(0,0,0,0) );

// Dispose of graphics object.

mg.Dispose();

// Copy metaFile to clipboard and keep it there after application exits.

Clipboard.SetDataObject( mf , true );

// Dispose of metafile.

mf.Dispose();

// All is well, data has been copied, can be seen with Petzold's ClipViewAll

// CANNOT be seen with windows clipview!

// CANNOT be pasted into another windows application, like Word, Wordpad,
etc

Reply to this message...
Vote that this is a GOOD answer... (1 vote from another user already)
 
 
    
John Hornick [MS] (VIP)
GOOD ANSWER
Hi,

[Original message clipped]

I'm currently writing a KB article to cover this. The problem is that the
framework
uses a new clipboard format for its metafiles - one that other apps, and
even the OS,
don't know about and therefore cannot translate into EMF.

The workaround is to interoperate with Win32 clipboard APIs, per the
following
(untested) code:
public class ClipboardMetafileHelper
{
    [DllImport("user32.dll")]
    static extern bool OpenClipboard(IntPtr hWndNewOwner);
    [DllImport("user32.dll")]
    static extern bool EmptyClipboard();
    [DllImport("user32.dll")]
    static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
    [DllImport("user32.dll")]
    static extern bool CloseClipboard();
    [DllImport("gdi32.dll")]
    static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
    [DllImport("gdi32.dll")]
    static extern bool DeleteEnhMetaFile(IntPtr hemf);
    
    // Metafile mf is set to an invalid state inside this function
    static public bool PutEnhMetafileOnClipboard( IntPtr hWnd, Metafile mf )
    {
        bool bResult = false;
        IntPtr hEMF, hEMF2;
        hEMF = mf.GetHenhmetafile(); // invalidates mf
        if( ! hEMF.Equals( new IntPtr(0) ) )
        {
            hEMF2 = CopyEnhMetaFile( hEMF, new IntPtr(0) );
            if( ! hEMF2.Equals( new IntPtr(0) ) )
            {
                if( OpenClipboard( hWnd ) )
                {
                    if( EmptyClipboard() )
                    {
                        IntPtr hRes = SetClipboardData( 14 /*CF_ENHMETAFILE*/, hEMF2 );
                        bResult = hRes.Equals( hEMF2 );
                        CloseClipboard();
                    }
                }
            }
            DeleteEnhMetaFile( hEMF );
        }
        return bResult;
    }
}

//You might call the above function with code like:
Metafile mf = new Metafile( "filename.emf" );
ClipboardMetafileHelper.PutEnhMetafileOnClipboard(this.Handle, mf );

Note that this function invalidates the Metafile object.

For completeness, here's the code in VB.NET:
Public Class ClipboardMetafileHelper
<DllImport("user32.dll", EntryPoint:="OpenClipboard", _
SetLastError:=True, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function OpenClipboard(ByVal hWnd As IntPtr) As Boolean
End Function
<DllImport("user32.dll", EntryPoint:="EmptyClipboard", _
SetLastError:=True, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function EmptyClipboard() As Boolean
End Function
<DllImport("user32.dll", EntryPoint:="SetClipboardData", _
SetLastError:=True, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function SetClipboardData(ByVal uFormat As Integer, ByVal
hWnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", EntryPoint:="CloseClipboard", _
SetLastError:=True, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function CloseClipboard() As Boolean
End Function
<DllImport("gdi32.dll", EntryPoint:="CopyEnhMetaFileA", _
SetLastError:=True, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function CopyEnhMetaFile(ByVal hemfSrc As IntPtr, ByVal
hNULL As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll", EntryPoint:="DeleteEnhMetaFile", _
SetLastError:=True, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function DeleteEnhMetaFile(ByVal hemfSrc As IntPtr) As
Boolean
End Function

' Metafile mf is set to an invalid state inside this function
Public Shared Function PutEnhMetafileOnClipboard(ByVal hWnd As IntPtr,
ByVal mf As Metafile) As Boolean
Dim bResult As New Boolean()
bResult = False
Dim hEMF, hEMF2 As IntPtr
hEMF = mf.GetHenhmetafile() ' invalidates mf
If Not hEMF.Equals(New IntPtr(0)) Then
hEMF2 = CopyEnhMetaFile(hEMF, New IntPtr(0))
If Not hEMF2.Equals(New IntPtr(0)) Then
If OpenClipboard(hWnd) Then
If EmptyClipboard() Then
Dim hRes As IntPtr
hRes = SetClipboardData(14, hEMF2) ' 14 ==
CF_ENHMETAFILE
bResult = hRes.Equals(hEMF2)
CloseClipboard()
End If
End If
End If
DeleteEnhMetaFile(hEMF)
End If
Return bResult
End Function

End Class

'You might call the above function with code like:
Dim mf As New Metafile("filename.emf")
ClipboardMetafileHelper.PutEnhMetafileOnClipboard(me.Handle,mf)

If you see any problems with the code above, let me know. This was a first
run at it.

Thanks,
- John
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.
Visit http://www.microsoft.com/security for current information on security.

Reply to this message...
Vote that this is a GOOD answer... (1 vote from another user already)
 
 
    
Niki Muller
GOOD ANSWER
Thank you very much for the prompt reply.

I tried the code and as far as I can tell for now, your workaround is
pretty ok!
I pasted the enhanced metafile into Word 2002 successfully.

I will test more thoroughly with other apps too.

Regards,

Niki Muller, LTML

"John Hornick [MS]" <Click here to reveal e-mail address> wrote in message
news:WzkrTjfGCHA.1648@cpmsftngxa07...
[Original message clipped]

Reply to this message...
Vote that this is a GOOD answer... (1 vote from another user already)
 
 
    
Niki Muller
GOOD ANSWER
I noticed that Word 2002 has to be running before I can paste to it
successfully with the workaraound, otherwise i.e. if I copy the metafile to
the clipboard (where it is visible), then start Word, I paste garbage ( a
default icon ). Also, if I execute a Paste Special, I can see in the former
case the enhanced metafile and in the latter case DIB or Bitmap. Strangely
enough, the mere fact of starting Word 2002 after copying the metafile to
the clipboard has the ugly side effect of destroying the metafile in the
clipboard.

Regards,

Niki Muller, LTML

"John Hornick [MS]" <Click here to reveal e-mail address> wrote in message
news:WzkrTjfGCHA.1648@cpmsftngxa07...
[Original message clipped]

Reply to this message...
Vote that this is a GOOD answer... (1 vote from another user already)
 
 
    
John Hornick [MS] (VIP)
GOOD ANSWER
Hi,

[Original message clipped]

On which OS do you see this behavior? I just tried it on XP and it
worked fine.

Thanks,
- John
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.
Visit http://www.microsoft.com/security for current information on security.

Reply to this message...
Vote that this is a GOOD answer... (1 vote from another user already)
 
 
 
System.Drawing.Graphics
System.Drawing.Imaging.EmfType
System.Drawing.Imaging.Metafile
System.Drawing.Imaging.MetafileFrameUnit
System.Drawing.Printing.Margins
System.IntPtr
System.IO.MemoryStream
System.Runtime.InteropServices.CallingConvention
System.Windows.Forms.Clipboard




Ad
BootFX
Reliable and powerful .NET application framework.
Recession Busting Bespoke Software
Get through the recession by investing in bespoke software to decrease costs and create commercial opportunities.
Other DN247 Network Sites
.NET 247
SQL Server Wins
Old Skool Developer
 
Copyright © AMX Software Ltd 2008-2009. Portions copyright © Matthew Baxter-Reynolds 2001-2009. All rights reserved.
Contact Us - Terms of Use - Privacy Policy - .NET 247 is a member of the DN247 Network - 4.0.30129.1734