概述
1、常规方法
在C#中,有一个常规检测剪贴板的方法,用的是 System.Windows.Forms.Clipboard;
使用起来很简单,代码如下:
/// <summary>
/// 设置剪贴板的文本内容
/// </summary>
/// <param name="s">文本内容</param>
public static void SetText(string s)
{
Clipboard.SetDataObject(s ?? "");
}
/// <summary>
/// 获取剪贴板中的文本内容
/// </summary>
/// <returns>返回剪贴板文本</returns>
public static string GetText()
{
IDataObject iData = Clipboard.GetDataObject();
return (string)iData.GetData(DataFormats.Text);
}
/// <summary>
/// 获取剪贴板位图格式数据(比如从画图软件里复制的图片……)
/// </summary>
/// <returns>位图</returns>
public static Bitmap GetBitmap()
{
IDataObject iData = Clipboard.GetDataObject();
//确定此实例中存储的数据是否与指定的格式关联,或是否可以转换成指定的格式
if (iData.GetDataPresent(DataFormats.Bitmap))
{
Bitmap bt = (Bitmap)iData.GetData(DataFormats.Bitmap);
return bt;
}
return null;
}
2、通知检测剪贴板
常规方法没有通知来告诉我们有数据,所以再来一个带通知的方案:
这个代码比较长……
public partial class Form2 : Form
{
IntPtr nextClipboardViewer;
public Form2()
{
InitializeComponent();
nextClipboardViewer = (IntPtr)SetClipboardViewer((int)Handle);
}
/// <summary>
/// 要处理的 WindowsSystem.Windows.Forms.Message。
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref Message m)
{
// defined in winuser.h
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
DisplayClipboardData();
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
case WM_CHANGECBCHAIN:
if (m.WParam == nextClipboardViewer)
nextClipboardViewer = m.LParam;
else
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
default:
base.WndProc(ref m);
break;
}
}
/// <summary>
/// 显示剪贴板内容
/// </summary>
public void DisplayClipboardData()
{
try
{
IDataObject iData = new DataObject();
iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Rtf))
richTextBox1.Rtf = (string)iData.GetData(DataFormats.Rtf);
else if (iData.GetDataPresent(DataFormats.Text))
richTextBox1.Text = (string)iData.GetData(DataFormats.Text);
else
richTextBox1.Text = "[Clipboard data is not RTF or ASCII Text]";
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
/// <summary>
/// 关闭程序,从观察链移除
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
ChangeClipboardChain(Handle, nextClipboardViewer);
}
#region WindowsAPI
/// <summary>
/// 将CWnd加入一个窗口链,每当剪贴板的内容发生变化时,就会通知这些窗口
/// </summary>
/// <param name="hWndNewViewer">句柄</param>
/// <returns>返回剪贴板观察器链中下一个窗口的句柄</returns>
[DllImport("User32.dll")]
protected static extern int SetClipboardViewer(int hWndNewViewer);
/// <summary>
/// 从剪贴板链中移出的窗口句柄
/// </summary>
/// <param name="hWndRemove">从剪贴板链中移出的窗口句柄</param>
/// <param name="hWndNewNext">hWndRemove的下一个在剪贴板链中的窗口句柄</param>
/// <returns>如果成功,非零;否则为0。</returns>
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
/// <summary>
/// 将指定的消息发送到一个或多个窗口
/// </summary>
/// <param name="hwnd">其窗口程序将接收消息的窗口的句柄</param>
/// <param name="wMsg">指定被发送的消息</param>
/// <param name="wParam">指定附加的消息特定信息</param>
/// <param name="lParam">指定附加的消息特定信息</param>
/// <returns>消息处理的结果</returns>
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
#endregion
}
认真看一下并不难理解,这种带通知的方式更方便操作。
3、代码
另外代码打了个包(Form1是方案一,Form2是方案二)
下载
from:
https://blog.csdn.net/arrowzz/article/details/56689111
=======================
MoreWindows工作笔记12】WM_DRAWCLIPBOARD 监视剪切板
2013年12月31日 16:00:23
阅读数:21767
有很多程序会监视剪贴板,比如迅雷,这样当你复制一个迅雷下载链接时,迅雷就可以自动启动并创建一个新的下载任务。下面我们就来看看如何实现这个技术。
实现这个技术一共需要4步:
第一步:Add the window to the clipboard viewer chain.
通过SetClipboardViewer()传入窗口句柄,所有监视剪贴板的窗口句柄会组成一个链表(后来者靠前)。这样当剪贴板内容发生变化时,Windows系统给给这些窗口发生消息。
第二步:Process the WM_CHANGECBCHAIN message.
当这个监视剪贴板的窗口句柄链表发生变化时,会收到这个消息。每个窗口都应该给下一个窗口传递消息。
这个消息的wParam和lParam说明如下:
wParam表示
A handle to the window being removedfrom the clipboard viewer chain
lParam表示
A handle to the next window in thechain following the window being removed. This parameter is NULL if thewindow being removed is the last window in the chain。
第三步:Process the WM_DRAWCLIPBOARD message.
当剪贴板数据发送变化时,窗口会依次收到这个消息。
第四步:Remove the window from the clipboard viewer chain before itis destroyed.
当窗口关闭时,应该调用ChangeClipboardChain()来通知Windows系统将自己从监视剪贴板的窗口句柄链表中移除。
代码如下(下载地址:http://download.csdn.net/download/morewindows/6793027)
[cpp] view plain copy
- <code class="language-cpp">// 【MoreWindows工作笔记12】WM_DRAWCLIPBOARD 监视剪切板
- // http://blog.csdn.net/morewindows/article/details/17655429
- // By MoreWindows( http://blog.csdn.net/MoreWindows )
- BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
- {
- static HWND s_hwnd_new_clipboard_viewer = NULL;
- static HWND s_hwnd_edit_clipboard_info = NULL;
- switch (message)
- {
- case WM_INITDIALOG:
- // 4-1 Add the window to the clipboard viewer chain.
- s_hwnd_new_clipboard_viewer = SetClipboardViewer(hDlg);
- // 把hwnd加入监视链,返回上一个加入的窗口句柄,如果是第一个,则返回值为NULL。新加的窗口在链条头部,成为“当前监视器”
- CenterWindow(hDlg);
- s_hwnd_edit_clipboard_info = GetDlgItem(hDlg, IDC_EDIT_CLIPBOARD_INFO);
- return FALSE;
- // 4-2 Process the WM_CHANGECBCHAIN message.
- case WM_CHANGECBCHAIN:
- if ((HWND)wParam == s_hwnd_new_clipboard_viewer)
- s_hwnd_new_clipboard_viewer = (HWND)lParam;
- else
- SendMessage(s_hwnd_new_clipboard_viewer, message, wParam, lParam);
- // 4-3 Process the WM_DRAWCLIPBOARD message.
- case WM_DRAWCLIPBOARD: //剪切板内容发生变化
- if (OpenClipboard(hDlg)) {
- UINT clipboard_format = EnumClipboardFormats(0);
- HGLOBAL global_memory = GetClipboardData(clipboard_format);
- DWORD data_size = GlobalSize(global_memory);
- CloseClipboard();
- WCHAR clipboard_info[1024];
- swprintf(clipboard_info, L"Clipboardrn Data Format = %xrn Data Address = 0x%xrn Data Size = %d", clipboard_format, global_memory, data_size);
- if (clipboard_format == CF_UNICODETEXT) {
- LPCWSTR clipboard_data = (LPCWSTR)GlobalLock(global_memory);
- if (clipboard_data != NULL) {
- wcscat(clipboard_info, L"rnData: rn");
- WCHAR buffer[1024];
- DWORD data_size = GlobalSize(global_memory);
- for (size_t i = 0; i < data_size; i++)
- buffer[i] = clipboard_data[i];
- buffer[data_size] = L'