﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-huyi-随笔分类-C/C++/VC</title><link>http://www.blogjava.net/huyi/category/544.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 19:24:08 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 19:24:08 GMT</pubDate><ttl>60</ttl><item><title>在C++中的ODBC API数据库编程</title><link>http://www.blogjava.net/huyi/archive/2005/04/04/2815.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Mon, 04 Apr 2005 01:55:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/04/04/2815.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2815.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/04/04/2815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2815.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2815.html</trackback:ping><description><![CDATA[一、动态加载数据源<BR><FONT size=+0>1</FONT>、通过修改注册表加载数据源：<BR>·用户数据源：<FONT size=+0>HKEY_CURRENT_USER</FONT>＼<FONT size=+0>SOFTWARE</FONT>＼<FONT size=+0>ODBC</FONT>＼<FONT size=+0>ODBC.INI<BR></FONT>·系统数据源：<FONT size=+0>HKEY_LOCAL_MACHINE</FONT>＼<FONT size=+0>SOFTWARE</FONT>＼<FONT size=+0>ODBC</FONT>＼<FONT size=+0>ODBC.INI<BR></FONT>对于不同类型的数据源，注册表的修改也不同，但基本上要修改两个地方，一个是在<FONT size=+0>ODBC.INI</FONT>子键下建立一个与数据源描述名同名的子键，并在该子键下建立与数据源配置相关的项；另一个是在＼<FONT size=+0>ODBC.INI</FONT>＼<FONT size=+0>ODBC Data Sources</FONT>子键下建立一个新项以便告诉驱动程序管理器<FONT size=+0>ODBC</FONT>数据源的类型。<BR><FONT size=+0>2</FONT>、通过<FONT size=+0>ODBC API</FONT>加载：<FONT size=+0>Windows</FONT>系统子目录下的动态链接库<FONT size=+0>Odbcinst.dll</FONT>提供了一个可以动态增加、修改和删除数据源的函数<FONT size=+0>SQLConfigDataSource</FONT>，由于<FONT size=+0>VC</FONT>的默认库文件中不包含此函数，因此使用前需将<FONT size=+0>Odbcinst.h</FONT>文件包含在工程的头文件中，在工程的<FONT size=+0>setting</FONT>属性框<FONT size=+0>Link</FONT>页的<FONT size=+0>Object/library module</FONT>编辑框中增加<FONT size=+0>Odbc32.lib</FONT>，同时保证系统目录<FONT size=+0>system32</FONT>下有文件<FONT size=+0>Odbccp32.dll</FONT>。<BR><FONT size=+0>3</FONT>、文件数据源的连接：除了<FONT size=+0>ODBC</FONT>管理器，还可以通过<FONT size=+0>SQLDriverConnect</FONT>来添加文件数据源。<BR>二、<FONT size=+0>ODBC&nbsp; API</FONT>编程<BR>如果一个<FONT size=+0>ODBC API</FONT>函数执行成功，则返回<FONT size=+0>SQL_SUCCESS</FONT>或<FONT size=+0>SQL_SUCCESS_WITH_INFO</FONT>，<FONT size=+0>SQL_SUCCESS</FONT>指示可通过诊断记录获取有关操作的详细信息，<FONT size=+0>SQL_SUCCESS_WITH_INFO</FONT>指示应用程序执行结果带有警告信息，可通过诊断记录获取详细信息。如果函数调用失败，返回码为<FONT size=+0>SQL_ERROR</FONT>。<BR>一般，编写<FONT size=+0>ODBC</FONT>程序主要有一下几个步骤：<BR><FONT size=+0>1、&nbsp;&nbsp; </FONT>分配环境句柄：声明一个<FONT size=+0>SQLHENV</FONT>的变量，调用函数<FONT size=+0>SQLAllocHandle</FONT>。<BR>设置环境属性：完成环境分配后，用函数<FONT size=+0>SQLSetEnvAttr</FONT>设置环境属性，注册<FONT size=+0>ODBC</FONT>版本号。<BR>释放环境句柄：完成数据访问任务时，应调用<FONT size=+0>SQLFreeHandle</FONT>释放前面分配的环境。<BR><FONT size=+0>2、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>分配连接句柄：声明一个<FONT size=+0>SQLHDBC</FONT>类型的变量，调用<FONT size=+0>SQLAllocHandle</FONT>函数分配句柄。<BR>设置连接属性：所有连接属性都可通过函数<FONT size=+0>SQLSetConnectAttr</FONT>设置，调用函数<FONT size=+0>SQLGetConnectAttr</FONT>可获取这些连接属性的当前设置值。<BR><FONT size=+0>3、&nbsp;&nbsp; </FONT>连接数据源：对于不同的程序和用户接口，可以用不同的函数建立连接<BR><FONT size=+0>SQLConnect</FONT>：该函数只要提供数据源名称、用户<FONT size=+0>ID</FONT>和口令，就可以进行连接了。<BR><FONT size=+0>SQLDriverConnect</FONT>：该函数用一个连接字符串建立至数据源的连接，它可以让用户输入必要的连接信息，使用系统中还没定义的数据源。<BR><FONT size=+0>SQLBrowseConnect</FONT>：该函数支持以一种迭代的方式获取到数据源的连接，直到最后建立连接，它基于客户机／服务器体系结构，因此本地数据库不支持该函数。<BR><FONT size=+0>4、&nbsp;&nbsp; </FONT>准备并执行<FONT size=+0>SQL</FONT>语句<BR><FONT size=+0>A、&nbsp; </FONT>分配语句句柄：语句句柄是通过调用<FONT size=+0>SQLAllocHandle</FONT>函数分配的。<BR>函数<FONT size=+0>SQLGetStmrrAttr</FONT>和<FONT size=+0>SQLSetStmrrAttr</FONT>用来获取和设置一个语句句柄的选项，使用完，调用<FONT size=+0>SQLFreeHandle</FONT>释放该句柄。<BR><FONT size=+0>B、&nbsp; </FONT>执行<FONT size=+0>SQL</FONT>语句<BR><FONT size=+0>SQLExecDirect</FONT>：该函数直接执行<FONT size=+0>SQL</FONT>语句，对于只执行一次的<FONT size=+0>SQL</FONT>语句来说，该函数是执行最快的方法。<BR><FONT size=+0>SQLPrepare</FONT>和<FONT size=+0>SQLExecute</FONT>：对于需要多次执行的<FONT size=+0>SQL</FONT>语句来说，可先调用<FONT size=+0>SQLPrepare</FONT>准备<FONT size=+0>SQL</FONT>语句的执行，用<FONT size=+0>SQLExecute</FONT>执行准备好的语句。<BR><FONT size=+0>C、&nbsp; </FONT>使用参数：使用参数可以使一条<FONT size=+0>SQL</FONT>语句多次执行，得到不同的结果。<BR>函数<FONT size=+0>SQLBindParameter</FONT>负责为参数定义变量，将一段<FONT size=+0>SQL</FONT>语句中的一个参数标识符<FONT size=+0>(</FONT>"？"<FONT size=+0>)</FONT>捆绑在一起，实现参数值的传递。<BR><FONT size=+0>5</FONT>、<FONT size=+0>&nbsp;&nbsp; </FONT>获取记录集<BR><FONT size=+0>A</FONT>、<FONT size=+0>&nbsp;&nbsp; </FONT>绑定列：首先必须分配与记录集中字段相对应的变量，然后通过函数<FONT size=+0>SQLBindCol</FONT>将记录字段同程序变量绑定在一起，对于长记录字段，可以通过调用函数<FONT size=+0>SQLGetData</FONT>直接取回数据。<BR>绑定字段可以根据自己的需要全部绑定，也可以绑定其中的某几个字段。<BR>通过调用函数<FONT size=+0>SQLBindCol</FONT>将变量地址值赋为<FONT size=+0>NULL</FONT>，可以结束对一个记录字段的绑定，通过调用函数<FONT size=+0>SQLFreeStmt</FONT>，将其中选项设为<FONT size=+0>SQL_UNBIND</FONT>，或者直接释放句柄，都会结束所有记录字段的绑定。<BR><FONT size=+0>B</FONT>、<FONT size=+0>SQLFetch</FONT>：该函数用于将记录集的下一行变成当前行，并把所有捆绑过的数据字段的数据拷贝到相应的缓冲区。<BR><FONT size=+0>C</FONT>、<FONT size=+0> </FONT>光标：应用程序获取数据是通过光标<FONT size=+0>(Cursor)</FONT>来实现的，在<FONT size=+0>ODBC</FONT>中，主要有<FONT size=+0>3</FONT>种类型的光标：单向光标、可滚动光标和块光标。<BR>有些应用程序不支持可滚动光标和块光标，<FONT size=+0>ODBC SDK</FONT>提供了一个光标库<FONT size=+0>(ODBCCR32.DLL)</FONT>，在应用程序中可通过设置连接属性<FONT size=+0>(SQL_STTR_ODBC_CURSOR)</FONT>激活光标库。<BR><FONT size=+0>6</FONT>、<FONT size=+0>&nbsp; </FONT>记录的添加、删除和更新：数据源数据更新可通过<FONT size=+0>3</FONT>种方式：通过<FONT size=+0>SQLExecDirect</FONT>函数使用相应的<FONT size=+0>SQL</FONT>语句；调用<FONT size=+0>SQLSetPos</FONT>函数实现记录集定义更新；调用<FONT size=+0>SQLBulkOperations</FONT>函数实现数据更新。<BR>第一种方式适用于任何<FONT size=+0>ODBC</FONT>数据源，后两种方式有的数据源不支持，可调用<FONT size=+0>SQLGetInfo</FONT>确定数据源。<BR><FONT size=+0>SQLBulkOperations</FONT>：该函数操作基于当前行集，调用前，须先调用<FONT size=+0>SQLFetch</FONT>或<FONT size=+0>SQLFetchScroll</FONT>获取。<BR>函数调用后，块光标的位置变为未定义状况，因此，应该先调用函数<FONT size=+0>SQLFetchScroll</FONT>设定光标位置。<BR><FONT size=+0>7</FONT>、错误处理：每个<FONT size=+0>ODBC API</FONT>函数都能产生一系列反映操作信息的诊断记录，可以用<FONT size=+0>SQLGetDiagField</FONT>函数获取诊断记录中特定的域，另外，可以使用<FONT size=+0>SQLGetDiagRec</FONT>获取诊断记录中一些常用的域。<BR><FONT size=+0>8</FONT>、事务处理：事务提交有两种方式：自动提交模式和手动提交模式。应用程序可通过调用函数<FONT size=+0>SQLSetConnectAttr</FONT>设定连接属性<FONT size=+0>SQL_ATTR_AUTOCOMMIT</FONT>，自动提交模式是默认的连接属性设置，对于所有的<FONT size=+0>ODBC</FONT>驱动程序都能适应这种模式下，所有语句都是作为一个独立的事务进行处理的。<BR>手动提交模式把一组<FONT size=+0>SQL</FONT>语句放入一个事务中，程序必须调用函数<FONT size=+0>SQLEenTran</FONT>明确地终止一个事务。若使用多个激活的事务，就必须建立多个连接，每一个连接包含一个事务。<BR><FONT size=+0>9</FONT>、断开数据连接并释放环境句柄：完成数据库操作后，可调用<FONT size=+0>SQLDisconnect</FONT>函数关闭同数据库的连接。<img src ="http://www.blogjava.net/huyi/aggbug/2815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-04-04 09:55 <a href="http://www.blogjava.net/huyi/archive/2005/04/04/2815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转贴:浅谈HOOK技术在VC编程中的应用</title><link>http://www.blogjava.net/huyi/archive/2005/03/30/2622.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Wed, 30 Mar 2005 12:55:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/30/2622.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2622.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/30/2622.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2622.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2622.html</trackback:ping><description><![CDATA[<SPAN id=ArticleContent1_ArticleContent1_lblContent>　　摘要： 本文针对HOOK技术在VC编程中的应用进行讨论，并着重对应用比较广泛的全局HOOK做了阐述。<BR>
<P>　　<B>引言</B></P>
<P>　　Windows操作系统是建立在事件驱动机制之上的，系统各部分之间的沟通也都是通过消息的相互传递而实现的。但在通常情况下，应用程序只能处理来自进程内部的消息或是从其他进程发过来的消息，如果需要对在进程外传递的消息进行拦截处理就必须采取一种被称为HOOK（钩子）的技术。钩子是Windows操作系统中非常重要的一种系统接口，用它可以轻松截获并处理在其他应用程序之间传递的消息，并由此可以完成一些普通应用程序难以实现的特殊功能。基于钩子在消息拦截处理中的强大功能，本文即以VC++ 6.0为编程背景对钩子的基本概念及其实现过程展开讨论。为方便理解，在文章最后还给出了一个简单的有关鼠标钩子的应用示例。</P>
<P>　　<B>钩子的基本原理</B></P>
<P>　　钩子的本质是一段用以处理系统消息的程序，通过系统调用，将其挂入到系统。钩子的种类有很多，每一种钩子负责截获并处理相应的消息。钩子机制允许应用程序截获并处理发往指定窗口的消息或特定事件，其监视的窗口即可以是本进程内的也可以是由其他进程所创建的。在特定的消息发出，并在到达目的窗口之前，钩子程序先行截获此消息并得到对其的控制权。此时在钩子函数中就可以对截获的消息进行各种修改处理，甚至强行终止该消息的继续传递。 </P>
<P>　　任何一个钩子都由系统来维护一个指针列表（钩子链表），其指针指向钩子的各个处理函数。最近安装的钩子放在链的开始，最早安装的钩子则放在最后，当钩子监视的消息出现时，操作系统调用链表开始处的第一个钩子处理函数进行处理，也就是说最后加入的钩子优先获得控制权。在这里提到的钩子处理函数必须是一个回调函数（callback function），而且不能定义为类成员函数，必须定义为普通的C函数。在使用钩子时可以根据其监视范围的不同将其分为全局钩子和线程钩子两大类，其中线程钩子只能监视某个线程，而全局钩子则可对在当前系统下运行的所有线程进行监视。显然，线程钩子可以看作是全局钩子的一个子集，全局钩子虽然功能强大但同时实现起来也比较烦琐：其钩子函数的实现必须封装在动态链接库中才可以使用。</P>
<P>　　<B>钩子的安装与卸载</B></P>
<P>　　由于全局钩子具有相当的广泛性而且在功能上完全覆盖了线程钩子，因此下面就主要对应用较多的全局钩子的安装与使用进行讨论。前面已经提过，操作系统是通过调用钩子链表开始处的第一个钩子处理函数而进行消息拦截处理的。因此，为了设置钩子，只需将回调函数放置于链首即可，操作系统会使其首先被调用。在具体实现时由函数SetWindowsHookEx()负责将回调函数放置于钩子链表的开始位置。SetWindowsHookEx()函数原型声明如下:</P>
<P>HHOOK SetWindowsHookEx(int idHook;<BR>HOOKPROC lpfn;<BR>HINSTANCE hMod;<BR>DWORD dwThreadId);</P>
<P>　　其中：参数idHook 指定了钩子的类型，总共有如下13种： <BR><BR>　　　WH_CALLWNDPROC 系统将消息发送到指定窗口之前的"钩子" <BR>　　　WH_CALLWNDPROCRET 消息已经在窗口中处理的"钩子" <BR>　　　WH_CBT 基于计算机培训的"钩子" <BR>　　　WH_DEBUG 差错"钩子" <BR>　　　WH_FOREGROUNDIDLE 前台空闲窗口"钩子" <BR>　　　WH_GETMESSAGE 接收消息投递的"钩子" <BR>　　　WH_JOURNALPLAYBACK 回放以前通过WH_JOURNALRECORD"钩子"记录的输入消息 <BR>　　　WH_JOURNALRECORD 输入消息记录"钩子" <BR>　　　WH_KEYBOARD 键盘消息"钩子" <BR>　　　WH_MOUSE 鼠标消息"钩子" <BR>　　　WH_MSGFILTER 对话框、消息框、菜单或滚动条输入消息"钩子" <BR>　　　WH_SHELL 外壳"钩子" <BR>　　　WH_SYSMSGFILTER 系统消息"钩子" <BR><BR>　　参数lpfn为指向钩子处理函数的指针，即回调函数的首地址；参数hMod则标识了钩子处理函数所处模块的句柄；第四个参数dwThreadId 指定被监视的线程，如果明确指定了某个线程的ID就只监视该线程，此时的钩子即为线程钩子；如果该参数被设置为0，则表示此钩子为监视系统所有线程的全局钩子。此函数在执行完后将返回一个钩子句柄。</P>
<P>　　虽然对于线程钩子并不要求其象全局钩子一样必须放置于动态链接库中，但是推荐其也在动态链接库中实现。因为这样的处理不仅可使钩子可为系统内的多个进程访问，也可以在系统中被直接调用，而且对于一个只供单进程访问的钩子，还可以将其钩子处理过程放在安装钩子的同一个线程内，此时SetWindowsHookEx()函数的第三个参数也就是该线程的实例句柄。</P>
<P>　　在SetWindowsHookEx()函数完成对钩子的安装后，如果被监视的事件发生，系统马上会调用位于相应钩子链表开始处的钩子处理函数进行处理，每一个钩子处理函数在进行相应的处理时都要考虑是否需要把事件传递给下一个钩子处理函数。如果要传递，就通过函数CallNestHookEx()来解决。尽管如此，在实际使用时还是强烈推荐无论是否需要事件传递而都在过程的最后调用一次CallNextHookEx( )函数，否则将会引起一些无法预知的系统行为或是系统锁定。该函数将返回位于钩子链表中的下一个钩子处理过程的地址，至于具体的返回值类型则要视所设置的钩子类型而定。该函数的原型声明如下：</P>
<P>LRESULT CallNextHookEx(HHOOK hhk;int nCode;WPARAM wParam;LPARAM lParam);</P>
<P>　　其中，参数hhk为由SetWindowsHookEx()函数返回的当前钩子句柄；参数nCode为传给钩子过程的事件代码；参数wParam和lParam 则为传给钩子处理函数的参数值，其具体含义同设置的钩子类型有关。</P>
<P>　　最后，由于安装钩子对系统的性能有一定的影响，所以在钩子使用完毕后应及时将其卸载以释放其所占资源。释放钩子的函数为UnhookWindowsHookEx()，该函数比较简单只有一个参数用于指定此前由SetWindowsHookEx()函数所返回的钩子句柄，原型声明如下：</P>
<P>BOOL UnhookWindowsHookEx(HHOOK hhk);<BR><BR><SPAN class=f14>　　<B>鼠标钩子的简单示例</B> </P>
<P></P>
<P>　　最后，为更清楚展示HOOK技术在VC编程中的应用，给出一个有关鼠标钩子使用的简单示例。在钩子设置时采用的是全局钩子。下面就对鼠标钩子的安装、使用以及卸载等过程的实现进行讲述：</P>
<P>　　由于本例程需要使用全局钩子，因此首先构造全局钩子的载体--动态链接库。考虑到　Win32 DLL与Win16 DLL存在的差别，在Win32环境下要在多个进程间共享数据，就必须采取一些措施将待共享的数据提取到一个独立的数据段，并通过def文件将其属性设置为读写共享：</P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>#pragma data_seg("TestData")<BR>HWND glhPrevTarWnd=NULL; // 窗口句柄<BR>HWND glhHook=NULL; // 鼠标钩子句柄<BR>HINSTANCE glhInstance=NULL; // DLL实例句柄<BR>#pragma data_seg()<BR>……<BR>SECTIONS // def文件中将数据段TestData设置为读写共享<BR>TestData READ WRITE SHARED</TD></TR></TBODY></TABLE></P>
<P>　　在安装全局鼠标钩子时使用函数SetWindowsHookEx()，并设定鼠标钩子的处理函数为MouseProc()，安装函数返回的钩子句柄保存于变量glhHook中：</P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>void StartHook(HWND hWnd)<BR>{<BR>……<BR>glhHook=(HWND)SetWindowsHookEx(WH_MOUSE,MouseProc,glhInstance,0);<BR>}</TD></TR></TBODY></TABLE></P>
<P>　　鼠标钩子安装好后，在移动、点击鼠标时将会发出鼠标消息，这些消息均经过消息处理函数MouseProc()的拦截处理。在此，每当捕获到系统各线程发出的任何鼠标消息后首先获取当前鼠标所在位置下的窗口句柄，并进一步通过GetWindowText()函数获取到窗口标题。在处理函数完成后，通过CallNextHookEx()函数将事件传递到钩子列表中的下一个钩子处理函数：</P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>LRESULT WINAPI MouseProc(int nCode,WPARAM wParam,LPARAM lParam)<BR>{<BR>LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *) lParam;<BR>if(nCode&gt;=0)<BR>{<BR>HWND glhTargetWnd=pMouseHook-&gt;hwnd; <BR>//取目标窗口句柄 <BR>HWND ParentWnd=glhTargetWnd; <BR>while(ParentWnd !=NULL)<BR>{<BR>glhTargetWnd=ParentWnd; <BR>//取应用程序主窗口句柄 <BR>ParentWnd=GetParent(glhTargetWnd); <BR>} <BR>if(glhTargetWnd!=glhPrevTarWnd) <BR>{ <BR>char szCaption[100]; <BR>//取目标窗口标题 <BR>GetWindowText(glhTargetWnd,szCaption,100); <BR>……<BR>} <BR>}<BR>//继续传递消息 <BR>return CallNextHookEx((HHOOK)glhHook,nCode,wParam,lParam); <BR>}</TD></TR></TBODY></TABLE></P>
<P>　　最后，调用UnhookWindowsHookEx()函数完成对钩子的卸载：</P>
<P>
<TABLE width="100%" bgColor=#ffffff>
<TBODY>
<TR>
<TD>void StopHook()<BR>{<BR>……<BR>UnhookWindowsHookEx((HHOOK)glhHook);<BR>}</TD></TR></TBODY></TABLE></P>
<P>　　现在完成的是鼠标钩子的动态链接库，经过编译后需要经应用程序的调用才能实现对当前系统下各线程间鼠标消息的拦截处理。这部分同普通动态链接库的使用没有任何区别，在将其加载到进程后，首先调用动态链接库的StartHook()函数安装好钩子，此时即可对系统下的鼠标消息实施拦截处理，在动态链接库被卸载即终止鼠标钩子时通过动态链接库中的StopHook()函数卸载鼠标钩子。</P>
<P>　　经上述编程，在安装好鼠标钩子后，鼠标在移动到系统任意窗口上时，马上就会通过对鼠标消息的拦截处理而获取到当前窗口的标题。实验证明此鼠标钩子的安装、使用和卸载过程是正确的。</P>
<P>　　<B>小结</B></P>
<P>　　钩子，尤其是系统钩子具有相当强大的功能，通过这种技术可以对几乎所有的Windows系统消息和事件进行拦截处理。这种技术广泛应用于各种自动监控系统对进程外消息的监控处理。本文只对钩子的一些基本原理和一般的使用方法做了简要的探讨，感兴趣的读者完全可以在本文所述代码基础之上用类似的方法实现对诸如键盘钩子、外壳钩子等其他类型钩子的安装与使用。本文所述代码在Windows 98下由Microsoft Visual C++ 6.0编译通过。</P></SPAN></SPAN><img src ="http://www.blogjava.net/huyi/aggbug/2622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-30 20:55 <a href="http://www.blogjava.net/huyi/archive/2005/03/30/2622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转贴:APIHOOK实例剖析 </title><link>http://www.blogjava.net/huyi/archive/2005/03/30/2621.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Wed, 30 Mar 2005 12:45:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/30/2621.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2621.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/30/2621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2621.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2621.html</trackback:ping><description><![CDATA[一、APIHOOK之dll部分<BR>&nbsp;<BR>//////////////////////////////// APIHook_Dll.cpp ////////////////////////////////////////<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rivershan写于2002.9.23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>///////////////////////////////////////////////////////////////////////////////////////// 
<P>#include "stdafx.h"<BR>#include "APIHook_Dll.h"</P>
<P>#include &lt;ImageHlp.h&gt;<BR>#include &lt;tlhelp32.h&gt;</P>
<P>#pragma comment(lib,"ImageHlp") //定义全局共享数据段</P>
<P>#pragma data_seg("Shared")<BR>HMODULE hmodDll=NULL;<BR>HHOOK hHook=NULL;</P>
<P>#pragma data_seg()</P>
<P>#pragma comment(linker,"/Section:Shared,rws") //设置全局共享数据段的属性</P>
<P>///////////////////////////////////// DllMain 函数 /////////////////////////////////////////<BR>//dll的入口点<BR>BOOL APIENTRY DllMain( HMODULE hModule, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD&nbsp; ul_reason_for_call, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPVOID lpReserved<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<BR>{<BR>&nbsp;switch(ul_reason_for_call)<BR>&nbsp;{<BR>&nbsp;case DLL_PROCESS_ATTACH:<BR>&nbsp;&nbsp;//if(sHook)&nbsp;&nbsp;<BR>&nbsp;&nbsp;<BR>&nbsp;case DLL_PROCESS_DETACH:<BR>&nbsp;&nbsp;UnInstallHook();<BR>&nbsp;&nbsp;break;<BR>&nbsp;}<BR>&nbsp;hmodDll=hModule;<BR>&nbsp;&nbsp;&nbsp; return TRUE;<BR>}</P>
<P>///////////////////////////////////// HookOneAPI 函数 /////////////////////////////////////////<BR>//进行IAT转换的关键函数，其参数含义：<BR>//pszCalleeModuleName：需要hook的模块名<BR>//pfnOriginApiAddress：要替换的自己API函数的地址<BR>//pfnDummyFuncAddress：需要hook的模块名的地址<BR>//hModCallerModule：我们要查找的模块名称，如果没有被赋值，<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将会被赋值为枚举的程序所有调用的模块</P>
<P>void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROC pfnDummyFuncAddress,HMODULE hModCallerModule)<BR>{<BR>&nbsp;ULONG size;</P>
<P>&nbsp;//获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针</P>
<P>&nbsp;PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)<BR>&nbsp;&nbsp;ImageDirectoryEntryToData(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&amp;size);</P>
<P>&nbsp;if (pImportDesc == NULL)<BR>&nbsp;&nbsp;return;</P>
<P>&nbsp;//查找记录,看看有没有我们想要的DLL</P>
<P>&nbsp;for (;pImportDesc-&gt;Name;pImportDesc++)<BR>&nbsp;{<BR>&nbsp;&nbsp;LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc-&gt;Name);<BR>&nbsp;&nbsp;if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0)<BR>&nbsp;&nbsp;&nbsp;break;<BR>&nbsp;}</P>
<P>&nbsp;if (pImportDesc-&gt;Name == NULL)<BR>&nbsp;{<BR>&nbsp;&nbsp;return;<BR>&nbsp;}</P>
<P>&nbsp;//寻找我们想要的函数</P>
<P>&nbsp;PIMAGE_THUNK_DATA pThunk = <BR>&nbsp;&nbsp;(PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc-&gt;FirstThunk);//IAT<BR>&nbsp;for (;pThunk-&gt;u1.Function;pThunk++)<BR>&nbsp;{<BR>&nbsp;&nbsp;//ppfn记录了与IAT表项相应的函数的地址</P>
<P>&nbsp;&nbsp;PROC * ppfn= (PROC *)&amp;pThunk-&gt;u1.Function;&nbsp;&nbsp;<BR>&nbsp;&nbsp;if (*ppfn == pfnOriginApiAddress) <BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;//如果地址相同，也就是找到了我们想要的函数，进行改写，将其指向我们所定义的函数</P>
<P>&nbsp;&nbsp;&nbsp;WriteProcessMemory(GetCurrentProcess(),ppfn,&amp;(pfnDummyFuncAddress),<BR>&nbsp;&nbsp;&nbsp;&nbsp;sizeof(pfnDummyFuncAddress),NULL);<BR>&nbsp;&nbsp;&nbsp;return;<BR>&nbsp;&nbsp;}<BR>&nbsp;}<BR>}</P>
<P>//查找所挂钩的进程所应用的dll模块的</P>
<P>BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROC pfnDummyFuncAddress,HMODULE hModCallerModule)<BR>{<BR>&nbsp;if (pszCalleeModuleName == NULL)<BR>&nbsp;{<BR>&nbsp;&nbsp;return FALSE;<BR>&nbsp;}<BR>&nbsp;if (pfnOriginApiAddress == NULL)<BR>&nbsp;{<BR>&nbsp;&nbsp;return FALSE;<BR>&nbsp;}<BR>&nbsp;//如果没传进来要挂钩的模块名称，枚举被挂钩进程的所有引用的模块，<BR>&nbsp;//并对这些模块进行传进来的相应函数名称的查找<BR>&nbsp;<BR>&nbsp;if (hModCallerModule == NULL)<BR>&nbsp;{<BR>&nbsp;&nbsp;MEMORY_BASIC_INFORMATION mInfo;<BR>&nbsp;&nbsp;HMODULE hModHookDLL;<BR>&nbsp;&nbsp;HANDLE hSnapshot;<BR>&nbsp;&nbsp;MODULEENTRY32 me = {sizeof(MODULEENTRY32)};<BR>&nbsp;&nbsp;//MODULEENTRY32:描述了一个被指定进程所应用的模块的struct</P>
<P>&nbsp;&nbsp;VirtualQuery(HookOneAPI,&amp;mInfo,sizeof(mInfo));<BR>&nbsp;&nbsp;hModHookDLL=(HMODULE)mInfo.AllocationBase;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0);<BR>&nbsp;&nbsp;BOOL bOk = Module32First(hSnapshot,&amp;me);<BR>&nbsp;&nbsp;while (bOk)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if (me.hModule != hModHookDLL)<BR>&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;hModCallerModule = me.hModule;//赋值<BR>&nbsp;&nbsp;&nbsp;&nbsp;//me.hModule:指向当前被挂钩进程的每一个模块 <BR>&nbsp;&nbsp;&nbsp;&nbsp;HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pfnDummyFuncAddress,hModCallerModule);<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;bOk = Module32Next(hSnapshot,&amp;me);<BR>&nbsp;&nbsp;}<BR>&nbsp;&nbsp;return TRUE;&nbsp;&nbsp;<BR>&nbsp;}<BR>&nbsp;//如果传进来了，进行查找<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;HookOneAPI(pszCalleeModuleName,pfnOriginApiAddress,<BR>&nbsp;&nbsp;&nbsp;&nbsp;pfnDummyFuncAddress,hModCallerModule);<BR>&nbsp;&nbsp;return TRUE;<BR>&nbsp;}<BR>&nbsp;return FALSE;<BR>}</P>
<P>//////////////////////////////////// UnhookAllAPIHooks 函数 /////////////////////////////////////<BR>//通过使pfnDummyFuncAddress与pfnOriginApiAddress相等的方法，取消对IAT的修改<BR>BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROC pfnDummyFuncAddress,HMODULE hModCallerModule)<BR>{<BR>&nbsp;PROC temp;<BR>&nbsp;temp = pfnOriginApiAddress;<BR>&nbsp;pfnOriginApiAddress = pfnDummyFuncAddress;<BR>&nbsp;pfnDummyFuncAddress = temp;<BR>&nbsp;return HookAllAPI(pszCalleeModuleName,pfnOriginApiAddress,<BR>&nbsp;&nbsp;pfnDummyFuncAddress,hModCallerModule);<BR>}</P>
<P>////////////////////////////////// GetMsgProc 函数 ////////////////////////////////////////<BR>//钩子子程。与其它钩子子程不大相同，没做什么有意义的事情，继续调用下一个钩子子程，形成循环<BR>LRESULT CALLBACK GetMsgProc(int code,WPARAM wParam,LPARAM lParam)<BR>{<BR>&nbsp;return CallNextHookEx(hHook,code,wParam,lParam);<BR>}</P>
<P>//////////////////////////////////// InstallHook 函数 /////////////////////////////////////<BR>//安装或卸载钩子，BOOL IsHook参数是标志位<BR>//对要钩哪个API函数进行初始化<BR>//我们这里装的钩子类型是WH_GETMESSAGE<BR>void __declspec(dllexport) WINAPI InstallHook(BOOL IsHook,DWORD dwThreadId)<BR>{<BR>&nbsp;if(IsHook)<BR>&nbsp;{<BR>&nbsp;hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgProc,hmodDll,dwThreadId);<BR>&nbsp;<BR>&nbsp;//GetProcAddress(GetModuleHandle("GDI32.dll"),"ExtTextOutA")：取得要钩的函数在所在dll中的地址<BR>&nbsp;<BR>&nbsp;HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),<BR>&nbsp;&nbsp;"TextOutW"),(PROC)&amp;H_TextOutW,NULL);<BR>&nbsp;HookAllAPI("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),<BR>&nbsp;&nbsp;"TextOutA"),(PROC)&amp;H_TextOutA,NULL);<BR>&nbsp;}<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;UnInstallHook();<BR>&nbsp;&nbsp;UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),<BR>&nbsp;&nbsp;&nbsp;"TextOutW"),(PROC)&amp;H_TextOutW,NULL);<BR>&nbsp;&nbsp;UnhookAllAPIHooks("GDI32.dll",GetProcAddress(GetModuleHandle("GDI32.dll"),<BR>&nbsp;&nbsp;&nbsp;"TextOutA"),(PROC)&amp;H_TextOutA,NULL);<BR>&nbsp;}<BR>}</P>
<P>///////////////////////////////////// UnInstallHook 函数 ////////////////////////////////////<BR>//卸载钩子<BR>BOOL WINAPI UnInstallHook()<BR>{<BR>&nbsp;UnhookWindowsHookEx(hHook);<BR>&nbsp;return TRUE;<BR>}</P>
<P>///////////////////////////////////// H_TextOutA 函数 /////////////////////////////////////////<BR>//我们的替换函数，可以在里面实现我们所要做的功能<BR>//这里我做的是显示一个对话框，指明是替换了哪个函数<BR>BOOL WINAPI H_TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpString,int cbString)<BR>{<BR>&nbsp;MessageBox(NULL,"TextOutA","APIHook_Dll ---rivershan",MB_OK);<BR>&nbsp;TextOutA(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数，以显示字符<BR>&nbsp;return TRUE;<BR>}</P>
<P>///////////////////////////////////// H_TextOutW 函数 /////////////////////////////////////////<BR>//同上<BR>BOOL WINAPI H_TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpString,int cbString)<BR>{<BR>&nbsp;MessageBox(NULL,"TextOutW","APIHook_Dll ---rivershan",MB_OK);<BR>&nbsp;TextOutW(hdc,nXStart,nYStart,lpString,cbString);//返回原来的函数，以显示字符<BR>&nbsp;return TRUE;<BR>}</P>
<P>**********************************************************************************************<BR>**********************************************************************************************</P>
<P>//////////////////////////////// APIHook_Dll.h ////////////////////////////////////////<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rivershan写于2002.9.23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>/////////////////////////////////////////////////////////////////////////////////////////</P>
<P>//dll头文件，用于声明函数</P>
<P>void __declspec(dllexport) WINAPI InstallHook(BOOL,DWORD);<BR>BOOL WINAPI UnInstallHook();<BR>LRESULT CALLBACK GetMsgProC(int code,WPARAM wParam,LPARAM lParam);</P>
<P>void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROC pfnDummyFuncAddress,HMODULE hModCallerModule);<BR>BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROC pfnDummyFuncAddress,HMODULE hModCallerModule);<BR>BOOL WINAPI UnhookAllAPIHooks(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PROC pfnDummyFuncAddress,HMODULE hModCallerModule);</P>
<P>BOOL WINAPI H_TextOutA(HDC, int, int, LPCSTR, int);<BR>BOOL WINAPI H_TextOutW(HDC, int, int, LPCWSTR, int);<BR>BOOL WINAPI H_ExtTextOutA(HDC, int, int, UINT, CONST RECT *,LPCSTR, UINT, CONST INT *);<BR>BOOL WINAPI H_ExtTextOutW(HDC, int, int, UINT, CONST RECT *,LPCWSTR, UINT, CONST INT *);</P>
<P>**********************************************************************************************<BR>**********************************************************************************************</P>
<P>;APIHook_Dll之def文件<BR>LIBRARY APIHook_Dll<BR>EXPORTS<BR>&nbsp; InstallHook @1<BR>&nbsp;<BR>二、APIHOOK之exe部分</P>
<P>//////////////////////////// APIHook_EXEDlg.cpp /////////////////////////////////////////<BR>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rivershan写于2002.9.23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //<BR>/////////////////////////////////////////////////////////////////////////////////////////</P>
<P><BR>#include "stdafx.h"<BR>#include "APIHook_EXE.h"<BR>#include "APIHook_EXEDlg.h"<BR>#include "APIHook_Dll.h"</P>
<P>#ifdef _DEBUG<BR>#define new DEBUG_NEW<BR>#undef THIS_FILE<BR>static char THIS_FILE[] = __FILE__;<BR>#endif</P>
<P>/////////////////////////////////////////////////////////////////////////////<BR>// CAPIHook_EXEDlg dialog</P>
<P>CAPIHook_EXEDlg::CAPIHook_EXEDlg(CWnd* pParent /*=NULL*/)<BR>: CDialog(CAPIHook_EXEDlg::IDD, pParent)<BR>{<BR>&nbsp;//{{AFX_DATA_INIT(CAPIHook_EXEDlg)<BR>&nbsp;// NOTE: the ClassWizard will add member initialization here<BR>&nbsp;//}}AFX_DATA_INIT<BR>&nbsp;// Note that LoadIcon does not require a subsequent DestroyIcon in Win32<BR>&nbsp;m_hIcon = AfxGetApp()-&gt;LoadIcon(IDR_MAINFRAME);<BR>}</P>
<P>void CAPIHook_EXEDlg::DoDataExchange(CDataExchange* pDX)<BR>{<BR>&nbsp;CDialog::DoDataExchange(pDX);<BR>&nbsp;//{{AFX_DATA_MAP(CAPIHook_EXEDlg)<BR>&nbsp;//&nbsp;DDX_Control(pDX, IDC_EDIT1, m_Edit);<BR>&nbsp;//}}AFX_DATA_MAP<BR>}</P>
<P>BEGIN_MESSAGE_MAP(CAPIHook_EXEDlg, CDialog)<BR>//{{AFX_MSG_MAP(CAPIHook_EXEDlg)<BR>ON_WM_PAINT()<BR>ON_WM_QUERYDRAGICON()<BR>&nbsp;ON_BN_CLICKED(IDC_BUTTON_OUT, OnButtonOut)<BR>&nbsp;ON_BN_CLICKED(IDC_BUTTON_BEGIN, OnButtonBegin)<BR>&nbsp;ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)<BR>&nbsp;//}}AFX_MSG_MAP<BR>END_MESSAGE_MAP()</P>
<P>/////////////////////////////////////////////////////////////////////////////<BR>// CAPIHook_EXEDlg message handlers</P>
<P>BOOL CAPIHook_EXEDlg::OnInitDialog()<BR>{<BR>&nbsp;CDialog::OnInitDialog();<BR>&nbsp;<BR>&nbsp;// Set the icon for this dialog.&nbsp; The framework does this automatically<BR>&nbsp;// when the application's main window is not a dialog<BR>&nbsp;SetIcon(m_hIcon, TRUE);&nbsp;&nbsp;&nbsp;// Set big icon<BR>&nbsp;SetIcon(m_hIcon, FALSE);&nbsp;&nbsp;// Set small icon<BR>&nbsp;<BR>&nbsp;// TODO: Add extra initialization here<BR>&nbsp;<BR>&nbsp;return TRUE;&nbsp; // return TRUE&nbsp; unless you set the focus to a control<BR>}</P>
<P>// If you add a minimize button to your dialog, you will need the code below<BR>//&nbsp; to draw the icon.&nbsp; For MFC applications using the document/view model,<BR>//&nbsp; this is automatically done for you by the framework.</P>
<P>void CAPIHook_EXEDlg::OnPaint() <BR>{<BR>&nbsp;if (IsIconic())<BR>&nbsp;{<BR>&nbsp;&nbsp;CPaintDC dc(this); // device context for painting<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;// Center icon in client rectangle<BR>&nbsp;&nbsp;int cxIcon = GetSystemMetrics(SM_CXICON);<BR>&nbsp;&nbsp;int cyIcon = GetSystemMetrics(SM_CYICON);<BR>&nbsp;&nbsp;CRect rect;<BR>&nbsp;&nbsp;GetClientRect(&amp;rect);<BR>&nbsp;&nbsp;int x = (rect.Width() - cxIcon + 1) / 2;<BR>&nbsp;&nbsp;int y = (rect.Height() - cyIcon + 1) / 2;<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;// Draw the icon<BR>&nbsp;&nbsp;dc.DrawIcon(x, y, m_hIcon);<BR>&nbsp;}<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;CDialog::OnPaint();<BR>&nbsp;}<BR>}</P>
<P>// The system calls this to obtain the cursor to display while the user drags<BR>//&nbsp; the minimized window.<BR>HCURSOR CAPIHook_EXEDlg::OnQueryDragIcon()<BR>{<BR>&nbsp;return (HCURSOR) m_hIcon;<BR>}<BR>///////////////////////////////////// OnButtonOut 函数 //////////////////////////////////////<BR>//使用TextOut函数<BR>void CAPIHook_EXEDlg::OnButtonOut() <BR>{<BR>&nbsp;// TODO: Add your control notification handler code here<BR>&nbsp;HDC hdc = ::GetDC(GetSafeHwnd());<BR>&nbsp;::TextOutA(hdc,0,0,"APIHOOK_EXE ---rivershan",30);<BR>&nbsp;UpdateWindow();<BR>}</P>
<P>///////////////////////////////////// OnButtonBegin 函数 ////////////////////////////////////<BR>//开始挂钩，这里我们挂的是自身这个APIHook_EXE这个程序<BR>void CAPIHook_EXEDlg::OnButtonBegin()<BR>{<BR>&nbsp;DWORD dwThreadId = GetWindowThreadProcessId(m_hWnd,NULL);//获得自身进程ID<BR>&nbsp;InstallHook(TRUE,dwThreadId);<BR>}</P>
<P>///////////////////////////////////// OnButtonStop 函数 ////////////////////////////////////<BR>//取消挂钩<BR>void CAPIHook_EXEDlg::OnButtonStop()<BR>{<BR>&nbsp;InstallHook(FALSE,0);<BR>}</P>
<P>三、APIHOOK之集成</P>
<P>1. 用 VC++新建一个 Win32 Dynamic-Link Library 程序，命名为 APIHook_Dll。接下来选择第二项 A Simple DLL Project；<BR>2. 新建一头文件，命名为 APIHook_Dll.h。删除工程中 APIHook_Dll.cpp文件中原来的内容，然后把上面的 APIHook_Dll.cpp 和 APIHook_Dll.h文件的内容全部复制到新建的这个工程的 .cpp及 .h文件中来；<BR>3. 新建一 Text文件，命名为 APIHook_Dll.def。复制上面的def文件内容。<BR>4. 编译；<BR>5. 新建一 MFC APPWizard(exe)程序，命名为 APIHook_EXE。接着选择第三项，基于对话框的程序，其它默认；<BR>6. 删除原来对话框上的控件，然后新建三个按钮ID分别为：IDC_BUTTON_BEGIN、IDC_BUTTON_STOP、IDC_BUTTON_OUT，Caption分别为：Bigin Hook、Stop Hook、Text Out。不要让这三个按钮出于对话框客户区的最上面就行；<BR>7. 拷贝 APIHook_Dll.h文件到 APIHook_EXE程序目录下，然后加到 APIHook_EXE的头文件夹中。<BR>8. 删除工程中 APIHook_EXEDlg.cpp文件中原来的内容，然后把上面的 APIHook_EXEDlg.cpp文件的内容全部复制到新建的这个工程的 .cpp文件中来；<BR>9. 打开 Project-&gt;Setting菜单，选择第四项link，在 Object/library moduls里添加我们的dll的lib文件的路径：..\APIHook_Dll\Debug\APIHook_Dll.lib；<BR>10. 编译；<BR>11. 把 APIHook_Dll.dll文件放在 APIHook_Dll.exe程序的同一个文件夹内；<BR>12. 运行程序，点击 Bigin Hook按钮，开始挂钩。再点击 Text Out按钮会跳出对话框并且会在程序中显示所要显示的字。点击 Stop Hook然后在点击 Text Out按钮就没有对话框出现了。</P>
<P>四、一些说明</P>
<P>1、我这个 HookAPI是使用了 Jeffrey Richter的改写程序的 IAT来实现的，也可以用跳转函数入口点的方法来实现，这个我没做研究。：）</P>
<P>2、我的一些心得：</P>
<P>&nbsp;所谓 HookAPI，就是改写程序的 IAT，再调用我自己写的用于替换原API函数的函数。在我们自己写的API函数中，我们可以进行我们想要的工作。之后呢，可以把原来的函数传回去，也可以不传回去，只要你设计好了就行。</P>
<P>&nbsp;而所谓调用自己的函数,就是把原函数参数都传给我的替换函数。我们就可以利用这些参数去干我们想做的事。而系统呢，我想由于微软设置的这个钩子的目的（我这么认为的），所以不会去检查替换函数是否就是原函数，只要参数、返回值符合条件就行，要不会出错。替换函数的返回值最好是原函数，否则有可能会出错</P>
<P>&nbsp;HookAPI时，exe程序起到的作用就是进行Hook，把dll注入到要Hook的程序，并且传回要挂接的进程的ID或者全局钩子，以便查询所要挂接的模块的IAT。如果不注入进去，系统不会让你去查询IAT的。DLL做的事情是确定要挂接哪个函数和这个函数在哪个DLL中等。</P><img src ="http://www.blogjava.net/huyi/aggbug/2621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-30 20:45 <a href="http://www.blogjava.net/huyi/archive/2005/03/30/2621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>跨进程API Hook（初稿）</title><link>http://www.blogjava.net/huyi/archive/2005/03/28/2519.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Mon, 28 Mar 2005 03:25:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/28/2519.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2519.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/28/2519.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2519.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2519.html</trackback:ping><description><![CDATA[<A href="http://www.zahui.com/html/1/3144.htm">http://www.zahui.com/html/1/3144.htm</A><BR>讲解非常详尽，有例子<img src ="http://www.blogjava.net/huyi/aggbug/2519.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-28 11:25 <a href="http://www.blogjava.net/huyi/archive/2005/03/28/2519.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>API Hooking Revealed </title><link>http://www.blogjava.net/huyi/archive/2005/03/28/2516.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Mon, 28 Mar 2005 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/28/2516.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2516.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/28/2516.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2516.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2516.html</trackback:ping><description><![CDATA[<P>来自CodeGuru的一篇文章<BR><A href="http://www.codeguru.com/Cpp/W-P/system/misc/article.php/c5667">http://www.codeguru.com/Cpp/W-P/system/misc/article.php/c5667</A></P><img src ="http://www.blogjava.net/huyi/aggbug/2516.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-28 11:07 <a href="http://www.blogjava.net/huyi/archive/2005/03/28/2516.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Processing Global Mouse and Keyboard Hooks in C#</title><link>http://www.blogjava.net/huyi/archive/2005/03/26/2473.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Sat, 26 Mar 2005 06:14:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/26/2473.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2473.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/26/2473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2473.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2473.html</trackback:ping><description><![CDATA[<A href="http://www.codeproject.com/csharp/globalhook.asp">http://www.codeproject.com/csharp/globalhook.asp</A><BR>这篇文章更绝，没有使用非托管代码就安装上了鼠标键盘钩子<img src ="http://www.blogjava.net/huyi/aggbug/2473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-26 14:14 <a href="http://www.blogjava.net/huyi/archive/2005/03/26/2473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Global System Hooks in .NET</title><link>http://www.blogjava.net/huyi/archive/2005/03/26/2472.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Sat, 26 Mar 2005 06:12:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/26/2472.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2472.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/26/2472.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2472.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2472.html</trackback:ping><description><![CDATA[<A href="http://www.codeproject.com/csharp/GlobalSystemHook.asp">http://www.codeproject.com/csharp/GlobalSystemHook.asp</A><BR>很有价值的一篇文章，有代码示例。<BR>讲述了如何通过非托管代码和托管代码的交互来按照钩子。<img src ="http://www.blogjava.net/huyi/aggbug/2472.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-26 14:12 <a href="http://www.blogjava.net/huyi/archive/2005/03/26/2472.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows编程的剪贴板机制</title><link>http://www.blogjava.net/huyi/archive/2005/03/26/2466.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Sat, 26 Mar 2005 05:23:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/26/2466.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2466.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/26/2466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2466.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2466.html</trackback:ping><description><![CDATA[<P><SPAN class=f14>　　<STRONG>摘要：</STRONG> 本文对Windows剪贴板机制作了深入、全面的阐述，具体内容包括：文本、位图、DSP、自定义格式剪贴板的使用和多数据项和延迟提交技术。</SPAN></P>
<P><SPAN class=f14>　　<STRONG>关键词：</STRONG> VC++6.0； 剪贴板机制；数据格式；延迟提交</SPAN></P>
<P><SPAN class=f14>　　<STRONG>Windows剪贴板</STRONG><BR><BR>　　Windows剪贴板是一种比较简单同时也是开销比较小的IPC（InterProcess Communication，进程间通讯）机制。Windows系统支持剪贴板IPC的基本机制是由系统预留的一块全局共享内存，用来暂存在各进程间进行交换的数据：提供数据的进程创建一个全局内存块，并将要传送的数据移到或复制到该内存块；接受数据的进程（也可以是提供数据的进程本身）获取此内存块的句柄，并完成对该内存块数据的读取。<BR><BR>　　为使剪贴板的这种IPC机制更加完善和便于使用，需要解决好如下三个问题：提供数据的进程在结束时Windows系统将删除其创建的全局内存块，而接受数据的进程则希望在其退出后剪贴板中的数据仍然存在，可以继续为其他进程所获取；能方便地管理和传送剪贴板数据句柄；能方便设置和确定剪贴板数据格式。为完善上述功能，Windows提供了存在于USER32.dll中的一组API函数、消息和预定义数据格式等，并通过对这些函数、消息的使用来管理在进程间进行的剪贴板数据交换。<BR><BR>　　Windows系统为剪贴板提供了一组API函数和多种消息，基本可以满足编程的需要。而且Windows还为剪贴板预定义了多种数据格式。通过这些预定义的格式，可以使接收方正确再现数据提供方放置于剪贴板中的数据内容。<BR><BR>　　<STRONG>文本剪贴板和位图剪贴板的使用</STRONG><BR><BR>　　这两种剪贴板是比较常用的。其中，文本剪贴板是包含具有格式CF_TEXT的字符串的剪贴板，是最经常使用的剪贴板之一。在文本剪贴板中传递的数据是不带任何格式信息的ASCII字符。若要将文本传送到剪贴板，可以先分配一个可移动全局内存块，然后将要复制的文本内容写入到此内存区域。最后调用剪贴板函数将数据放置到剪贴板：<BR><BR></P>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>DWORD dwLength = 100; // 要复制的字串长度<BR>HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存<BR>LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存<BR>for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块<BR>　*lpGlobalMemory++ = '*';<BR>　GlobalUnlock(hGlobalMemory); // 锁定内存块解锁<BR>　HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄<BR>　::OpenClipboard(hWnd); // 打开剪贴板<BR>　::EmptyClipboard(); // 清空剪贴板<BR>　::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板<BR>　::CloseClipboard(); // 关闭剪贴板</TD></TR></TBODY></TABLE>
<P><BR>　　这里以OpenClipboard（）打开剪贴板，并在调用了EmptyClipboard（）后使hWnd指向的窗口成为剪贴板的拥有者，一直持续到CloseClipboard（）函数的调用。在此期间，剪贴板为拥有者所独占，其他进程将无法对剪贴板内容进行修改。<BR><BR>　　从剪贴板获取文本的过程与之类似，首先打开剪贴板并获取剪贴板的数据句柄，如果数据存在就拷贝其数据到程序变量。由于GetClipboardData（）获取的数据句柄是属于剪贴板的，因此用户程序必须在调用CloseClipboard（）函数之前使用它：<BR><BR></P>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄<BR>::OpenClipboard(hWnd); // 打开剪贴板<BR>HANDLE hClipMemory = ::GetClipboardData(CF_TEXT);// 获取剪贴板数据句柄<BR>DWORD dwLength = GlobalSize(hClipMemory); // 返回指定内存区域的当前大小<BR>LPBYTE lpClipMemory = (LPBYTE)GlobalLock(hClipMemory); // 锁定内存<BR>m_sMessage = CString(lpClipMemory); // 保存得到的文本数据<BR>GlobalUnlock(hClipMemory); // 内存解锁<BR>::CloseClipboard(); // 关闭剪贴板</TD></TR></TBODY></TABLE>
<P><BR>　　大多数应用程序对图形数据采取的是位图的剪贴板数据格式。位图剪贴板的使用与文本剪贴板的使用是类似的，只是数据格式要指明为CF_BITMAP，而且在使用SetClipboardData（）或GetClipboardData（）函数时交给剪贴板或从剪贴板返回的是设备相关位图句柄。下面这段示例代码将把存在于剪贴板中的位图数据显示到程序的客户区：<BR><BR></P>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄<BR>::OpenClipboard(hWnd); // 打开剪贴板<BR>HANDLE hBitmap = ::GetClipboardData(CF_BITMAP); // 获取剪贴板数据句柄<BR>HDC hDC = ::GetDC(hWnd); // 获取设备环境句柄<BR>HDC hdcMem = CreateCompatibleDC(hDC); // 创建与设备相关的内存环境<BR>SelectObject(hdcMem, hBitmap); // 选择对象<BR>SetMapMode(hdcMem, GetMapMode(hDC)); // 设置映射模式<BR>BITMAP bm; // 得到位图对象<BR>GetObject(hBitmap, sizeof(BITMAP), &amp;bm);<BR>BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); //位图复制<BR>::ReleaseDC(hWnd, hDC); // 释放设备环境句柄<BR>DeleteDC(hdcMem); // 删除内存环境<BR>::CloseClipboard(); // 关闭剪贴板</TD></TR></TBODY></TABLE>
<P><BR></P><STRONG>多数据项和延迟提交技术</STRONG><BR><BR>　　要把数据放入剪贴板，在打开剪贴板后一定要调用EmptyClipboard（）函数清除当前剪贴板中的内容，而不可以在原有数据项基础上追加新的数据项。但是，可以在EmptyClipboard（）和CloseClipboard（）调用之间多次调用SetClipboardData（）函数来放置多个不同格式的数据项。例如：<BR><BR>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>OpenClipboard（hWnd）;<BR>EmptyClipboardData（）;<BR>SetClipboardData（CF_TEXT, hGMemText）;<BR>SetClipboardData（CF_BITMAP, hBitmap）;<BR>CloseClipboard（）;</TD></TR></TBODY></TABLE>
<P><BR>　　这时如果用CF_TEXT或CF_BITMAP等格式标记去调用IsClipboardFormatAvailable（）都将返回TRUE，表明这几种格式的数据同时存在于剪贴板中。以不同的格式标记去调用GetClipboardData（）函数可以得到相应的数据句柄。<BR><BR>　　对于多数据项的剪贴板数据，还可以用CountClipboardFormats（）和EnumClipboardFormats（）函数得到当前剪贴板中存在的数据格式数目和具体的数据格式。EnumClipboardFormats（）的函数原型为：<BR><BR></P>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>UINT EnumClipboardFormats(UINT format);</TD></TR></TBODY></TABLE>
<P><BR>　　参数format指定了剪贴板的数据格式。如果成功执行将返回format指定的格式的下一个数据格式值，如果format为最后的数据格式值，那么将返回0。由此不难写出处理剪贴板中所有格式数据项的程序段代码：<BR><BR></P>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>UINT format = 0; // 从第一种格式值开始枚举<BR>OpenClipboard（hWnd）;<BR>while（format = EnumClipboardFormats（format））<BR>{<BR>…… // 对相关格式数据的处理<BR>}<BR>CloseClipboard（）;</TD></TR></TBODY></TABLE>
<P><BR>　　在数据提供进程创建了剪贴板数据后，一直到有其他进程获取剪贴板数据前，这些数据都要占据内存空间。如在剪贴板放置的数据量过大，就会浪费内存空间，降低对资源的利用率。为避免这种浪费，可以采取延迟提交（Delayed rendering）技术，即由数据提供进程先创建一个指定数据格式的空（NULL）剪贴板数据块，直到有其他进程需要数据或自身进程要终止运行时才真正提交数据。<BR><BR>　　延迟提交的实现并不复杂，只需剪贴板拥有者进程在调用SetClipboardData（）将数据句柄参数设置为NULL即可。延迟提交的拥有者进程需要做的主要工作是对WM_RENDERFORMAT、WM_DESTORYCLIPBOARD和WM_RENDERALLFORMATS等剪贴板延迟提交消息的处理。<BR><BR>　　当另一个进程调用GetClipboardData（）函数时，系统将会向延迟提交数据的剪贴板拥有者进程发送WM_RENDERFORMAT消息。剪贴板拥有者进程在此消息的响应函数中应使用相应的格式和实际的数据句柄来调用SetClipboardData（）函数，但不必再调用OpenClipboard（）和EmptyClipboard（）去打开和清空剪贴板了。在设置完数据有也无须调用CloseClipboard（）关闭剪贴板。如果其他进程打开了剪贴板并且调用EmptyClipboard（）函数去清空剪贴板的内容，接管剪贴板的拥有权时，系统将向延迟提交的剪贴板拥有者进程发送WM_DESTROYCLIPBOARD消息，以通知该进程对剪贴板拥有权的丧失。而失去剪贴板拥有权的进程在收到该消息后则不会再向剪贴板提交数据。另外，在延迟提交进程在提交完所有要提交的数据后也会收到此消息。如果延迟提交剪贴板拥有者进程将要终止，系统将会为其发送一条WM_RENDERALLFORMATS消息，通知其打开并清除剪贴板内容。在调用SetClipboardData（）设置各数据句柄后关闭剪贴板。<BR><BR>　　下面这段代码将完成对数据的延迟提交，WM_RENDERFORMAT消息响应函数OnRenderFormat（）并不会立即执行，当有进程调用GetClipboardData（）函数从剪贴板读取数据时才会发出该消息。在消息处理函数中完成对数据的提交：<BR><BR>　　进行延迟提交：<BR><BR></P>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄<BR>::OpenClipboard(hWnd); // 打开剪贴板<BR>::EmptyClipboard(); // 清空剪贴板<BR>::SetClipboardData(CF_TEXT, NULL); // 进行剪贴板数据的延迟提交<BR>::CloseClipboard(); // 关闭剪贴板</TD></TR></TBODY></TABLE>
<P><BR>　　在WM_RENDERFORMAT消息的响应函数中：<BR><BR></P>
<P>　 
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>DWORD dwLength = 100; // 要复制的字串长度<BR>HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存块<BR>LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存块<BR>for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块<BR>*lpGlobalMemory++ = '*';<BR>GlobalUnlock(hGlobalMemory); // 锁定内存块解锁<BR>::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板</TD></TR></TBODY></TABLE><SPAN class=f14><STRONG>&nbsp;&nbsp;&nbsp; DSP和自定义数据格式的使用</STRONG><BR><BR>　　Windows系统预定义了三个带“DSP”前缀的数据格式：CF_DSPTEXT、CF_DSPBITMAP和CF_DSPMETAFILEPICT。这是一些伪标准格式，用于表示在程序中定义的私有剪贴板数据格式。对于不同的程序，这些格式的规定是不同的，因此这些格式只针对某一具体程序的不同实例才有意义。<BR><BR>　　为使用DSP数据格式，必须确保进程本身与剪贴板拥有者进程同属一个程序。可以调用GetClipboardOwner（）函数来获取剪贴板拥有者窗口句柄，并调用GetClassName（）来获取窗口类名：<BR><BR>
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>HWND hClipOwner = GetClipboardOwner（）;<BR>GetClassName（hClipOwner, &amp;ClassName, 255）;</TD></TR></TBODY></TABLE><BR>　　如果剪贴板拥有者窗口类名同本进程的窗口类名一致，就可以使用带有DSP前缀的剪贴板数据格式了。<BR>除了使用Windows预定义的剪贴板数据格式外，也可以在程序中使用自定义的数据格式。对于自定义的数据格式lpszFormat，可以调用RegisterClipboardFormat（）函数来登记，并获取其返回的格式标识值：<BR><BR>
<TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#e6e4dd border=1>
<TBODY>
<TR>
<TD>UINT format = RegisterClipboardFormat（lpszFormat）;</TD></TR></TBODY></TABLE><BR>　　对此返回的格式标识值的使用与系统预定义的格式标识是一样的。可以通过GetClipboardFormatName（）函数来获取自定义格式的ASCII名。<BR><BR>　　<STRONG>小结</STRONG><BR><BR>　　本文主要对Windows编程中的剪贴板机制作了较为深入的讨论，对其中常用的文本、位图、DSP和自定义数据格式的使用方法以及多数据项和延迟提交等重要技术一并做了阐述。并给出了具体的程序示例代码，使读者能够更好的掌握剪贴板机制的使用。</SPAN></P></SPAN><img src ="http://www.blogjava.net/huyi/aggbug/2466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-26 13:23 <a href="http://www.blogjava.net/huyi/archive/2005/03/26/2466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Window 消息大全使用详解 </title><link>http://www.blogjava.net/huyi/archive/2005/03/26/2465.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Sat, 26 Mar 2005 05:19:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/26/2465.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2465.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/26/2465.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2465.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2465.html</trackback:ping><description><![CDATA[<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，就是指<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=Windows"><FONT color=#000080>Windows</FONT></A>发出的一个通知，告诉应用程序某个事情发生了。例如，单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=Windows"><FONT color=#000080>Windows</FONT></A>发送一个<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给应用程序。<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>本身是作为一个记录传递给应用程序的，这个记录中包含了<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>的类型以及其他信息。例如，对于单击鼠标所产生的<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来说，这个记录中包含了单击鼠标时的坐标。这个记录类型叫做TMsg，<BR><BR>它在<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=Windows"><FONT color=#000080>Windows</FONT></A>单元中是这样声明的：<BR>type<BR>TMsg = packed record<BR>hwnd: HWND; / /窗口句柄<BR>message: UINT; / /<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>常量标识符<BR>wParam: WPARAM ; // 32位<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>的特定附加信息<BR>lParam: LPARAM ; // 32位<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>的特定附加信息<BR>time: DWORD; / /<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>创建时的时间<BR>pt: TPoint; / /<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>创建时的鼠标位置<BR>end;<BR><BR><A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>中有什么？<BR>是否觉得一个<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>记录中的信息像希腊语一样？如果是这样，那么看一看下面的解释：<BR>hwnd 32位的窗口句柄。窗口可以是任何类型的屏幕对象，因为Win32能够维护大多数可视对象的句柄(窗口、对话框、按钮、编辑框等)。<BR>message 用于区别其他<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>的常量值，这些常量可以是<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=Windows"><FONT color=#000080>Windows</FONT></A>单元中预定义的常量，也可以是自定义的常量。<BR>wParam 通常是一个与<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>有关的常量值，也可能是窗口或控件的句柄。<BR>lParam 通常是一个指向内存中数据的指针。由于W P a r a m、l P a r a m和P o i n t e r都是3 2位的，<BR>因此，它们之间可以相互转换。<BR><BR>WM_NULL = $0000;<BR>WM_CREATE = $0001;<BR>应用程序创建一个窗口<BR>WM_DESTROY = $0002;<BR>一个窗口被销毁<BR>WM_MOVE = $0003;<BR>移动一个窗口<BR>WM_SIZE = $0005;<BR>改变一个窗口的大小<BR>WM_ACTIVATE = $0006;<BR>一个窗口被激活或失去激活状态；<BR>WM_SETFOCUS = $0007;<BR>获得焦点后<BR>WM_KILLFOCUS = $0008;<BR>失去焦点<BR>WM_ENABLE = $000A;<BR>改变enable状态<BR>WM_SETREDRAW = $000B;<BR>设置窗口是否能重画 <BR>WM_SETTEXT = $000C;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来设置一个窗口的文本<BR>WM_GETTEXT = $000D;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来复制对应窗口的文本到缓冲区<BR>WM_GETTEXTLENGTH = $000E;<BR>得到与一个窗口有关的文本的长度（不包含空字符）<BR>WM_PAINT = $000F;<BR>要求一个窗口重画自己<BR>WM_CLOSE = $0010;<BR>当一个窗口或应用程序要关闭时发送一个信号<BR>WM_QUERYENDSESSION = $0011;<BR>当用户选择结束对话框或程序自己调用Exit<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=Windows"><FONT color=#000080>Windows</FONT></A>函数<BR>WM_QUIT = $0012;<BR>用来结束程序运行或当程序调用postquitmessage函数 <BR>WM_QUERYOPEN = $0013;<BR>当用户窗口恢复以前的大小位置时，把此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给某个图标<BR>WM_ERASEBKGND = $0014;<BR>当窗口背景必须被擦除时（例在窗口改变大小时）<BR>WM_SYSCOLORCHANGE = $0015;<BR>当系统颜色改变时，发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给所有顶级窗口<BR>WM_ENDSESSION = $0016;<BR>当系统进程发出WM_QUERYENDSESSION<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>后，此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给应用程序，<BR>通知它对话是否结束<BR>WM_SYSTEMERROR = $0017;<BR>WM_SHOWWINDOW = $0018;<BR>当隐藏或显示窗口是发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给这个窗口<BR>WM_ACTIVATEAPP = $001C;<BR>发此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给应用程序哪个窗口是激活的，哪个是非激活的；<BR>WM_FONTCHANGE = $001D;<BR>当系统的字体资源库变化时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给所有顶级窗口<BR>WM_TIMECHANGE = $001E;<BR>当系统的时间变化时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给所有顶级窗口<BR>WM_CANCELMODE = $001F;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来取消某种正在进行的摸态（操作）<BR>WM_SETCURSOR = $0020;<BR>如果鼠标引起光标在某个窗口中移动且鼠标输入没有被捕获时，就发<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给某个窗口<BR>WM_MOUSEACTIVATE = $0021;<BR>当光标在某个非激活的窗口中而用户正按着鼠标的某个键发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给当前窗口<BR>WM_CHILDACTIVATE = $0022;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI子窗口当用户点击此窗口的标题栏，或当窗口被激活，移动，改变大小<BR>WM_QUEUESYNC = $0023;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>由基于计算机的训练程序发送，通过WH_JOURNALPALYBACK的hook程序<BR>分离出用户输入<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_GETMINMAXINFO = $0024;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给窗口当它将要改变大小或位置；<BR>WM_PAINTICON = $0026;<BR>发送给最小化窗口当它图标将要被重画<BR>WM_ICONERASEBKGND = $0027;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给某个最小化窗口，仅当它在画图标前它的背景必须被重画<BR>WM_NEXTDLGCTL = $0028;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给一个对话框程序去更改焦点位置<BR>WM_SPOOLERSTATUS = $002A;<BR>每当打印管理列队增加或减少一条作业时发出此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A> <BR>WM_DRAWITEM = $002B;<BR>当button，combobox，listbox，menu的可视外观改变时发送<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给这些空件的所有者<BR>WM_MEASUREITEM = $002C;<BR>当button, combo box, list box, list view control, or menu item 被创建时<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给控件的所有者<BR>WM_DELETEITEM = $002D;<BR>当the list box 或 combo box 被销毁 或 当 某些项被删除通过LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT <A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_VKEYTOITEM = $002E;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>有一个LBS_WANTKEYBOARDINPUT风格的发出给它的所有者来响应WM_KEYDOWN<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A> <BR>WM_CHARTOITEM = $002F;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>由一个LBS_WANTKEYBOARDINPUT风格的列表框发送给他的所有者来响应WM_CHAR<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A> <BR>WM_SETFONT = $0030;<BR>当绘制文本时程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>得到控件要用的颜色 <BR>WM_GETFONT = $0031;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>得到当前控件绘制文本的字体<BR>WM_SETHOTKEY = $0032;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>让一个窗口与一个热键相关连<BR>WM_GETHOTKEY = $0033;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来判断热键与某个窗口是否有关联<BR>WM_QUERYDRAGICON = $0037;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给最小化窗口，当此窗口将要被拖放而它的类中没有定义图标，应用程序能返回一个图标或光标的句柄，当用户拖放图标时系统显示这个图标或光标<BR>WM_COMPAREITEM = $0039;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来判定combobox或listbox新增加的项的相对位置<BR>WM_GETOBJECT = $003D;<BR>WM_COMPACTING = $0041;<BR>显示内存已经很少了<BR>WM_WINDOWPOSCHANGING = $0046;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给那个窗口的大小和位置将要被改变时，来调用setwindowpos函数或其它窗口管理函数<BR>WM_WINDOWPOSCHANGED = $0047;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给那个窗口的大小和位置已经被改变时，来调用setwindowpos函数或其它窗口管理函数<BR>WM_POWER = $0048;（适用于16位的windows）<BR>当系统将要进入暂停状态时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_COPYDATA = $004A;<BR>当一个应用程序传递数据给另一个应用程序时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_CANCELJOURNAL = $004B;<BR>当某个用户取消程序日志激活状态，提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给程序<BR>WM_NOTIFY = $004E;<BR>当某个控件的某个事件已经发生或这个控件需要得到一些信息时，发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口<BR>WM_INPUTLANGCHANGEREQUEST = $0050;<BR>当用户选择某种输入语言，或输入语言的热键改变<BR>WM_INPUTLANGCHANGE = $0051;<BR>当平台现场已经被改变后发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给受影响的最顶级窗口<BR>WM_TCARD = $0052;<BR>当程序已经初始化windows帮助例程时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给应用程序<BR>WM_HELP = $0053;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>显示用户按下了F1，如果某个菜单是激活的，就发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>个此窗口关联的菜单，否则就<BR>发送给有焦点的窗口，如果当前都没有焦点，就把此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给当前激活的窗口<BR>WM_USERCHANGED = $0054;<BR>当用户已经登入或退出后发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给所有的窗口，当用户登入或退出时系统更新用户的具体<BR>设置信息，在用户更新设置时系统马上发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>；<BR>WM_NOTIFYFORMAT = $0055;<BR>公用控件，自定义控件和他们的父窗口通过此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来判断控件是使用ANSI还是UNICODE结构<BR>在WM_NOTIFY<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，使用此控件能使某个控件与它的父控件之间进行相互通信<BR>WM_CONTEXTMENU = $007B;<BR>当用户某个窗口中点击了一下右键就发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给这个窗口<BR>WM_STYLECHANGING = $007C;<BR>当调用SETWINDOWLONG函数将要改变一个或多个 窗口的风格时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给那个窗口<BR>WM_STYLECHANGED = $007D;<BR>当调用SETWINDOWLONG函数一个或多个 窗口的风格后发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给那个窗口<BR>WM_DISPLAYCHANGE = $007E;<BR>当显示器的分辨率改变后发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给所有的窗口<BR>WM_GETICON = $007F;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给某个窗口来返回与某个窗口有关连的大图标或小图标的句柄；<BR>WM_SETICON = $0080;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>让一个新的大图标或小图标与某个窗口关联；<BR>WM_NCCREATE = $0081;<BR>当某个窗口第一次被创建时，此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>在WM_CREATE<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送前发送；<BR>WM_NCDESTROY = $0082;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通知某个窗口，非客户区正在销毁<BR>WM_NCCALCSIZE = $0083;<BR>当某个窗口的客户区域必须被核算时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCHITTEST = $0084;//移动鼠标，按住或释放鼠标时发生<BR>WM_NCPAINT = $0085;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给某个窗口当它（窗口）的框架必须被绘制时；<BR>WM_NCACTIVATE = $0086;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给某个窗口 仅当它的非客户区需要被改变来显示是激活还是非激活状态；<BR>WM_GETDLGCODE = $0087;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给某个与对话框程序关联的控件，widdows控制方位键和TAB键使输入进入此控件<BR>通过响应WM_GETDLGCODE<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，应用程序可以把他当成一个特殊的输入控件并能处理它<BR>WM_NCMOUSEMOVE = $00A0;<BR>当光标在一个窗口的非客户区内移动时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给这个窗口 //非客户区为：窗体的标题栏及窗 <BR>的边框体<BR>WM_NCLBUTTONDOWN = $00A1;<BR>当光标在一个窗口的非客户区同时按下鼠标左键时提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCLBUTTONUP = $00A2;<BR>当用户释放鼠标左键同时光标某个窗口在非客户区十发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>；<BR>WM_NCLBUTTONDBLCLK = $00A3;<BR>当用户双击鼠标左键同时光标某个窗口在非客户区十发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCRBUTTONDOWN = $00A4;<BR>当用户按下鼠标右键同时光标又在窗口的非客户区时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCRBUTTONUP = $00A5;<BR>当用户释放鼠标右键同时光标又在窗口的非客户区时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCRBUTTONDBLCLK = $00A6;<BR>当用户双击鼠标右键同时光标某个窗口在非客户区十发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCMBUTTONDOWN = $00A7;<BR>当用户按下鼠标中键同时光标又在窗口的非客户区时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCMBUTTONUP = $00A8;<BR>当用户释放鼠标中键同时光标又在窗口的非客户区时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_NCMBUTTONDBLCLK = $00A9;<BR>当用户双击鼠标中键同时光标又在窗口的非客户区时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_KEYFIRST = $0100;<BR>WM_KEYDOWN = $0100; <BR>//按下一个键<BR>WM_KEYUP = $0101; <BR>//释放一个键<BR>WM_CHAR = $0102; <BR>//按下某键，并已发出WM_KEYDOWN， WM_KEYUP<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_DEADCHAR = $0103;<BR>当用translatemessage函数翻译WM_KEYUP<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给拥有焦点的窗口<BR>WM_SYSKEYDOWN = $0104;<BR>当用户按住ALT键同时按下其它键时提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给拥有焦点的窗口；<BR>WM_SYSKEYUP = $0105;<BR>当用户释放一个键同时ALT 键还按着时提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给拥有焦点的窗口<BR>WM_SYSCHAR = $0106;<BR>当WM_SYSKEYDOWN<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>被TRANSLATEMESSAGE函数翻译后提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给拥有焦点的窗口<BR>WM_SYSDEADCHAR = $0107;<BR>当WM_SYSKEYDOWN<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>被TRANSLATEMESSAGE函数翻译后发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给拥有焦点的窗口<BR>WM_KEYLAST = $0108;<BR>WM_INITDIALOG = $0110;<BR>在一个对话框程序被显示前发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它，通常用此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>初始化控件和执行其它任务<BR>WM_COMMAND = $0111;<BR>当用户选择一条菜单命令项或当某个控件发送一条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口，一个快捷键被翻译<BR>WM_SYSCOMMAND = $0112;<BR>当用户选择窗口菜单的一条命令或当用户选择最大化或最小化时那个窗口会收到此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_TIMER = $0113; //发生了定时器事件<BR>WM_HSCROLL = $0114;<BR>当一个窗口标准水平滚动条产生一个滚动事件时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给那个窗口，也发送给拥有它的控件<BR>WM_VSCROLL = $0115;<BR>当一个窗口标准垂直滚动条产生一个滚动事件时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给那个窗口也，发送给拥有它的控件 WM_INITMENU = $0116;<BR>当一个菜单将要被激活时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，它发生在用户菜单条中的某项或按下某个菜单键，它允许程序在显示前更改菜单<BR>WM_INITMENUPOPUP = $0117;<BR>当一个下拉菜单或子菜单将要被激活时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，它允许程序在它显示前更改菜单，而不要改变全部 <BR>WM_MENUSELECT = $011F;<BR>当用户选择一条菜单项时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给菜单的所有者（一般是窗口）<BR>WM_MENUCHAR = $0120;<BR>当菜单已被激活用户按下了某个键（不同于加速键），发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给菜单的所有者；<BR>WM_ENTERIDLE = $0121;<BR>当一个模态对话框或菜单进入空载状态时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的所有者，一个模态对话框或菜单进入空载状态就是在处理完一条或几条先前的<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>后没有<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>它的列队中等待<BR>WM_MENURBUTTONUP = $0122;<BR>WM_MENUDRAG = $0123;<BR>WM_MENUGETOBJECT = $0124;<BR>WM_UNINITMENUPOPUP = $0125;<BR>WM_MENUCOMMAND = $0126;<BR>WM_CHANGEUISTATE = $0127;<BR>WM_UPDATEUISTATE = $0128;<BR>WM_QUERYUISTATE = $0129; <BR>WM_CTLCOLORMSGBOX = $0132;<BR>在windows绘制<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>框前发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>框的所有者窗口，通过响应这条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，所有者窗口可以通过使用给定的相关显示设备的句柄来设置<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>框的文本和背景颜色<BR>WM_CTLCOLOREDIT = $0133;<BR>当一个编辑型控件将要被绘制时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口；通过响应这条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，所有者窗口可以通过使用给定的相关显示设备的句柄来设置编辑框的文本和背景颜色<BR>WM_CTLCOLORLISTBOX = $0134;<BR>当一个列表框控件将要被绘制前发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口；通过响应这条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，所有者窗口可以通过使用给定的相关显示设备的句柄来设置列表框的文本和背景颜色 <BR>WM_CTLCOLORBTN = $0135;<BR>当一个按钮控件将要被绘制时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口；通过响应这条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，所有者窗口可以通过使用给定的相关显示设备的句柄来设置按纽的文本和背景颜色<BR>WM_CTLCOLORDLG = $0136;<BR>当一个对话框控件将要被绘制前发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口；通过响应这条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，所有者窗口可以通过使用给定的相关显示设备的句柄来设置对话框的文本背景颜色<BR>WM_CTLCOLORSCROLLBAR= $0137;<BR>当一个滚动条控件将要被绘制时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口；通过响应这条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，所有者窗口可以通过使用给定的相关显示设备的句柄来设置滚动条的背景颜色<BR>WM_CTLCOLORSTATIC = $0138; <BR>当一个静态控件将要被绘制时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口；通过响应这条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，所有者窗口可以通过使用给定的相关显示设备的句柄来设置静态控件的文本和背景颜色<BR>WM_MOUSEFIRST = $0200;<BR>WM_MOUSEMOVE = $0200; <BR>// 移动鼠标<BR>WM_LBUTTONDOWN = $0201; <BR>//按下鼠标左键<BR>WM_LBUTTONUP = $0202; <BR>//释放鼠标左键<BR>WM_LBUTTONDBLCLK = $0203;<BR>//双击鼠标左键<BR>WM_RBUTTONDOWN = $0204;<BR>//按下鼠标右键<BR>WM_RBUTTONUP = $0205;<BR>//释放鼠标右键<BR>WM_RBUTTONDBLCLK = $0206; <BR>//双击鼠标右键<BR>WM_MBUTTONDOWN = $0207; <BR>//按下鼠标中键 <BR>WM_MBUTTONUP = $0208; <BR>//释放鼠标中键<BR>WM_MBUTTONDBLCLK = $0209; <BR>//双击鼠标中键<BR>WM_MOUSEWHEEL = $020A;<BR>当鼠标轮子转动时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>个当前有焦点的控件<BR>WM_MOUSELAST = $020A;<BR>WM_PARENTNOTIFY = $0210;<BR>当MDI子窗口被创建或被销毁，或用户按了一下鼠标键而光标在子窗口上时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给它的父窗口<BR>WM_ENTERMENULOOP = $0211;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通知应用程序的主窗口that已经进入了菜单循环模式<BR>WM_EXITMENULOOP = $0212;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通知应用程序的主窗口that已退出了菜单循环模式<BR>WM_NEXTMENU = $0213;<BR>WM_SIZING = 532;<BR>当用户正在调整窗口大小时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给窗口；通过此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>应用程序可以监视窗口大小和位置也可以修改他们<BR>WM_CAPTURECHANGED = 533;<BR>发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A> 给窗口当它失去捕获的鼠标时；<BR>WM_MOVING = 534;<BR>当用户在移动窗口时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，通过此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>应用程序可以监视窗口大小和位置也可以修改他们；<BR>WM_POWERBROADCAST = 536;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给应用程序来通知它有关电源管理事件；<BR>WM_DEVICECHANGE = 537;<BR>当设备的硬件配置改变时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给应用程序或设备驱动程序<BR>WM_IME_STARTCOMPOSITION = $010D;<BR>WM_IME_ENDCOMPOSITION = $010E;<BR>WM_IME_COMPOSITION = $010F;<BR>WM_IME_KEYLAST = $010F;<BR>WM_IME_SETCONTEXT = $0281;<BR>WM_IME_NOTIFY = $0282;<BR>WM_IME_CONTROL = $0283;<BR>WM_IME_COMPOSITIONFULL = $0284;<BR>WM_IME_SELECT = $0285;<BR>WM_IME_CHAR = $0286;<BR>WM_IME_REQUEST = $0288;<BR>WM_IME_KEYDOWN = $0290;<BR>WM_IME_KEYUP = $0291;<BR>WM_MDICREATE = $0220;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给多文档的客户窗口来创建一个MDI 子窗口<BR>WM_MDIDESTROY = $0221;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给多文档的客户窗口来关闭一个MDI 子窗口<BR>WM_MDIACTIVATE = $0222;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给多文档的客户窗口通知客户窗口激活另一个MDI子窗口，当客户窗口收到此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>后，它发出WM_MDIACTIVE<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI子窗口（未激活）激活它；<BR>WM_MDIRESTORE = $0223;<BR>程序 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口让子窗口从最大最小化恢复到原来大小<BR>WM_MDINEXT = $0224;<BR>程序 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口激活下一个或前一个窗口<BR>WM_MDIMAXIMIZE = $0225;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口来最大化一个MDI子窗口；<BR>WM_MDITILE = $0226;<BR>程序 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口以平铺方式重新排列所有MDI子窗口<BR>WM_MDICASCADE = $0227;<BR>程序 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口以层叠方式重新排列所有MDI子窗口<BR>WM_MDIICONARRANGE = $0228;<BR>程序 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口重新排列所有最小化的MDI子窗口<BR>WM_MDIGETACTIVE = $0229;<BR>程序 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口来找到激活的子窗口的句柄<BR>WM_MDISETMENU = $0230;<BR>程序 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给MDI客户窗口用MDI菜单代替子窗口的菜单<BR>WM_ENTERSIZEMOVE = $0231;<BR>WM_EXITSIZEMOVE = $0232;<BR>WM_DROPFILES = $0233;<BR>WM_MDIREFRESHMENU = $0234;<BR>WM_MOUSEHOVER = $02A1;<BR>WM_MOUSELEAVE = $02A3;<BR>WM_CUT = $0300;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给一个编辑框或combobox来删除当前选择的文本<BR>WM_COPY = $0301;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给一个编辑框或combobox来复制当前选择的文本到剪贴板<BR>WM_PASTE = $0302;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给editcontrol或combobox从剪贴板中得到数据<BR>WM_CLEAR = $0303;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给editcontrol或combobox清除当前选择的内容；<BR>WM_UNDO = $0304;<BR>程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给editcontrol或combobox撤消最后一次操作<BR>WM_RENDERFORMAT = $0305；<BR><BR>WM_RENDERALLFORMATS = $0306;<BR>WM_DESTROYCLIPBOARD = $0307;<BR>当调用ENPTYCLIPBOARD函数时 发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给剪贴板的所有者<BR>WM_DRAWCLIPBOARD = $0308;<BR>当剪贴板的内容变化时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给剪贴板观察链的第一个窗口；它允许用剪贴板观察窗口来<BR>显示剪贴板的新内容；<BR>WM_PAINTCLIPBOARD = $0309;<BR>当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区需要重画；<BR>WM_VSCROLLCLIPBOARD = $030A;<BR>WM_SIZECLIPBOARD = $030B;<BR>当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区域的大小已经改变是此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通过剪贴板观察窗口发送给剪贴板的所有者；<BR>WM_ASKCBFORMATNAME = $030C;<BR>通过剪贴板观察窗口发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给剪贴板的所有者来请求一个CF_OWNERDISPLAY格式的剪贴板的名字<BR>WM_CHANGECBCHAIN = $030D;<BR>当一个窗口从剪贴板观察链中移去时发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给剪贴板观察链的第一个窗口；<BR>WM_HSCROLLCLIPBOARD = $030E; <BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通过一个剪贴板观察窗口发送给剪贴板的所有者 ；它发生在当剪贴板包含CFOWNERDISPALY格式的数据并且有个事件在剪贴板观察窗的水平滚动条上；所有者应滚动剪贴板图象并更新滚动条的值；<BR>WM_QUERYNEWPALETTE = $030F;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>发送给将要收到焦点的窗口，此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>能使窗口在收到焦点时同时有机会实现他的逻辑调色板<BR>WM_PALETTEISCHANGING= $0310;<BR>当一个应用程序正要实现它的逻辑调色板时发此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通知所有的应用程序<BR>WM_PALETTECHANGED = $0311;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>在一个拥有焦点的窗口实现它的逻辑调色板后发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给所有顶级并重叠的窗口，以此来改变系统调色板 <BR>WM_HOTKEY = $0312;<BR>当用户按下由REGISTERHOTKEY函数注册的热键时提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_PRINT = 791;<BR>应用程序发送此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>仅当WINDOWS或其它应用程序发出一个请求要求绘制一个应用程序的一部分；<BR>WM_PRINTCLIENT = 792;<BR>WM_HANDHELDFIRST = 856;<BR>WM_HANDHELDLAST = 863;<BR>WM_PENWINFIRST = $0380;<BR>WM_PENWINLAST = $038F;<BR>WM_COALESCE_FIRST = $0390;<BR>WM_COALESCE_LAST = $039F;<BR>WM_DDE_FIRST = $03E0;<BR>WM_DDE_INITIATE = WM_DDE_FIRST + 0;<BR>一个DDE客户程序提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>开始一个与服务器程序的会话来响应那个指定的程序和主题名；<BR>WM_DDE_TERMINATE = WM_DDE_FIRST + 1;<BR>一个DDE应用程序（无论是客户还是服务器）提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来终止一个会话；<BR>WM_DDE_ADVISE = WM_DDE_FIRST + 2;<BR>一个DDE客户程序提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给一个DDE服务程序来请求服务器每当数据项改变时更新它<BR>WM_DDE_UNADVISE = WM_DDE_FIRST + 3;<BR>一个DDE客户程序通过此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通知一个DDE服务程序不更新指定的项或一个特殊的剪贴板格式的项<BR>WM_DDE_ACK = WM_DDE_FIRST + 4;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>通知一个DDE（动态数据交换）程序已收到并正在处理WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_DATA, WM_DDE_ADVISE, WM_DDE_UNADVISE, or WM_DDE_INITIAT<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A><BR>WM_DDE_DATA = WM_DDE_FIRST + 5;<BR>一个DDE服务程序提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给DDE客户程序来传递个一数据项给客户或通知客户的一条可用数据项<BR>WM_DDE_REQUEST = WM_DDE_FIRST + 6;<BR>一个DDE客户程序提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给一个DDE服务程序来请求一个数据项的值；<BR>WM_DDE_POKE = WM_DDE_FIRST + 7;<BR>一个DDE客户程序提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给一个DDE服务程序，客户使用此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来请求服务器接收一个未经同意的数据项；服务器通过答复WM_DDE_ACK<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>提示是否它接收这个数据项；<BR>WM_DDE_EXECUTE = WM_DDE_FIRST + 8;<BR>一个DDE客户程序提交此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>给一个DDE服务程序来发送一个字符串给服务器让它象串行命令一样被处理，服务器通过提交WM_DDE_ACK<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>来作回应；<BR>WM_DDE_LAST = WM_DDE_FIRST + 8;<BR>WM_APP = $8000;<BR>WM_USER = $0400;<BR>此<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>能帮助应用程序自定义私有<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>；<BR>/////////////////////////////////////////////////////////////////////<BR>通知<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>(Notification message)是指这样一种<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>，一个窗口内的子控件发生了一些事情，需要通知父窗口。通知<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>只适用于标准的窗口控件如按钮、列表框、组合框、编辑框，以及<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=Windows"><FONT color=#000080>Windows</FONT></A> 95公共控件如树状视图、列表视图等。例如，单击或双击一个控件、在控件中选择部分文本、操作控件的滚动条都会产生通知<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>。 <BR>按扭<BR>B N _ C L I C K E D //用户单击了按钮<BR>B N _ D I S A B L E //按钮被禁止<BR>B N _ D O U B L E C L I C K E D //用户双击了按钮<BR>B N _ H I L I T E //用户加亮了按钮<BR>B N _ PA I N T按钮应当重画<BR>B N _ U N H I L I T E加亮应当去掉<BR>组合框<BR>C B N _ C L O S E U P组合框的列表框被关闭<BR>C B N _ D B L C L K用户双击了一个字符串<BR>C B N _ D R O P D O W N组合框的列表框被拉出<BR>C B N _ E D I T C H A N G E用户修改了编辑框中的文本<BR>C B N _ E D I T U P D AT E编辑框内的文本即将更新<BR>C B N _ E R R S PA C E组合框内存不足<BR>C B N _ K I L L F O C U S组合框失去输入焦点<BR>C B N _ S E L C H A N G E在组合框中选择了一项<BR>C B N _ S E L E N D C A N C E L用户的选择应当被取消<BR>C B N _ S E L E N D O K用户的选择是合法的<BR>C B N _ S E T F O C U S组合框获得输入焦点<BR>编辑框<BR>E N _ C H A N G E编辑框中的文本己更新<BR>E N _ E R R S PA C E编辑框内存不足<BR>E N _ H S C R O L L用户点击了水平滚动条<BR>E N _ K I L L F O C U S编辑框正在失去输入焦点<BR>E N _ M A X T E X T插入的内容被截断<BR>E N _ S E T F O C U S编辑框获得输入焦点<BR>E N _ U P D AT E编辑框中的文本将要更新<BR>E N _ V S C R O L L用户点击了垂直滚动条<A id=highlight href="http://www.kehui.net/index.php?op=article&amp;action=keyword&amp;keyword=%CF%FB%CF%A2"><FONT color=#000080>消息</FONT></A>含义<BR>列表框<BR>L B N _ D B L C L K用户双击了一项<BR>L B N _ E R R S PA C E列表框内存不够<BR>L B N _ K I L L F O C U S列表框正在失去输入焦点<BR>L B N _ S E L C A N C E L选择被取消<BR>L B N _ S E L C H A N G E选择了另一项<BR>L B N _ S E T F O C U S列表框获得输入焦点<B><BR></B><img src ="http://www.blogjava.net/huyi/aggbug/2465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-26 13:19 <a href="http://www.blogjava.net/huyi/archive/2005/03/26/2465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WINDOWS键盘事件的挂钩监控原理及其应用技术</title><link>http://www.blogjava.net/huyi/archive/2005/03/26/2464.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Sat, 26 Mar 2005 04:59:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/26/2464.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2464.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/26/2464.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2464.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2464.html</trackback:ping><description><![CDATA[<P class=fontsize10 style="FONT-SIZE: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;WINDOWS的消息处理机制为了能在应用程序中监控系统的各种事件消息，提供了挂接 各种反调函数(HOOK)的功能。这种挂钩函数(HOOK)类似扩充中断驱动程序，挂钩上 可以挂接多个反调函数构成一个挂接函数链。系统产生的各种消息首先被送到各种 挂接函数，挂接函数根据各自的功能对消息进行监视、修改和控制等，然后交还控 制权或将消息传递给下一个挂接函数以致最终达到窗口函数。WINDOW系统的这种反 调函数挂接方法虽然会略加影响到系统的运行效率，但在很多场合下是非常有用 的，通过合理有效地利用键盘事件的挂钩函数监控机制可以达到预想不到的良好效 果。 <BR>一、在WINDOWS键盘事件上挂接监控函数的方法 <BR>WINDOW下可进行挂接的过滤函数包括11种： <BR>WH_CALLWNDPROC 窗口函数的过滤函数 <BR>WH_CBT 计算机培训过滤函数 <BR>WH_DEBUG 调试过滤函数 <BR>WH_GETMESSAGE 获取消息过滤函数 <BR>WH_HARDWARE 硬件消息过滤函数 <BR>WH_JOURNALPLAYBACK 消息重放过滤函数 <BR>WH_JOURNALRECORD 消息记录过滤函数 <BR>WH_MOUSE 鼠标过滤函数 <BR>WH_MSGFILTER 消息过滤函数 <BR>WH_SYSMSGFILTER 系统消息过滤函数 <BR>WH_KEYBOARD 键盘过滤函数<BR>其中键盘过滤函数是最常用最有用的过滤函数类型，不管是哪一种类型的过滤函 数，其挂接的基本方法都是相同的。 WINDOW调用挂接的反调函数时总是先调用挂接链首的那个函数，因此必须将键盘挂 钩函数利用函数SetWindowsHookEx()将其挂接在函数链首。至于消息是否传递给函 数链的下一个函数是由每个具体函数功能确定的，如果消息需要传统给下一个函 数，可调用API函数的CallNextHookEx()来实现，如果不传递直接返回即可。 挂接函数可以是用来监控所有线程消息的全局性函数，也可以是单独监控某一线程 的局部性函数。如果挂接函数是局部函数，可以将它放到一个.DLL动态链接库中， 也可以放在一个局部模块中；如果挂接函数是全局的，那么必须将其放在一个.DLL 动态链接库中。挂接函数必须严格按照下述格式进行声明，以键盘挂钩函数为例： <BR>int FAR PASCAL KeyboardProc( int nCode,WORD wParam,DWORD lParam) 其中KeyboardProc为定义挂接函数名，该函数必须在模块定义文件中利用EXPORTS命 令进行说明；nCode决定挂接函数是否对当前消息进行处理；wParam和lParam为具体 的消息内容。<BR><BR>二、键盘事件挂接函数的安装与下载 在程序中可以利用函数SetWindowsHookEx()来挂接过滤函数，在挂接函数时必须指 出该挂接函数的类型、函数的入口地址以及函数是全局性的还是局部性的，挂接函 数的具体调用格式如下： <BR>SetWindowsHookEx(iType,iProc,hInst,iCode) 其中iType为挂接函数类型，键盘类型为WH_KEYBOARD,iProc为挂接函数地址，hInst 为挂接函数链接库实例句柄，iCode为监控代码－0表示全局性函数。 如果挂接函数需要将消息传递给下一个过滤函数，则在该挂接函数返回前还需要调 用一次CallNextHookEx()函数，当需要下载挂接函数时，只要调用一次 UnhookWindowsHookEx(iProc)函数即可实现。 如果函数是全局性的，那么它必须放在一个.DLL动态链接库中，这时该函数调用方 法可以和其它普通.DLL函数一样有三种： <BR>1.在DEF定义文件中直接用函数名或序号说明： EXPORTS WEP @1 RESIDENTNAME InitHooksDll @2 InstallFilter @3 KeyboardProc @4 用序号说明格式为：链接库名.函数名(如本例中说明方法为KEYDLL.KeyboardProc)。 <BR>2.在应用程序中利用函数直接调用： 首先在应用程序中利用LoadLibrary(LPSTR "链接库名")将动态链接库装入，并取得 装载库模块句柄hInst,然后直接利用GetProcAddress(HINSTANCE hInst,LPSTR "函 数过程名")获取函数地址，然后直接调用该地址即可，程序结束前利用函数 FreeLibrary( )释放装入的动态链接库即可。 <BR>3.利用输入库.LIB方法 利用IMPLIB.EXE程序在建立动态链接库的同时建立相应的输入库.LIB，然后直接在 项目文件中增加该输入库。<BR><BR>三、WINDOWS挂钩监控函数的实现步骤 WINDOWS挂钩函数只有放在动态链接库DLL中才能实现所有事件的监控功能。在.DLL 中形成挂钩监控函数基本方法及其基本结构如下： <BR><BR>１、首先声明DLL中的变量和过程；<BR><BR>２、然后编制DLL主模块LibMain()，建立模块实例；<BR><BR>３、建立系统退出DLL机制WEP()函数；<BR><BR>４、完成DLL初始化函数InitHooksDll(),传递主窗口程序句柄； <BR><BR>５、编制挂钩安装和下载函数InstallFilter()； <BR><BR>６、编制挂钩函数KeyboardProc()，在其中设置监控功能，并确定继续调下一个钩 子函数还是直接返回WINDOWS应用程序。<BR><BR>７、在WINDOWS主程序中需要初始化DLL并安装相应挂钩函数，由挂接的钩子函数负 责与主程序通信；<BR><BR>８、在不需要监控时由下载功能卸掉挂接函数。<BR><BR>四、WINDOWS下键盘挂钩监控函数的应用技术 目前标准的104 键盘上都有两个特殊的按键，其上分别用WINDOW程序徽标和鼠标下 拉列表标识，本文暂且分别称为Micro左键和Micro右键，前者用来模拟鼠标左键激 活开始菜单，后者用来模拟鼠标右键激活属性菜单。这两个特殊按键只有在按下后 立即抬起即完成 CLICK过程才能实现其功能，并且没有和其它按键进行组合使用。 由于WINDOWS 系统中将按键划分得更加详细，使应用程序中很难灵活定义自己的专 用快捷键，比如在开发.IME等应用程序时很难找到不与WORD8.0等其它应用程序冲突 的功能按键。如果将标准104键盘中的这两个特殊按键作为模拟CTRL和ALT 等专用按 键，使其和其它按键组合，就可以在自己的应用程序中自由地设置专用功能键，为 应用程序实现各种功能快捷键提供灵活性。正常情况下WINDOWS 键盘事件驱动程序 并不将这两个按键的消息进行正常解释，这就必须利用键盘事件的挂钩监控函数来 实现其特定的功能。其方法如下：<BR><BR>１、首先编制如下一个简单动态链接库程序，并编译成DLL文件。 #include "windows.h" <BR>int FAR PASCAL LibMain(HANDLE hModule,UINT wDataSeg, UINT cbHeapSize,LPSTR lpszCmdLine); <BR>int WINAPI WEP(int bSystemExit); <BR>int WINAPI InitHooksDll(HWND hwndMainWindow); <BR>int WINAPI InstallFilter(BOOL nCode); <BR>LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam); <BR>static HANDLE hInstance; // 全局句柄 <BR>static HWND hWndMain; // 主窗口句柄 <BR>static int InitCalled=0; // 初始化标志 <BR>static HHOOK hKeyHook; <BR>FARPROC lpfnKeyHook=(FARPROC)KeyHook; <BR>BOOL HookStates=FALSE; <BR>int FAR PASCAL LibMain( HANDLE hModule, UINT wDataSeg, UINT cbHeapSize, LPSTR lpszCmdLine) <BR>{<BR>if (cbHeapSize!=0) <BR>UnlockData(0); <BR>hInstance = hModule; <BR>return 1; <BR>} <BR>int WINAPI WEP (int bSystemExit) <BR>{ return 1;} <BR>int WINAPI InitHooksDll(HWND hwndMainWindow) <BR>{ <BR>hWndMain = hwndMainWindow; <BR>InitCalled = 1; <BR>return (0); <BR>} <BR><BR>int WINAPI InstallFilter(BOOL nCode) <BR>{ if (InitCalled==0) <BR>return (-1); <BR>if (nCode==TRUE) <BR>{ <BR>hKeyHook=SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)lpfnKeyHook,hInstance,0); <BR>HookStates=TRUE; <BR>} <BR>else <BR>{ <BR>UnhookWindowsHookEx(hKeyHook); <BR>HookStates=FALSE; <BR>} <BR>return(0); <BR>} <BR><BR>LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam) <BR>{ <BR>static BOOL msflag=FALSE; <BR>if(nCode&gt;=0) <BR>{ <BR>if(HookStates==TRUE)<BR>{ <BR>if((wParam==0xff)|| //WIN3.X下按键值 <BR>(wParam==0x5b)||(wParam==0x5c)){//WIN95下按键值 <BR>if((i==0x15b)||(i==0x15c)){ //按键按下处理 <BR>msflag=TRUE; <BR>PostMessage(hWndMain,0x7fff,0x1,0x3L); <BR>} <BR>else if((i==0xc15b)||(i==0xc15c)){//按键抬起处理 msflag=FALSE; <BR>PostMessage(hWndMain,0x7fff,0x2,0x3L); <BR>} <BR>} <BR>} <BR>} <BR>return((int)CallNextHookEx<BR>(hKeyHook,nCode,wParam,lParam)); <BR>} <BR>该程序的主要功能是监控键盘按键消息，将两个特殊按键Micro按下和抬起消息转换 成自定义类型的消息，并将自定义消息发送给应用程序主窗口函数。<BR><BR>２、在应用程序主函数中建立窗口后，调用InitHooksDll()函数来初始化动态链接 库，并将应用程序主窗口句柄传递给链接库，然后调用InstallFilter()函数挂接键 盘事件监控回调函数。 <BR>InitHooksDll(hIMEWnd); //初始化DLL <BR>InstallFilter(TRUE); //安装键盘回调函数 <BR><BR>３、在应用程序主窗口函数处理自定义消息时，保存Micro按键的状态，供组合按键 处理时判断使用。 <BR>switch (iMessage) <BR>{ <BR>case 0x7fff: //自定义消息类型 <BR>if(lParam==0x3L)<BR>{//设置Micro键的状态 <BR>if(wParam==0x1) <BR>MicroFlag=TRUE; <BR>else if(wParam==0x2) <BR>MicroFlag=FALSE; <BR>} <BR>break; <BR><BR>４、在进行按键组合处理时，首先判断Micro键是否按下，然后再进行其它按键的判 断处理。 <BR>case WM_KEYDOWN: // 按键按下处理 <BR>if(MicroFlag==TRUE)<BR>{<BR>//Micro键按下 <BR>if((BYTE)HIBYTE(wParam)==0x5b)<BR>{ <BR>//Micro+"["组合键 ......//按键功能处理 } <BR>else if((BYTE)HIBYTE(wParam)==0x5d)<BR>{ <BR>//Micro+"]"组合键 ......//按键功能处理 } } break; <BR><BR>５、当应用程序退出时应注意下载键盘监控函数，即调用InstallFilter(FALSE)函 数一次。 <BR><BR>６、利用本文提供的方法设置自己的应用程序功能按键，在保证程序功能按键不会 与其它系统发生冲突的同时，有效地利用了系统中现有资源，而且在实现应用程序 功能的同时灵活应用了系统中提供的各种功能调用。</P><img src ="http://www.blogjava.net/huyi/aggbug/2464.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-26 12:59 <a href="http://www.blogjava.net/huyi/archive/2005/03/26/2464.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>转贴：在应用程序中监视剪贴板的变化和内容</title><link>http://www.blogjava.net/huyi/archive/2005/03/23/2389.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Wed, 23 Mar 2005 11:04:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/23/2389.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2389.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/23/2389.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2389.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2389.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>剪贴板是<SPAN lang=EN-US>Windows中系统级的堆空间，系统中任何一个应用程序对剪贴板都有访问权，可以通过剪贴板消息和使用剪贴板API来读写剪贴板内容。因此使用剪贴板不仅可以在同一个应用程序内交互数据，也可以在不通应用程序之间交互数据。尤其是在不通应用程序之间交互时，应用程序往往需要对剪贴板内容的变化做到实时感知，即应用程序要能监视剪贴板内容的变化。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>Windows应用是消息驱动的，同理当剪贴板内容发生变化时，Windows提供了剪贴板变化消息，因此要实时感知剪贴板内容的变化，关键是应用程序要能响应和处理Windows触发的剪贴板变化消息。<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>第一步，要将窗口注册为<SPAN lang=EN-US>Clipboard Viewer<o:p></o:p></SPAN></FONT></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>需要首先解释两个概念：<SPAN lang=EN-US>Clipboard Viewer和Clipboard Viewer Chain。<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>Clipboard Viewer是一个需要取得并显示剪贴板内容的窗口，通过Clipboard Viewer这个机制，应用程序可以在不影响剪贴板内容的情况下获取剪贴板的变化消息。Clipboard Viewer可以显示系统定义的标准格式的剪贴板内容，也可以显示应用自定义的私有数据格式的内容。通过调用函数SetClipboardViewer将窗口注册为Clipboard Viewer。<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>Clipboard Viewer Chain是保存Clipboard Viewer窗口以及他们之间的前后向关系的一个Windows系统链表，当一个窗口注册为Clipboard Viewer后，他会被加入Clipboard Viewer Chain，并得到链表中下一个Viewer窗口的句柄，该句柄必须保存以在响应消息时使用，该句柄的作用在下文说明。Windows正是通过Clipboard Viewer Chain保证了所有Clipboard Viewer能接收和响应剪贴板变化消息。<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>第二步，响应剪贴板变化消息，判断和取出剪贴板内容<SPAN lang=EN-US><o:p></o:p></SPAN></FONT></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>在消息响应里必须正确处理两个消息：<SPAN lang=EN-US>WM_DRAWCLIPBOARD和WM_CHANGECBCHAIN。<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>当剪贴板内容发生变化时，<SPAN lang=EN-US>Windows将触发WM_DRAWCLIPBOARD消息，并将该消息送给Clipboard Viewer Chain的第一个窗口。每一个Clipboard Viewer窗口，包括第一个窗口在响应和处理该消息后，必须根据其保存的链表中的下一个窗口的句柄将该消息发送给下一个Clipboard Viewer窗口。窗口可以在该消息中取出剪贴板内容，并判断是否是该窗口增在监视的内容，如果是就进行相应的处理。<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>当某个<SPAN lang=EN-US>Clipboard Viewer窗口注销时，系统将触发WM_CHANGECBCHAIN，并将该消息送给Clipboard Viewer Chain的第一个窗口。每一个窗口必须处理该消息。<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>第三步，将窗口从<SPAN lang=EN-US>Clipboard Viewer Chain中注销<o:p></o:p></SPAN></FONT></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>当窗口不再需要监视剪贴板变化消息，或窗口要关闭时，必须调用<SPAN lang=EN-US>ChangeClipboardChain函数将窗口从Clipboard Viewer Chain中注销。注销后系统会触发WM_CHANGECBCHAIN消息，同WM_DRAWCLIPBOARD消息一样，该消息会给发送给Clipboard Viewer Chain的第一个窗口处理。下面代码示例当窗口被关闭时进行注销。<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>下面的代码片断给出了监视剪贴板中是否拷贝了<SPAN lang=EN-US>URL地址的例子，如果剪贴板中的内容是URL地址，则将其显示在窗口界面上。为使示例代码具有一般性，下面给出了一般Windows程序代码和基于MFC的代代码。其他语言要实现该功能可以参考Windows程序代码。两个DEMO的完成代码请见附件。<o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>Windows程序示例代码<o:p></o:p></FONT></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>int wmId, wmEvent;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>PAINTSTRUCT ps;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>HDC hdc;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>unsigned int anFormats[] = {CF_TEXT};<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>unsigned int nFormat;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>switch (message) <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//----------------------------------------------------------------<SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>case WM_CREATE:<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>//将本窗口注册到Clipboard Viewer Chain，<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//并保存Clipboard Viewer Chain中下一个窗口的句柄<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>hwndNextViewer = SetClipboardViewer(hWnd); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>break; <SPAN style="mso-tab-count: 1"></SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>case WM_CHANGECBCHAIN:<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>//Clipboard Viewer注销<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>//如果注销的Clipboard Viewer窗口是本窗口的下一个窗口，<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//则修改本窗口保存的下一个窗口句柄,<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//否则将该消息传递到Clipboard Viewer Chain的下一个窗口<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>if ((HWND) wParam == hwndNextViewer) <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>hwndNextViewer = (HWND) lParam; <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>else if (hwndNextViewer != NULL) <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>SendMessage(hwndNextViewer, message, wParam, lParam);<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>break; <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>case WM_DRAWCLIPBOARD:<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>//剪贴板内容变化<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>//触发ON_PAINT显示URL内容<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>InvalidateRect(hWnd, NULL, TRUE); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>UpdateWindow(hWnd); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>//否则将该消息传递到Clipboard Viewer Chain的下一个窗口<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>SendMessage(hwndNextViewer, message, wParam, lParam); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>break; <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>case WM_DESTROY:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//从Clipboard Viewer Chain注销本窗口<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>ChangeClipboardChain(hWnd, hwndNextViewer); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>PostQuitMessage(0);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>break;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//----------------------------------------------------------------<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>case WM_COMMAND:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>wmId<SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>= LOWORD(wParam); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>wmEvent = HIWORD(wParam); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>// Parse the menu selections:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>switch (wmId)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>case IDM_ABOUT:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 42pt; mso-char-indent-count: 4.0; mso-char-indent-size: 10.5pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>hWnd, (DLGPROC)About);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>break;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>case IDM_EXIT:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>DestroyWindow(hWnd);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>break;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>default:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>return DefWindowProc(hWnd, message, wParam, lParam);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>break;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>case WM_PAINT:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>hdc = BeginPaint(hWnd, &amp;ps);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//判断剪贴板中的内容是否为URL地址，如是则显示<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>nFormat = GetPriorityClipboardFormat(anFormats,sizeof(anFormats));<SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>if(nFormat == CF_TEXT)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>OpenClipboard(hWnd); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>HGLOBAL hMem = GetClipboardData(nFormat); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>LPTSTR lpstr = (LPTSTR)GlobalLock(hMem); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>if(strstr(lpstr,"http://") != NULL ||<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>strstr(lpstr,"ftp://")<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>!= NULL ||<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>strstr(lpstr,"file://") != NULL)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>RECT rt;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>GetClientRect(hWnd, &amp;rt);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>DrawText(hdc, lpstr, -1, &amp;rt, DT_LEFT);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>GlobalUnlock(hMem); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>CloseClipboard(); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>} <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>EndPaint(hWnd, &amp;ps);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>break;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>default:<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>return DefWindowProc(hWnd, message, wParam, lParam);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>return 0;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>MFC程序示例代码<o:p></o:p></FONT></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体"><FONT size=3>首先要映射以下消息和继承以下函数<SPAN lang=EN-US><o:p></o:p></SPAN></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>afx_msg void OnChangeCbChain(HWND hWndRemove, HWND hWndAfter);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>afx_msg void OnDrawClipboard();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>afx_msg void OnDestroy();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>virtual void OnInitialUpdate();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>void CMonitorUrlView::OnInitialUpdate()<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>CListView::OnInitialUpdate();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>m_pListCtrl = &amp;GetListCtrl();;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>m_pListCtrl-&gt;SetExtendedStyle(LVS_EX_FULLROWSELECT |<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>LVS_EX_GRIDLINES |<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>LVS_EX_TRACKSELECT |<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>LVS_EX_TWOCLICKACTIVATE |<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp; </SPAN>LVS_EX_UNDERLINECOLD);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>m_pListCtrl-&gt;ModifyStyle(LVS_TYPEMASK, LVS_REPORT); <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>m_pListCtrl-&gt;InsertColumn(0, "URL",LVCFMT_LEFT,600,1);<SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//将本窗口注册到Clipboard Viewer Chain，<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//并保存Clipboard Viewer Chain中下一个窗口的句柄<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>m_hwndNextViewer = SetClipboardViewer();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>void CMonitorUrlView::OnDestroy() <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>CListView::OnDestroy();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//从Clipboard Viewer Chain注销本窗口<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>ChangeClipboardChain(m_hwndNextViewer);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>//Clipboard Viewer注销<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>void CMonitorUrlView::OnChangeCbChain(HWND hWndRemove, HWND hWndAfter) <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//如果注销的Clipboard Viewer窗口是本窗口的下一个窗口，<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>//则修改本窗口保存的下一个窗口句柄,<SPAN style="mso-tab-count: 1"> </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>CView::OnChangeCbChain(hWndRemove,hWndAfter);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>if(hWndRemove == m_hwndNextViewer)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>m_hwndNextViewer = hWndAfter;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>&nbsp;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>//剪贴板内容变化,判断剪贴板中的内容是否为URL地址，如是则显示<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>void CMonitorUrlView::OnDrawClipboard() <o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>CView::OnDrawClipboard();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>unsigned int anFormats[] = {CF_TEXT};<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>unsigned int nFormat =<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 63pt; TEXT-INDENT: 21pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-spacerun: yes">&nbsp;</SPAN>GetPriorityClipboardFormat(anFormats,sizeof(anFormats));<SPAN style="mso-tab-count: 1">&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>if(nFormat == CF_TEXT)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>HGLOBAL hMem;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>OpenClipboard();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>if(hMem = ::GetClipboardData(CF_TEXT))<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>LPTSTR lpszText = (LPTSTR) GlobalLock(hMem);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>CString strURL = lpszText;<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>strURL = strURL.SpanExcluding("\r\n");<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>if(strURL.Left(7).CompareNoCase("http://") == 0 ||<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>strURL.Left(6).CompareNoCase("ftp://")<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>== 0 ||<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>strURL.Left(7).CompareNoCase("file://") == 0)<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>m_pListCtrl-&gt;InsertItem(0,lpszText);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>GlobalUnlock(hMem);<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>CloseClipboard();<o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3><SPAN style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </SPAN>}<SPAN style="mso-tab-count: 1">&nbsp;&nbsp; </SPAN><o:p></o:p></FONT></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US style="FONT-FAMILY: 宋体"><FONT size=3>}<o:p></o:p></FONT></SPAN></P><img src ="http://www.blogjava.net/huyi/aggbug/2389.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-23 19:04 <a href="http://www.blogjava.net/huyi/archive/2005/03/23/2389.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DLL的Export和Import</title><link>http://www.blogjava.net/huyi/archive/2005/03/01/1582.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Tue, 01 Mar 2005 00:53:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/01/1582.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/1582.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/01/1582.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/1582.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/1582.html</trackback:ping><description><![CDATA[<A href="http://dev.csdn.net/article/62/62859.shtm">http://dev.csdn.net/article/62/62859.shtm</A><img src ="http://www.blogjava.net/huyi/aggbug/1582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-01 08:53 <a href="http://www.blogjava.net/huyi/archive/2005/03/01/1582.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++ ADO数据库编程入门</title><link>http://www.blogjava.net/huyi/archive/2005/03/01/1581.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Tue, 01 Mar 2005 00:46:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/01/1581.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/1581.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/01/1581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/1581.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/1581.html</trackback:ping><description><![CDATA[<A href="http://dev.csdn.net/article/63/63402.shtm">http://dev.csdn.net/article/63/63402.shtm</A><BR><A href="http://dev.csdn.net/article/63/63401.shtm">http://dev.csdn.net/article/63/63401.shtm</A><img src ="http://www.blogjava.net/huyi/aggbug/1581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-01 08:46 <a href="http://www.blogjava.net/huyi/archive/2005/03/01/1581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>