ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 13510|回复: 9

[求助] vba中如何获取粘贴板中的信息

[复制链接]

TA的精华主题

TA的得分主题

发表于 2012-1-6 13:58 | 显示全部楼层 |阅读模式
当我选中了一个或多个单元格之后进行复制,
这时用vba如何获取到我复制的这些单元格的信息?

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-1-6 14:25 | 显示全部楼层
咋没人回答呢?是我表述不清楚么?

TA的精华主题

TA的得分主题

发表于 2012-1-6 14:27 | 显示全部楼层
从来就没用过此功能。想复就复,管它什么信息。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-1-6 15:42 | 显示全部楼层
张三李四 发表于 2012-1-6 14:27
从来就没用过此功能。想复就复,管它什么信息。

没有其他办法了么?

TA的精华主题

TA的得分主题

发表于 2012-1-6 16:36 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
下面语句可以读到复制单元格的范围地址:
    Dim cRgn As Range
    Set cRgn = Selection
    Debug.Print cRgn.Address

TA的精华主题

TA的得分主题

发表于 2012-1-6 17:18 | 显示全部楼层
你要获取剪贴板什么信息?单元格内容还是完整的单元格对象?

可能需要API

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-1-6 20:53 | 显示全部楼层
liucqa 发表于 2012-1-6 17:18
你要获取剪贴板什么信息?单元格内容还是完整的单元格对象?

可能需要API

需要什么样的API啊?

TA的精华主题

TA的得分主题

发表于 2012-1-6 21:37 | 显示全部楼层
剪贴板所有api函数 收藏
2009年11月04日 星期三 10:33
2009年09月02日 下午 11:24

剪贴板所有api函数 收藏
剪贴板所有api函数 [转大富翁笔记]
这是我在编写剪贴板相关程序是收集的相关API函数。
(一)ChangeClipboardChain
将剪贴的连接从一个句柄转到下一个句柄。
BOOL ChangeClipboardChain(
HWND hWndRemove, // handle to window to remove
HWND hWndNewNext // handle to next window
);
(1)hWndRemove表示第一个窗口的句柄(断开)。
(2)hWndNewNext表示第二个窗口的句柄(连接)。
注意,在使用之前应该使用SetClipboardViewer事先进行窗口句柄的连接。
(二)CloseClipboard
关闭剪贴板。
BOOL CloseClipboard(VOID)//VOID意思是空白。
本函数没有参数,事先应该用OpenClipboard函数打开过剪贴板。
(三)CountClipboardFormats
不管剪贴板是什么格式,全部转化为数据格式。
int CountClipboardFormats(VOID)
本函数没有参数。
(四)EmptyClipboard
清空剪贴板。
BOOL EmptyClipboard(VOID)
本函数没有参数。
(五)EnumClipboardFormats
使剪贴板内的格式转变成指定格式。
UINT EnumClipboardFormats(
UINT format // specifies a known available clipboard format
);
其中format表示的是将要转化成的格式。该参数的意义可参照后面。
(六)GetClipboardData
获取剪贴板内的数据。
HANDLE GetClipboardData(
UINT uFormat // clipboard format
);
其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
(七)GetClipboardFormatName
获取剪贴板内数据格式的名称。
int GetClipboardFormatName(
UINT format, // clipboard format to retrieve
LPTSTR lpszFormatName, // address of buffer for name
int cchMaxCount // length of name string in characters
);
(1)format表示的意义同前,应该是不事先规定格式;
(2)lpszFormatName表示的是格式名称地址;
(3)cchMaxCount剪贴板内数据的长度。
(八)GetClipboardOwner
获取当前剪贴板是属于哪一个窗口的句柄。
HWND GetClipboardOwner(VOID)
返回那个窗口的句柄。
(九)GetClipboardSequenceNumber
返回剪贴板序号。
DWORD GetClipboardSequenceNumber(VOID)
(十)GetClipboardViewer
返回剪贴板属于窗口的句柄。
HWND GetClipboardViewer(VOID)
(十一)GetOpenClipboardWindow
返回打开剪贴板的那个窗口句柄。
HWND GetOpenClipboardWindow(VOID)
(十二)GetPriorityClipboardFormat
int GetPriorityClipboardFormat(
UINT *paFormatPriorityList, // address of priority list
int cFormats // number of entries in list
);
(十三)IsClipboardFormatAvailable
判断剪贴板的格式。
BOOL IsClipboardFormatAvailable(
UINT format // clipboard format
);
其中format表示的是剪贴板内数据的格式。该参数的意义可参照后面。
(十四)OpenClipboard
打开剪贴板。
BOOL OpenClipboard(
HWND hWndNewOwner // handle to window opening clipboard
);
返回剪贴板的句柄。
(十五)RegisterClipboardFormat
注册新的剪贴板格式。
UINT RegisterClipboardFormat(
LPCTSTR lpszFormat // address of name string
);
lpszFormat新的剪贴板格式名称。
(十六)SetClipboardData
设置剪贴板内的数据。
HANDLE SetClipboardData(
UINT uFormat, // clipboard format
HANDLE hMem // data handle
);
uFormat表示的是要放进剪贴板数据的格式;
hMem表示数据的地址指针。
(十七)SetClipboardViewer
将剪贴板内容连接到窗口。
HWND SetClipboardViewer(
HWND hWndNewViewer // handle to clipboard viewer window
);
hWndNewViewer表示要连接到的那个窗口句柄。
上文中剪贴板格式Format的可选参数如下:
CF_BITMAP位图格式;
CF_DIB
CF_DIBV5
CF_DIF
CF_DSPBITMAP
CF_DSPENHMETAFILE
CF_DSPMETAFILEPICT
CF_DSPTEXT
CF_ENHMETAFILE
CF_GDIOBJFIRST
CF_GDIOBJLAST
CF_HDROP
CF_LOCALE
CF_METAFILEPICT
CF_OEMTEXT
CF_OWNERDISPLAY
CF_PALETTE
CF_PENDATA
CF_PRIVATEFIRST
CF_PRIVATELAST
CF_RIFF
CF_SYLK
CF_TEXT文本格式;
CF_WAVE音乐格式;
CF_TIFF
CF_UNICODETEXT


