深入剪贴板编程

来源:互联网 发布:苹果1533支持什么网络 编辑:程序博客网 时间:2024/05/20 06:53

http://wlbookwl.diy.myrice.com/jck/MSVCer/20020113clipspyhot.htm

附演示源程序 ClipSpy (13.4KB)

  剪贴板察看器(Clipboard-viewer)是一种让人感觉很神秘,又很有用的程序。典型的例子就是Windows 98所附带的剪贴板察看程序工具。它可以在任何程序向剪贴板中复制数据或剪贴板被清空时立刻反映这种变化,即使它处于后台运行时,仍具有这种奇妙的能力。那么它是如何实现这种功能的呢?下面的内容会给您以详细的解答,并且给出实现这种功能具体的实现步骤。最后通过一个简单的程序实例来运用这种技术构造一个Spy剪贴板中数据格式的小工具。

1                         技术说明及实现步骤

    剪贴板察看器类程序使用了剪贴板察看器链(Clipboard-viewer chain)这种技术。一个窗口若想在剪贴板重置时,能够被剪贴板通知,它必须向剪贴板注册自己为剪贴板的察看器窗口,剪贴板将若干此类窗口链接在一起,组成剪贴板察看器链。其运行机制如下,每当剪贴板内容重置或链结构改变时,剪贴板便发送消息给链中第一个窗口,第一个窗口响应消息后,发送该消息给链中的下一个窗口,链中每个窗口都重复响应消息、传递消息这个动作,直到链中最后一个窗口。这样,每个窗口通过响应剪贴板的重置消息,就可以根据此时剪贴板情况来执行对应的动作。

    下面介绍一下具体的编程步骤:

    1、将要响应剪贴板重置消息的窗口放入剪贴板察看器链中。可视情况在OnInitDialog()或OnInitialUpdate()中调用基类的SetClipboardViewer()来将窗口插入链中。将该函数返回值保存在私有变量HWND m_hWndNextCBViewer中,该返回值即为链中的下一个窗口句柄。

    2、添加对WM_DRAWCLIPBOARD和WM_CHANGECBCHAIN消息的处理函数OnDrawClipboard()、OnChangeCbChain()。其中OnDrawClipboard()在剪贴板重置时被调用,在其中便可完成程序在剪贴板内容重置进想要完成的任何预定任务。OnChangeCbChain()在链结构改变时被调用,在此处要判断参数hWndRemove是否为链中本窗口的下一个窗口,若是,表明此窗口已在链中清除自己,为保持链的完整性,需要将hWndAfter参数传递的链中此窗口的下一个窗口保存为本窗口的下一个窗口。注意:在这两个函数中,一定要将接收到的消息传递给m_hWndNextCBViewer标识的下一个窗口。

3、添加对WM_DESTROY消息的处理函数OnDestroy()。在函数中调用基类的ChangeClipboardChain()函数,以在窗口销毁时,在察看器链中清除本窗口。

2                         应用范围

    剪贴板察看器链技术,对于那些对自己程序界面要求苛刻或特定方面的编程人员还是很有价值的。如编制Windows窗口应用程序时,一般都会提供粘贴功能,为了方便用户使用,除了在编辑菜单中提供粘贴项外,还会在工具栏中放上粘贴按钮,这种布置方法事实上已经成为Windows程序普遍采用的标准形式。而界面友好的应用程序,为了让用户直观的知道程序现在可否响应粘贴命令,会在程序有能力处理当前剪贴板上数据格式时使能粘贴按钮,而在格式与程序要求不相符时禁止该按钮,这种处理方式要比按下按钮时弹出个消息框或干脆一声不吭要友好的多。但若用MFC的命令状态更新宏来实现这种处理,会发现当程序处于后台运行时,粘贴按钮变了,剪贴板与它无关。这是因为MFC对命令状态更新是当程序处于空闲时(idle-time)才进行的,而后台运行的程序由于消息循环中无消息,当OnIdle()返回FALSE后,消息循环便不再调用它,程序因此也就无法及时反映剪贴板的这种变化。

3                         实例说明

对于一项技术,一段具体的代码最能说明问题了。使用AppWizard建立一个基于对话框的项目ClipSpy。打开对话框模板IDD_CLIPSPY_DIALOG,删掉OK、Cancel按钮及静态文本框,调整对话框边界,只留下标题栏作显示之用,再按技术说明及实现步骤中的编程步骤将文后所附代码添加到项目中,好了,一个实用的小工具就做成了,它会如实的列出你都向剪贴板中复制了什么。

