`
hcmfys
  • 浏览: 356590 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

剪贴板

 
阅读更多

<!-- [if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:PunctuationKerning/> <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing> <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery> <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:Compatibility> <w:SpaceForUL/> <w:BalanceSingleByteDoubleByteWidth/> <w:DoNotLeaveBackslashAlone/> <w:ULTrailSpace/> <w:DoNotExpandShiftReturn/> <w:AdjustLineHeightInTable/> <w:BreakWrappedTables/> <w:SnapToGridInCell/> <w:WrapTextWithPunct/> <w:UseAsianBreakRules/> <w:DontGrowAutofit/> <w:UseFELayout/> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!-- [if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles> </xml><![endif]--><!-- [if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]--><!-- [if gte mso 9]><xml> <o:shapedefaults v:ext="edit" spidmax="1026"/> </xml><![endif]--><!-- [if gte mso 9]><xml> <o:shapelayout v:ext="edit"> <o:idmap v:ext="edit" data="1"/> </o:shapelayout></xml><![endif]-->

一、传统剪贴板

传统剪贴板的形式非常的简单,其基本思路是当复制时程序复制一个数据副本给全局内存对象,打开剪贴板并且清空剪贴板当中的数据,将全局内存对象复制给剪贴 板最后关闭剪贴板;从剪贴板中获取数据的顺序是打开剪贴板获取全局内存对象,锁定全局内存对象后从中复制数据,解锁内存对象并且关闭剪贴板。需要注意的是 剪贴板在某个时刻只能被一个程序所打开,如果试图打开一个已经被其他程序打开的剪贴板就会导致API 函数调用返回NULL 值,由于这个机制要求所有程序在 打开剪贴板后在尽可能快的时间内关闭剪贴板。

下面是复制和粘贴的两个例程,这里把m_string 当中的文本复制到剪贴板:

// 复制数据

char m_string[] = "Hello,World";

if (::OpenClipboard(this->m_hWnd))

{

HANDLE hMem = ::GlobalAlloc(GHND,::lstrlen(m_string) + 1);

char *phandle = (char *)::GlobalLock(hMem);

lstrcpy(phandle,m_string);

::GlobalUnlock(hMem);

::EmptyClipboard();

::SetClipboardData(CF_TEXT,hMem);

::CloseClipboard();

}

// 粘贴数据

m_string[BUFFER];

if (::OpenClipboard(this->m_hWnd))

{

HANDLE hMem = ::GetClipboardData(CF_TEXT);

char *phandle = GlobalLock(hMem);

if (::lstrlen(phandle) < BUFFER)

::lstrcpy(m_string,phandle);

GloableUnlock(hMem);

::CloseClipboard();

}

除了使用系统定义的一系列数据类型ID 外我们还可以使用::RegisterClipboardFormat(LPCSTR) 函数来注册自定义的剪贴板数据ID ,这个API 函数保证只要参数提供的字符串内容相同,就会返回相同的UINT 类型的ID 值。

某些程序需要一个延迟型剪贴板,这种剪贴板的基本思想是:给剪贴板发送一个只包含数据类型ID 但不包括全局内存对象的SetClipboardData 调 用,直至有其他程序需要该剪贴板内容数据时再调用SetClipboardData 函数将数据传送给剪贴板。这种程序需要响应 WM_RENDERFORMATWM_RENDERALLFORMAT 两个消息,在处理钱一个消息时我们不必打开剪贴板而只需要直接传送数据即可而后一 个消息需要打开剪贴板。

有时在我们打开剪贴板获取其中的内容之前我们需要知道剪贴板中是否有我们需要的数据,因此我们就需要调用::IsClipboardFomatAvaliable(UINT nID) API 函数,这个函数的参数是我们指定的数据类型ID 。另外我们可以调用

UINT EnumClipboardFormats(UINT nID) 函数来枚举所有的在剪贴板当中的数据类型。调用函数GetPriorityClipboardFormat 函数通过提供给参数的一个UINT 数组API 函数会从中选择一个优先的数据ID 予以返回。

关于传统剪贴板更详细的内容可以参考《WINDOWS 程序设计》。

二、OLE 类型的剪贴板

OLE 类型的剪贴板提供了比传统剪贴板更为强大的功能,但是其使用也较为复杂。在MFC 当中OLE 剪贴板被封装在COleDataSource COleDataObject 两个类当中,这两个类抽象了剪贴板的数据提供者和剪贴板的数据使用者。在类的内部使用了COM 技术来构建。

1. 简单的OLE 剪贴板使用

简单的OLE 剪贴板也使用全局内存对象,在提供数据方面其使用步骤为:在堆上声明一个COleDataSource 对象,调用 CatchGlobalData 函数将全局内存对象句柄交给COleDataSource 对象,最后调用SetClipboard() 成员函数将数据交给 剪贴板;在获取数据方面其使用步骤为:在栈上声明一个COleDataObject 对象,调用AttachClipboard 成员函数将对象与剪贴板连接 起来,调用GetGlobalData 成员函数获取剪贴板中的数据,使用完全局内存对象后调用::GlobalFree 释放全局内存对象。

2. 使用其他媒体的OLE 剪贴板调用

OLE 剪贴板较传统剪贴板强大的一个方面体现在了OLE 剪贴板允许使用多种媒体来传递数据。在使用多种媒体传递数据时,最重要的是FORMATETCSTGMEDIUM 两个数据结构。这两个数据结构的原型如下:

typedef struct tagFORMATETC
{
CLIPFORMAT cfFormat; //
剪贴板数据对象类型,如CF_TEXT
DVTARGETDEVICE *ptd; //
目标设备,一般设置为NULL
DWORD dwAspect; //DVASPECT_CONTENT
LONG lindex; //-1
DWORD tymed; //
媒体类型,如TYMED_HGLOBALTYMED_FILE
}FORMATETC, *LPFORMATETC;

typedef struct tagSTGMEDIUM
{
DWORD tymed; //
等同于FORMATETC 当中的tymed 字段
[switch_type(DWORD), switch_is((DWORD) tymed)]
union { //
联合体当中储存了当前数据信息
[case(TYMED_GDI)] HBITMAP hBitmap;
[case(TYMED_MFPICT)] HMETAFILEPICT hMetaFilePict;
[case(TYMED_ENHMF)] HENHMETAFILE hEnhMetaFile;
[case(TYMED_HGLOBAL)] HGLOBAL hGlobal;
[case(TYMED_FILE)] LPWSTR lpszFileName;
[case(TYMED_ISTREAM)] IStream *pstm;
[case(TYMED_ISTORAGE)] IStorage *pstg;
[default] ;
};
[unique] IUnknown *pUnkForRelease;
}STGMEDIUM;
typedef STGMEDIUM *LPSTGMEDIUM;

在使用非全局内存对象传递剪贴板数据当中,最常用的是使用文件来传递数据,这样做的好处在于可以避免内存的过多浪费,其步骤如下:

// 提供数据

char string[] = "Hello World";

char TempPath[MAX_PATH],FileName[MAX_PATH];

::GetTempPath(MAX_PATH,TempPath); // 获取临时文件夹路径

::GetTempFileName(TempPath,"tmp",0,FileName); // 设置临时文件名

// 打开FileName 文件写入string

LPWSTR wszFileName = (LPWSTR)::CoTaskMemAlloc(MAX_PATH * sizeof(TCHAR));

#ifdef UNICODE // 由于STGMEDIUM 当中的lpszFileName 要求UNICODE 字符串,因此进行转换

::lstrcpy(wszFileName,TempFileName)

#else

::MulityByteToWideChar(CP_ACP,MB_PRECOMPOSED,szFileName,-1,wszFileName,MAX_PATH);

#endif

FORMATETC fe = {CF_TEXT,NULL,DVASCEPT_CONTENT,-1,TYMED_FILE};

STGMEDIUM stgm;

stgm.tymed = TYMED_FILE;

stgm.lpszFileName = wszFileName;

COleDataSource *ods = new COleDataSource;

ods->CatchData(CF_TEXT,&fe,&stgm);

ods->SetClipboardData();

// 获取数据的方法

STGMEDIUM stgm

FORMATETC fe = {CF_TEXT,NULL,DVASCEPT_CONTENT,-1,TYMED_FILE};

COleDataObject odo;

odo.AttachClipboard();

if (odo.GetData(CF_TEXT,&fe,&stgm) && stgm.tymed == TYMED_FILE)

{

TCHAR FileName[MAX_PATH];

#ifdef UNICODE

::lstrcpy(FileName,stgm.lpszFileName);

#else

::WideCharToMulityByte(CP_ACP,0,stgm.lpszFileName,-1,FileName,sizeof (FileName) / sizeof (TCHAR),NULL,NULL);

// 打开文件读取数据

ReleaseStgMedium(&stgm);

}

在上面例程当中,只能读取由TYMED_FILE 作为媒体的剪贴板数据,更通用的办法是调用COleDataObject::GetFile() 成员函数来获取一个CFile 指针,利用这个指针来读取数据。其例程如下:

FORMATETC fe = {CF_TEXT,NULL,DVASCEPT_CONTENT,-1,TYMED_FILE |TYMED_HGLOBAL};

STGMEDIUM stgm;

COleDataObject odo;

odo.AttachClipboard()

switch (odo.GetData(CF_TEXT,&fe,&odo))

{

case TYMED_FILE:

CFile *pfile = odo.GetFile();

// 读取数据

delete pfile;

case TYMED_HGLOBAL:

// 用简单OLE 剪贴板方式获取数据

}

OLE 剪贴板中并没有象传统剪贴板一样对每中数据类型的ID 在剪贴板中只允许放入一个数据项,在OLE 剪贴板中只要在FORMATETC 当中的tymed 字段定义的媒体类型不同即使是相同数据类型ID 的数据项允许存在多个数据项。

OLE 剪贴板的数据类型存在检查通过调用COleDataObject::IsDataAvaliable 成员函数来实现,这个成员函数接受两个参数一个 指示数据类型IDCFFORMAT 值和一个指向FORMATETC 结构的指针,只要在OLE 剪贴板中存在参数指定的数据类型那么就会返回一个非零值。

二、OLE 拖放

MFC 当中实现OLE 拖放需要使用两个类:COleDropSourceCOleDropTarget ,第一个类实现了拖放数据的提供,第二个类实现 了拖放数据的获取。在现实的使用过程当中我们并不直接使用COleDropSource 类来提供数据,作为替代我们使用COleDataSource 来提 供数据。COleDataSource 类的DoDragDrop 成员函数将会创建COleDropSource 类对象并且调用其中的成员函数来提供数据。 与OLE 剪贴板的提供数据不同,在OLE 拖放当中被其他函数或者类调用的对象不再是COleDataSource 而是COleDropSource ,因此 COleDataSource 不再需要在堆上创建而只需要在栈上创建即可。提供数据的一个简单例程如下:

char szText[] = "Hello world";

HANDLE handle = ::GlobalAlloc(GHND,lstrlen(szText) + 1);

char *phandle = ::GlobalLock(handle);

lstrcpy(phandle,szText);

::GlobalUnlock(handle);

COleDataSource ods;

ods.CatchDataGlobal(handle);

DROPEFFECT de = ods.DoDragDorp(DROPEFFECT_MOVE | DROPEFFECT_COPY); // 允许拖放移动和复制两种选项

if (de == DROPEFFECT_COPY)

// 向文档类当中加入新项

else

// 改变文档类当中被拖动项的数据

在允许OLE 拖动的目标程序的视图类当中我们需要加入一个COleDropTarget 保护型数据对象,在OnCreate 成员函数当中我们需要加入对 COleDropTarget::Register 成员函数的调用。然后我们需要处理OnDropEnter,OnDropOver,OnDrop 三个成 员函数的覆盖。这三个成员函数分别对应拖动对象进入窗口,拖动对象在窗口当中移动,拖动对象在窗口中被放下。对这三个成员函数的覆盖的例子如下:

DROPEFFECT CCheckedView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
CScrollView::OnDragEnter(pDataObject, dwKeyState, point);
if (!pDataObject->IsDataAvailable(CF_TEXT))
return FALSE;
return ((dwKeyState & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE);
}

DROPEFFECT CCheckedView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
CScrollView::OnDragOver(pDataObject, dwKeyState, point);
if (!pDataObject->IsDataAvailable(CF_TEXT))
return FALSE;
return ((dwKeyState & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE);
}

BOOL CCheckedView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
CScrollView::OnDrop(pDataObject, dropEffect, point);
if (pDataObject->IsDataAvailable(CF_TEXT))
{
//
读取数据加入到文档中并且刷新视图
return TRUE;
}
return FALSE;
}

分享到:
评论

相关推荐

    易语言从剪切板取图片

    1. 剪切板接口:易语言提供了对剪切板操作的接口,如`系统剪贴板.取得位图()`函数,用于从剪切板中获取位图数据。这个函数返回一个位图对象,可以进一步处理或显示。 2. 位图对象:位图对象是易语言中表示图像的...

    剪切板-delphi实现监视剪贴板

    "剪切板-监视剪贴板.png"可能是一个示例程序的截图,展示如何在Delphi环境下设置剪切板监视器,而".dpr"、".dfm"和".dcu"等文件是Delphi项目和组件的配置文件,它们包含了程序的源代码、界面设计和编译后的单元文件...

    清空剪切板ClearOfficeClipboard

    标题中的"清空剪切板ClearOfficeClipboard"就是针对这一需求的一个功能。 在Excel VBA中,虽然没有直接的函数来清空剪贴板,但我们可以利用一些技巧来实现这个功能。通常,我们会使用API(应用程序接口)调用来与...

    剪切板查看器—clipbrd

    用于查看复制和剪切到剪切板中的内容! “剪贴薄查看器”概述当您从某个程序剪切或复制信息时,该信息会被移动到剪贴板并保留在那里,直到您清除剪贴板或者您剪切或复制了另一片信息。“剪贴簿查看器”中的剪贴板...

    剪贴板查看神器,看看谁用了你的剪贴板

    "剪贴板查看神器"是一款专门针对剪贴板活动进行监控和分析的工具,它能够帮助用户了解哪些程序或进程在何时访问并使用了剪贴板内容。这对于日常使用电脑时的安全意识提升,以及开发者在调试代码时查找问题来源都有很...

    vba清空剪贴板内容

    除了清空剪贴板,VBA还提供了其他剪贴板操作,如读取和写入剪贴板数据。例如,使用`SetData`和`GetData`函数可以实现数据的复制和粘贴。 五、实践应用 在实际应用中,你可以在适当的地方调用`ClearClipboard`子程序...

    java操作剪贴板

    在Java编程中,剪贴板操作是一个非常实用的功能,它允许程序之间共享数据,比如文本、图片等。本文将深入探讨如何使用Java API来实现剪贴板操作,并通过一个简单的示例程序`ClipBoardTest.java`来阐述核心概念。 ...

    QML使用剪贴板

    在QML中,剪贴板(Clipboard)是一个用于在应用程序之间交换数据的工具。它可以用来复制、剪切和粘贴文本、图像等信息。在QML中,我们使用`QtQuick.Controls`模块中的`Clipboard`对象来访问和操作剪贴板。这个功能...

    c#实现Windows剪贴板监视器

    在编程领域,尤其是在Windows应用程序开发中,有时我们需要监控用户的剪贴板操作,以便在特定情况下进行响应或记录。本文将详细介绍如何使用C#语言来实现一个Windows剪贴板监视器。 首先,剪贴板是操作系统提供的一...

    剪切板 网页操作

    在IT行业中,剪切板操作是一项基础但至关重要的功能,特别是在网页交互和编程语言如C++及VC(Visual C++)的应用中。剪切板是操作系统提供的一种共享数据的机制,用户可以通过它来复制、剪切和粘贴信息。下面我们将...

    c++实现将剪贴板内容保存为bmp图

    在C++编程中,将剪贴板的内容保存为BMP图像文件涉及到几个关键知识点,包括剪贴板操作、图像处理和BMP文件格式的理解。首先,我们需要了解Windows API中的剪贴板函数,然后掌握如何解析和创建BMP文件,最后通过实际...

    jQuery获取剪贴板内容的方法

    在当今Web开发中,操作剪贴板功能是用户日常交互的一个重要方面。尽管如此,直接在网页中访问剪贴板是受到限制的,因为出于安全考虑,浏览器默认不允许脚本直接读取剪贴板数据。然而,某些场景下,例如在线文本编辑...

    delphi 获取剪切板图像_获取剪切板图像_delphi源码_poolz1i_

    在Delphi编程环境中,获取剪贴板中的图像是一项常见的任务,尤其在涉及到用户交互和数据交换的场景下。本文将详细讲解如何利用Delphi的API函数来实现这一功能,并提供一个简单的源码示例。 首先,剪贴板是操作系统...

    AHK 拷贝 win 资源管理器选择文件的文件名与路径到剪切板

    win 资源管理器选择文件的文件名与路径到剪切板”指的是使用 AutoHotkey (AHK) 这款自动化脚本语言,编写脚本来实现在Windows资源管理器中选中多个文件后,一键将这些文件的完整路径和名称复制到剪贴板的功能。...

    VB.NET实现Windows剪贴板监视器

    通过创建这样的应用,开发者可以监控系统剪贴板的变化,例如文本、图像或其他数据类型的复制、剪切和粘贴活动。 首先,了解Windows剪贴板是操作系统提供的一种共享内存区域,用于临时存储数据,以便于在不同的应用...

    C#获取剪切板内容

    本文将深入探讨如何使用C#获取剪切板内容,这在日常编程中是一个非常实用的功能,比如在实现复制、粘贴或者数据交换的场景下。 首先,我们需要了解Windows操作系统中的剪切板。剪切板是系统提供的一种临时存储数据...

    PB剪切板工具

    "PB剪切板工具"是一款高效实用的剪贴板管理软件,专为提高用户在日常电脑操作中的复制、粘贴效率而设计。该工具的独特之处在于它能够保存并展示用户的多次复制历史,使得用户不再局限于操作系统自带的单一剪贴板功能...

    C# 复制图片 剪切板

    在本案例中,我们关注的是使用C#语言实现从网页中复制图片并将其存储到剪切板,以便用户可以方便地在不同应用程序之间进行粘贴,如微信或QQ。以下是对这个主题的详细讲解: 首先,我们需要理解剪切板是什么。剪切板...

    用VB将剪切板中的图片保存为JPG文件\捕获屏幕快照的程序,可制作用户手册

    本项目“用VB将剪切板中的图片保存为JPG文件”是利用VB来实现的一个实用功能,它能够捕获屏幕快照并将其保存为JPEG(JPG)格式的图像文件,这对于制作用户手册或教程文档非常有用。 首先,我们需要了解VB中的剪贴板...

    delphi获取处理剪贴板中Excel中的数据,封装成自定义的数据集

    `OpenClipboard`函数用于打开剪贴板,`EmptyClipboard`清空剪贴板,`SetClipboardData`设置剪贴板数据,而`CloseClipboard`则关闭剪贴板。当从Excel复制数据时,剪贴板上通常包含多种数据格式,如CF_TEXT、CF_...

Global site tag (gtag.js) - Google Analytics