Windows剪贴板

  Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制。Windows系统支持剪贴板IPC的基本机制是由系统预留的一块全局共享内存,用来暂存在各进程间进行交换的数据:提供数据的进程创建一个全局内存块,并将要传送的数据移到或复制到该内存块;接受数据的进程(也可以是提供数据的进程本身)获取此内存块的句柄,并完成对该内存块数据的读取。

  为使剪贴板的这种IPC机制更加完善和便于使用,需要解决好如下三个问题:提供数据的进程在结束时Windows系统将删除其创建的全局内存块,而接受数据的进程则希望在其退出后剪贴板中的数据仍然存在,可以继续为其他进程所获取;能方便地管理和传送剪贴板数据句柄;能方便设置和确定剪贴板数据格式。为完善上述功能,Windows提供了存在于USER32.dll中的一组API函数、消息和预定义数据格式等,并通过对这些函数、消息的使用来管理在进程间进行的剪贴板数据交换。

  Windows系统为剪贴板提供了一组API函数和多种消息,基本可以满足编程的需要。而且Windows还为剪贴板预定义了多种数据格式。通过这些预定义的格式,可以使接收方正确再现数据提供方放置于剪贴板中的数据内容。

  文本剪贴板和位图剪贴板的使用

  这两种剪贴板是比较常用的。其中,文本剪贴板是包含具有格式CF_TEXT的字符串的剪贴板,是最经常使用的剪贴板之一。在文本剪贴板中传递的数据是不带任何格式信息的ASCII字符。若要将文本传送到剪贴板,可以先分配一个可移动全局内存块,然后将要复制的文本内容写入到此内存区域。最后调用剪贴板函数将数据放置到剪贴板:

注意:
    下面代码中:
    1、HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1);
分配内存长度必须是dwLength + 1,否则在调用SetClipboardData时会出错;可以通过调用 int i2 = ::GlobalSize(hGlobalMemory );来查看分配的长度。

    2、hGlobalMemory不能释放,即不能调用::GlobalFree(hGlobalMemory),因为如果在一个程序中还要粘贴的话就必须不能释放,否则在同一程序中粘贴时获得的指针为NULL,但如果只在别的程序中粘贴则可以释放。

    以上两条是在编制HsfBrowserCtl(HOOPS三维浏览控件)时总结出来的。可参看原码中的复制、粘贴部分。
  DWORD dwLength = 100; // 要复制的字串长度
HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存
LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存
for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
 *lpGlobalMemory++ = '*';
 GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
 HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
 ::OpenClipboard(hWnd); // 打开剪贴板
 ::EmptyClipboard(); // 清空剪贴板
 ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
 ::CloseClipboard(); // 关闭剪贴板

  这里以OpenClipboard()打开剪贴板,并在调用了EmptyClipboard()后使hWnd指向的窗口成为剪贴板的拥有者,一直持续到CloseClipboard()函数的调用。在此期间,剪贴板为拥有者所独占,其他进程将无法对剪贴板内容进行修改。

  从剪贴板获取文本的过程与之类似,首先打开剪贴板并获取剪贴板的数据句柄,如果数据存在就拷贝其数据到程序变量。由于GetClipboardData()获取的数据句柄是属于剪贴板的,因此用户程序必须在调用CloseClipboard()函数之前使用它:

  HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
