Click here to Skip to main content
12,398,225 members (58,308 online)
Click here to Skip to main content
Add your own
alternative version

Stats

75.2K views
688 downloads
50 bookmarked
Posted

Add clipboard copy functionality easily with metafiles

, 7 Feb 2006
Rate this:
Please Sign up or sign in to vote.
An article on how to implement clipboard copy with metafiles.

Contents

Introduction

While I was reading Charles Petzold's Programming Windows book, more specifically the chapter on metafiles, I was wondering what could be the potential usages of such a feature in a real world application. The chapter describes in length what metafiles do and how they work, but little is said about what you can do with them or why you should use them. I think that I found a worthwhile application for metafiles and I am going to share it with you. This article has no claims of inventing a revolutionary technique as it is ridiculously simple, but at the same time, it does not seem to be widely known. This technique is for sharing data among different applications, as for sharing the data among the same application, private data formats might be more appropriate. In this article, I will give a brief overview of what metafiles are, and then I will present the technique.

Background

There are two types of metafiles: the original ones that have been around since Windows 1.0, and the enhanced metafiles. The difference between them is very small. The enhanced metafiles have a slightly more detailed header which makes them more self contained. There is no good reason to use the original metafiles unless you have to keep compatibility with an old Win16 application. If it is not the case, then you should stick with the enhanced metafiles. Metafiles are GDI objects that once opened will return a device context. Metafiles store all the GDI function calls performed with their DC and then allow the user to perform a playback of the stored GDI calls. They are one of the standard data formats that the clipboard accepts. MFC encapsulates metafiles functionality in the class CMetaFileDC which derives from the class CDC.

Using the code

The technique consists of putting your drawing code in a function that takes a device context object pointer as an input parameter:

void Draw(CDC *pdc);

This function can be called from your WM_PAINT handler:

void CChildView::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    
    Draw(&dc);
}

Now, your new copy handler will look like this:

void CChildView::OnEditCopy() 
{
    CMetaFileDC mfdc;
    if( mfdc.CreateEnhanced(NULL,NULL,NULL,NULL) )
    {
        Draw(&mfdc);
        HENHMETAFILE hmf;
        if( (hmf = mfdc.CloseEnhanced()) )
        {
            if( OpenClipboard() )
            {
                EmptyClipboard();
                SetClipboardData(CF_ENHMETAFILE, hmf);
                CloseClipboard();
            }
            else
            {
                /*
                 * The metafile is deleted only 
                 * when it has not been set in
                 * the clipboard.
                 */
                ::DeleteEnhMetaFile(hmf);
            }
        }
    }
}

This is all that your program needs, to be able to copy the client area content and paste it in any application supporting metafiles.

The demo program

The demo is just a simple MFC AppWizard generated SDI application where a bogus drawing function has been added to prove the concept. Then, the copy handler has been added to the CChildView class.

Points of interest

You can easily adapt this code to a MFC View/Document program or a Win32 API program. Also, an astute reader pointed out that if your OnDraw() function calls attribute GDI functions such as GetTextExtent(), you must first manually set the metafile h_hAttribDC. You can either do that with a CClientDC or with an information context like this:

CMetaFileDC mfdc;
if( mfdc.CreateEnhanced(NULL,NULL,NULL,NULL) )
{
    // Create a second device context that 
    // points to the screen, in order to make
    // functions like GetTextExtent work correctly
    CDC cdc;
    VERIFY(cdc.CreateIC(__TEXT("DISPLAY"),NULL,NULL,NULL));
    mfdc.SetAttribDC(cdc.m_hAttribDC);

    Draw(&mfdc);
    ...
}

You cannot call SetAttribDC() with mfdc.m_hDC because the CMetafileDC version of this function forbids you to set m_hAttribDC to m_hDC but this is wrong! It should work because the first parameter of CreateEnhanced is:

  • pDCRef - Identifies a reference device for the enhanced metafile.

When it is NULL, the reference device will be the display. The reason why MFC ignores pDCRef and sets m_hAttribDC to NULL is probably because CMetafileDC also supports the old Windows 1.0 metafile format and these metafiles have no notion of reference devices. As a side note, I just do not like the attribute DC notion of MFC DC classes because most of the time m_hDC is the same as m_hAttribDC and the presence of m_hAttribDC just adds a superfluous overhead all over the CDC code. The only exception where m_hAttribDC is actually useful is in CPreviewDC used in the MFC print preview feature. Here is an example of this from the MFC source code:

CPoint CDC::MoveTo(int x, int y)
{
     ASSERT(m_hDC != NULL);
     CPoint point;

     if (m_hDC != m_hAttribDC)
          VERIFY(::MoveToEx(m_hDC, x, y, &point));
     if (m_hAttribDC != NULL)
          VERIFY(::MoveToEx(m_hAttribDC, x, y, &point));
     return point;
}

Conclusion

That is it! I hope you enjoyed this article, and if you did and find it useful, please take a few seconds to rank it. You can do so right at the bottom of the article.

Bibliography

History

  • 12-03-2005
    • Added mention of the potential attribute DC problem reported by Peter Boulton.
  • 11-23-2005
    • Original article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

lano1106
Web Developer
Canada Canada
I'm located in Montreal,Canada and I graduated in electrical engineering at E.T.S.

Highly experienced C++ developer. I have been working 3 years at Nortel Networks on their Next-gen OC-768 products firmware. I then worked for the FAA 3 years on their next-gen Oceanic Air Traffic Control system. Followed by a short period in the video game industry at Quazal, the online multiplayer middleware provider and now I am in the Internet audio/video streaming business at StreamTheWorld.

To contact me, visit my website

You may also be interested in...

Comments and Discussions

 
QuestionHow can i add just a little section to the clipboard? Pin
suamikim13-Nov-06 4:07
membersuamikim13-Nov-06 4:07 
AnswerRe: How can i add just a little section to the clipboard? Pin
lano110613-Nov-06 16:04
memberlano110613-Nov-06 16:04 
GeneralRe: How can i add just a little section to the clipboard? Pin
suamikim13-Nov-06 22:13
membersuamikim13-Nov-06 22:13 
GeneralThank you Pin
JC_196914-Jul-06 10:33
memberJC_196914-Jul-06 10:33 
GeneralIt is greate Pin
yangyzqo26-Feb-06 15:33
memberyangyzqo26-Feb-06 15:33 
GeneralOLE Pin
walster10-Feb-06 6:49
memberwalster10-Feb-06 6:49 
GeneralThanks for the article Pin
Stuart Dootson8-Feb-06 22:40
memberStuart Dootson8-Feb-06 22:40 
GeneralGood work for metafile clipboard support! Pin
ucc80116-Jan-06 15:16
memberucc80116-Jan-06 15:16 
GeneralEnhancement to stop crashes on GetTextExtent etc. Pin
peterboulton28-Nov-05 23:35
memberpeterboulton28-Nov-05 23:35 
GeneralRe: Enhancement to stop crashes on GetTextExtent etc. Pin
lano110629-Nov-05 15:47
memberlano110629-Nov-05 15:47 
GeneralRe: Enhancement to stop crashes on GetTextExtent etc. Pin
lano11065-Dec-05 2:26
memberlano11065-Dec-05 2:26 
GeneralRe: Enhancement to stop crashes on GetTextExtent etc. Pin
lano11065-Dec-05 3:04
memberlano11065-Dec-05 3:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160721.1 | Last Updated 8 Feb 2006
Article Copyright 2005 by lano1106
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid