|
| 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
|
|
|
| |
|
|
| |
| |
| 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.
|
|
|
| |
|
|
| |
| |
| 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]
|
|
|
| |
|
|
| |
|
| |
| 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]
|
|
|
| |
|
|
| |
| |
| 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.
|
|
|
| |
|
|
| |
|
|
|
|
|
|
|
|
|
|
BootFX
Reliable and powerful .NET application framework. |
|
|
|
|
|
|