HANDLE hClipMemory = ::GetClipboardData(CF_TEXT);// 获取剪贴板数据句柄
DWORD dwLength = GlobalSize(hClipMemory); // 返回指定内存区域的当前大小
LPBYTE lpClipMemory = (LPBYTE)GlobalLock(hClipMemory); // 锁定内存
m_sMessage = CString(lpClipMemory); // 保存得到的文本数据
GlobalUnlock(hClipMemory); // 内存解锁
::CloseClipboard(); // 关闭剪贴板

  大多数应用程序对图形数据采取的是位图的剪贴板数据格式。位图剪贴板的使用与文本剪贴板的使用是类似的,只是数据格式要指明为CF_BITMAP,而且在使用SetClipboardData()或GetClipboardData()函数时交给剪贴板或从剪贴板返回的是设备相关位图句柄。下面这段示例代码将把存在于剪贴板中的位图数据显示到程序的客户区:

  HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
HANDLE hBitmap = ::GetClipboardData(CF_BITMAP); // 获取剪贴板数据句柄
HDC hDC = ::GetDC(hWnd); // 获取设备环境句柄
HDC hdcMem = CreateCompatibleDC(hDC); // 创建与设备相关的内存环境
SelectObject(hdcMem, hBitmap); // 选择对象
SetMapMode(hdcMem, GetMapMode(hDC)); // 设置映射模式
BITMAP bm; // 得到位图对象
GetObject(hBitmap, sizeof(BITMAP), &bm);
BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); //位图复制
::ReleaseDC(hWnd, hDC); // 释放设备环境句柄
DeleteDC(hdcMem); // 删除内存环境
::CloseClipboard(); // 关闭剪贴板

多数据项和延迟提交技术

  要把数据放入剪贴板,在打开剪贴板后一定要调用EmptyClipboard()函数清除当前剪贴板中的内容,而不可以在原有数据项基础上追加新的数据项。但是,可以在EmptyClipboard()和CloseClipboard()调用之间多次调用SetClipboardData()函数来放置多个不同格式的数据项。例如:

  OpenClipboard(hWnd);
EmptyClipboardData();
SetClipboardData(CF_TEXT, hGMemText);
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();

  这时如果用CF_TEXT或CF_BITMAP等格式标记去调用IsClipboardFormatAvailable()都将返回TRUE,表明这几种格式的数据同时存在于剪贴板中。以不同的格式标记去调用GetClipboardData()函数可以得到相应的数据句柄。

  对于多数据项的剪贴板数据,还可以用CountClipboardFormats()和EnumClipboardFormats()函数得到当前剪贴板中存在的数据格式数目和具体的数据格式。EnumClipboardFormats()的函数原型为:

  UINT EnumClipboardFormats(UINT format);

  参数format指定了剪贴板的数据格式。如果成功执行将返回format指定的格式的下一个数据格式值,如果format为最后的数据格式值,那么将返回0。由此不难写出处理剪贴板中所有格式数据项的程序段代码:

  UINT format = 0; // 从第一种格式值开始枚举
OpenClipboard(hWnd);
while(format = EnumClipboardFormats(format))
{
…… // 对相关格式数据的处理
}
CloseClipboard();

  在数据提供进程创建了剪贴板数据后,一直到有其他进程获取剪贴板数据前,这些数据都要占据内存空间。如在剪贴板放置的数据量过大,就会浪费内存空间,降低对资源的利用率。为避免这种浪费,可以采取延迟提交(Delayed rendering)技术,即由数据提供进程先创建一个指定数据格式的空(NULL)剪贴板数据块,直到有其他进程需要数据或自身进程要终止运行时才真正提交数据。

  延迟提交的实现并不复杂,只需剪贴板拥有者进程在调用SetClipboardData()将数据句柄参数设置为NULL即可。延迟提交的拥有者进程需要做的主要工作是对WM_RENDERFORMAT、WM_DESTORYCLIPBOARD和WM_RENDERALLFORMATS等剪贴板延迟提交消息的处理。

  当另一个进程调用GetClipboardData()函数时,系统将会向延迟提交数据的剪贴板拥有者进程发送WM_RENDERFORMAT消息。剪贴板拥有者进程在此消息的响应函数中应使用相应的格式和实际的数据句柄来调用SetClipboardData()函数,但不必再调用OpenClipboard()和EmptyClipboard()去打开和清空剪贴板了。在设置完数据有也无须调用CloseClipboard()关闭剪贴板。如果其他进程打开了剪贴板并且调用EmptyClipboard()函数去清空剪贴板的内容,接管剪贴板的拥有权时,系统将向延迟提交的剪贴板拥有者进程发送WM_DESTROYCLIPBOARD消息,以通知该进程对剪贴板拥有权的丧失。而失去剪贴板拥有权的进程在收到该消息后则不会再向剪贴板提交数据。另外,在延迟提交进程在提交完所有要提交的数据后也会收到此消息。如果延迟提交剪贴板拥有者进程将要终止,系统将会为其发送一条WM_RENDERALLFORMATS消息,通知其打开并清除剪贴板内容。在调用SetClipboardData()设置各数据句柄后关闭剪贴板。

  下面这段代码将完成对数据的延迟提交,WM_RENDERFORMAT消息响应函数OnRenderFormat()并不会立即执行,当有进程调用GetClipboardData()函数从剪贴板读取数据时才会发出该消息。在消息处理函数中完成对数据的提交:

  进行延迟提交:

  HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄
