65.9K
CodeProject 正在变化。 阅读更多。
Home

使用图元文件轻松添加剪贴板复制功能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.35/5 (13投票s)

2005年11月24日

4分钟阅读

viewsIcon

90546

downloadIcon

847

关于如何使用图元文件实现剪贴板复制的文章。

目录

引言

当我阅读 Charles Petzold 的《Windows 编程》一书时,更具体地说,是关于图元文件的那一章,我在想,在实际应用中,这种功能有哪些潜在的用途。那一章详细介绍了图元文件是什么以及它们如何工作,但很少谈到你可以用它们做什么或者为什么应该使用它们。我认为我找到了图元文件的一个有价值的应用,并且我将与你分享。这篇文章并没有声称发明了什么革命性的技术,因为它非常简单,但同时,它似乎也不是广为人知的。这项技术用于在不同应用程序之间共享数据,至于在同一应用程序中共享数据,私有数据格式可能更合适。在本文中,我将简要概述图元文件是什么,然后介绍这项技术。

背景

图元文件有两种类型:一种是自 Windows 1.0 以来就存在的原始图元文件,另一种是增强型图元文件。它们之间的区别很小。增强型图元文件具有更详细的标题,使其更具独立性。除非您需要与旧的 Win16 应用程序保持兼容性,否则没有充分的理由使用原始图元文件。如果不是这种情况,那么您应该坚持使用增强型图元文件。图元文件是 GDI 对象,一旦打开,它们就会返回一个设备上下文。图元文件会存储使用其 DC 执行的所有 GDI 函数调用,然后允许用户回放存储的 GDI 调用。它们是剪贴板接受的标准数据格式之一。MFC 将图元文件功能封装在 CMetaFileDC 类中,该类派生自 CDC 类。

Using the Code

该技术包括将您的绘图代码放入一个以设备上下文对象指针作为输入参数的函数中

void Draw(CDC *pdc);

此函数可以从您的 WM_PAINT 处理程序中调用

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

现在,您的新复制处理程序将如下所示

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);
            }
        }
    }
}

您的程序只需要这些,就可以复制客户端区域的内容并将其粘贴到任何支持图元文件的应用程序中。

演示程序

演示只是一个简单的 MFC AppWizard 生成的 SDI 应用程序,其中添加了一个伪绘图函数来证明该概念。然后,将复制处理程序添加到 CChildView 类中。

关注点

您可以轻松地将此代码改编到 MFC 视图/文档程序或 Win32 API 程序。另外,一位敏锐的读者指出,如果您的 OnDraw() 函数调用了像 GetTextExtent() 这样的属性 GDI 函数,您必须先手动设置图元文件的 h_hAttribDC。您可以使用 CClientDC 或信息上下文来实现,如下所示

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);
    ...
}

您不能使用 mfdc.m_hDC 调用 SetAttribDC(),因为此函数的 CMetafileDC 版本禁止您将 m_hAttribDC 设置为 m_hDC,但这是错误的!它应该可以工作,因为 CreateEnhanced 的第一个参数是

  • pDCRef - 标识增强型图元文件的参考设备

当它为 NULL 时,参考设备将是显示器。MFC 忽略 pDCRef 并将 m_hAttribDC 设置为 NULL 的原因可能是因为 CMetafileDC 还支持旧的 Windows 1.0 图元文件格式,而这些图元文件没有参考设备的概念。顺便说一句,我就是不喜欢 MFC DC 类中的属性 DC 概念,因为大多数情况下 m_hDCm_hAttribDC 相同,而 m_hAttribDC 的存在只是在整个 CDC 代码中增加了不必要的开销。m_hAttribDC 实际上有用的唯一情况是在 MFC 打印预览功能中使用的 CPreviewDC 中。这是 MFC 源代码中的一个示例

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;
}

结论

就是这样!希望您喜欢这篇文章,如果您喜欢并且觉得它有用,请花几秒钟对其进行评分。您可以在文章底部进行操作。

参考文献

历史

  • 12-03-2005
    • 添加了对 Peter Boulton 报告的潜在属性 DC 问题的提及
  • 11-23-2005
    • 原文

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.