附录

1、头文件

// ClipSpyDlg.h : header file

class CClipSpyDlg : public CDialog

{

private:

       HWND m_hWndNextCBViewer;

};

2、实现文件

// ClipSpyDlg.cpp : implementation file

CClipSpyDlg::CClipSpyDlg(CWnd* pParent /*=NULL*/)

       : CDialog(CClipSpyDlg::IDD, pParent)

{

       m_hWndNextCBViewer=NULL;

}

BOOL CClipSpyDlg::OnInitDialog()

{

       //TODO: 将对话框加入剪贴板察看窗口链中

       m_hWndNextCBViewer=SetClipboardViewer();

}

void CClipSpyDlg::OnDestroy()

{

       //TODO: 从察看链中删除本察看窗口

       ChangeClipboardChain( m_hWndNextCBViewer );

       CDialog::OnDestroy();

}

void CClipSpyDlg::OnDrawClipboard()

{

       //TODO: 剪贴板内容发生变化

       CString sText("ClipSpy-");

       UINT CBFormat[]={

              CF_BITMAP,

              CF_DIB,

              CF_DIF,

              CF_DSPBITMAP,

              CF_DSPENHMETAFILE,

              CF_DSPMETAFILEPICT,

              CF_DSPTEXT,

              CF_ENHMETAFILE,

              CF_HDROP,

              CF_LOCALE,

              CF_METAFILEPICT,

              CF_OEMTEXT,

              CF_OWNERDISPLAY,

              CF_PALETTE,

              CF_PENDATA,

              CF_RIFF,

              CF_SYLK,

              CF_TEXT,

              CF_WAVE,

              CF_TIFF

       };

       char *FormatName[]={

              "CF_BITMAP",

              "CF_DIB",

              "CF_DIF",

              "CF_DSPBITMAP",

              "CF_DSPENHMETAFILE",

              "CF_DSPMETAFILEPICT",

              "CF_DSPTEXT",

              "CF_ENHMETAFILE",

              "CF_HDROP",

              "CF_LOCALE",

              "CF_METAFILEPICT",

              "CF_OEMTEXT",

              "CF_OWNERDISPLAY",

              "CF_PALETTE",

              "CF_PENDATA",

              "CF_RIFF",

              "CF_SYLK",

              "CF_TEXT",

              "CF_WAVE",

              "CF_TIFF",

              "未知格式或剪贴板中无数据"

       };

       //打开剪贴板查询格式类型

       if( OpenClipboard() )

       {

              CString sCBAvailableFormat("");

              int nFormatNum=sizeof(CBFormat)/sizeof(UINT);

              //枚举类型

              for(int i=0;i<nFormatNum;i++)

              {

                     if( ::IsClipboardFormatAvailable( CBFormat[i] ) )

                     {

                            //此处if-else修饰输出格式

                            if( sCBAvailableFormat.IsEmpty() )

                                   sCBAvailableFormat+=FormatName[i];

                            else

                                   sCBAvailableFormat=sCBAvailableFormat+" & "+FormatName[i];

                     }

              }

              if( !sCBAvailableFormat.IsEmpty() )

                     sText+=sCBAvailableFormat;//列出有效格式

              else

                     sText+=FormatName[i];//该格式未知

              ::CloseClipboard();

       }

       //在标题栏中显示格式

       SetWindowText( sText );

       //传WM_DRAWCLIPBOARD给下一个察看窗口

       ::SendMessage(m_hWndNextCBViewer,WM_DRAWCLIPBOARD,0,0);

}

void CClipSpyDlg::OnChangeCbChain(HWND hWndRemove, HWND hWndAfter)

{

       // TODO: 察看链中窗口发生变动

       if( m_hWndNextCBViewer==hWndRemove )

              m_hWndNextCBViewer=hWndAfter;

       //传WM_CHANGECBCHAIN给下一个察看窗口   

       ::SendMessage(m_hWndNextCBViewer,WM_CHANGECBCHAIN,

                     (WPARAM)hWndRemove,(LPARAM)hWndAfter);

}

 

 

原创粉丝点击