::OpenClipboard(hWnd); // 打开剪贴板
::EmptyClipboard(); // 清空剪贴板
::SetClipboardData(CF_TEXT, NULL); // 进行剪贴板数据的延迟提交
::CloseClipboard(); // 关闭剪贴板

  在WM_RENDERFORMAT消息的响应函数中:

  DWORD dwLength = 100; // 要复制的字串长度
HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存块
LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存块
for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块
*lpGlobalMemory++ = '*';
GlobalUnlock(hGlobalMemory); // 锁定内存块解锁
::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板
    DSP和自定义数据格式的使用

  Windows系统预定义了三个带“DSP”前缀的数据格式:CF_DSPTEXT、CF_DSPBITMAP和CF_DSPMETAFILEPICT。这是一些伪标准格式,用于表示在程序中定义的私有剪贴板数据格式。对于不同的程序,这些格式的规定是不同的,因此这些格式只针对某一具体程序的不同实例才有意义。

  为使用DSP数据格式,必须确保进程本身与剪贴板拥有者进程同属一个程序。可以调用GetClipboardOwner()函数来获取剪贴板拥有者窗口句柄,并调用GetClassName()来获取窗口类名:

HWND hClipOwner = GetClipboardOwner();
GetClassName(hClipOwner, &ClassName, 255);

  如果剪贴板拥有者窗口类名同本进程的窗口类名一致,就可以使用带有DSP前缀的剪贴板数据格式了。
除了使用Windows预定义的剪贴板数据格式外,也可以在程序中使用自定义的数据格式。对于自定义的数据格式lpszFormat,可以调用RegisterClipboardFormat()函数来登记,并获取其返回的格式标识值:

UINT format = RegisterClipboardFormat(lpszFormat);

  对此返回的格式标识值的使用与系统预定义的格式标识是一样的。可以通过GetClipboardFormatName()函数来获取自定义格式的ASCII名。

  小结

  本文主要对Windows编程中的剪贴板机制作了较为深入的讨论,对其中常用的文本、位图、DSP和自定义数据格式的使用方法以及多数据项和延迟提交等重要技术一并做了阐述。并给出了具体的程序示例代码,使读者能够更好的掌握剪贴板机制的使用。


功能实现:复制位图到剪切阪。

今日看了下COleDataSource的原码和网上的文章。

COleDataSource用内嵌类实现了IDataObject接口
//COPY HBITMAP To CilpBoard
void CMyView::OnEditCopy()
{

    COLORREF BACKGROUND_COLOR = RGB(255,255,255);
    tagSTGMEDIUM * data;
    CBitmap * junk;
    COleDataSource* pData = new COleDataSource;
    data = new tagSTGMEDIUM;
    junk = new CBitmap();
    CClientDC cdc(this);
    CDC dc;
    dc.CreateCompatibleDC(&cdc);
    CRect client;
    //replace this with something that calculates
    //the proper rectangle size
    GetClientRect(client);
    junk->CreateCompatibleBitmap(&cdc,client.Width(),client.Height());
    dc.SelectObject(junk);
    CBrush fill(BACKGROUND_COLOR);
    dc.FillRect(client,&fill);
    //replace this with something that draws to a CDC
    OnDraw(&dc);
    data->tymed = TYMED_GDI;
    data->hBitmap = HBITMAP(*junk);
    pData->CacheData( CF_BITMAP, data );
    pData->SetClipboard();
    delete data;
    delete junk;
    //delete pData;
}

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-1-7 23:28 | 显示全部楼层
liucqa 发表于 2012-1-6 21:37
剪贴板所有api函数 收藏
2009年11月04日 星期三 10:33
2009年09月02日 下午 11:24

非常感谢!!!!!

TA的精华主题

TA的得分主题

发表于 2019-3-24 12:33 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-19 15:30 , Processed in 0.044325 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表