﻿<?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>C++博客-君子性非异也，善假于物也。-随笔分类-程序设计</title><link>http://www.cppblog.com/xushaohua/category/2730.html</link><description>如有恒，何须三更起，半夜眠；最怕莫，三天打鱼两天晒网，竹篮打水一场空！</description><language>zh-cn</language><lastBuildDate>Tue, 17 Feb 2009 05:42:31 GMT</lastBuildDate><pubDate>Tue, 17 Feb 2009 05:42:31 GMT</pubDate><ttl>60</ttl><item><title>[转]Win32应用程序中进程间通信方法分析与比较</title><link>http://www.cppblog.com/xushaohua/archive/2009/02/17/74015.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Tue, 17 Feb 2009 03:18:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2009/02/17/74015.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/74015.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2009/02/17/74015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/74015.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/74015.html</trackback:ping><description><![CDATA[<span  style="color: rgb(75, 75, 75); font-family: Verdana; font-size: 13px; line-height: 19px; "><p align="center" style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; "><strong>Win32</strong><strong>应用程序中进程间通信方法分析与比较</strong></p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; ">&#160;</p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; "><strong>1&#160;</strong><strong>进程与进程通信</strong></p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; ">&#160;</p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; ">　　进程是装入内存并准备执行的程序，每个进程都有私有的虚拟地址空间，由代码、数据以及它可利用的系统资源(如文件、管道等)组成。多进程/多线程是Windows操作系统的一个基本特征。Microsoft Win32应用编程接口(Application Programming Interface, API)提供了大量支持应用程序间数据共享和交换的机制，这些机制行使的活动称为进程间通信(InterProcess Communication, IPC)，进程通信就是指不同进程间进行数据共享和数据交换。<br>　　正因为使用Win32 API进行进程通信方式有多种，如何选择恰当的通信方式就成为应用开发中的一个重要问题，下面本文将对Win32中进程通信的几种方法加以分析和比较。</p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; ">&#160;</p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; "><strong>2&#160;</strong><strong>进程通信方法</strong></p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; "><strong>2.1&#160;</strong><strong>文件映射</strong><br>　　文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此，进程不必使用文件I/O操作，只需简单的指针操作就可读取和修改文件的内容。<br>　　Win32 API允许多个进程访问同一文件映射对象，各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针，不同进程就可以读或修改文件的内容，实现了对文件中数据的共享。<br>　　应用程序有三种方法来使多个进程共享一个文件映射对象。<br>　　(1)继承：第一个进程建立文件映射对象，它的子进程继承该对象的句柄。<br>　　(2)命名文件映射：第一个进程在建立文件映射对象时可以给该对象指定一个名字(可与文件名不同)。第二个进程可通过这个名字打开此文件映射对象。另外，第一个进程也可以通过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。<br>　　(3)句柄复制：第一个进程建立文件映射对象，然后通过其它IPC机制(有名管道、邮件槽等)把对象句柄传递给第二个进程。第二个进程复制该句柄就取得对该文件映射对象的访问权限。<br>　　文件映射是在多个进程间共享数据的非常有效方法，有较好的安全性。但文件映射只能用于本地机器的进程之间，不能用于网络中，而开发者还必须控制进程间的同步。<br><strong>2.2&#160;</strong><strong>共享内存</strong><br>　　Win32 API中共享内存(Shared Memory)实际就是文件映射的一种特殊情况。进程在创建文件映射对象时用0xFFFFFFFF来代替文件句柄(HANDLE)，就表示了对应的文件映射对象是从操作系统页面文件访问内存，其它进程打开该文件映射对象就可以访问该内存块。由于共享内存是用文件映射实现的，所以它也有较好的安全性，也只能运行于同一计算机上的进程之间。<br><strong>2.3&#160;</strong><strong>匿名管道</strong><br>　　管道(Pipe)是一种具有两个端点的通信通道：有一端句柄的进程可以和有另一端句柄的进程通信。管道可以是单向－一端是只读的，另一端点是只写的；也可以是双向的一管道的两端点既可读也可写。<br>　　匿名管道(Anonymous Pipe)是在父进程和子进程之间，或同一父进程的两个子进程之间传输数据的无名字的单向管道。通常由父进程创建管道，然后由要通信的子进程继承通道的读端点句柄或写端点句柄，然后实现通信。父进程还可以建立两个或更多个继承匿名管道读和写句柄的子进程。这些子进程可以使用管道直接通信，不需要通过父进程。<br>　　匿名管道是单机上实现子进程标准I/O重定向的有效方法，它不能在网上使用，也不能用于两个不相关的进程之间。<br><strong>2.4&#160;</strong><strong>命名管道</strong><br>　　命名管道(Named Pipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。不同于匿名管道的是命名管道可以在不相关的进程之间和不同计算机之间使用，服务器建立命名管道时给它指定一个名字，任何进程都可以通过该名字打开管道的另一端，根据给定的权限和服务器进程通信。<br>　　命名管道提供了相对简单的编程接口，使通过网络传输数据并不比同一计算机上两进程之间通信更困难，不过如果要同时和多个进程通信它就力不从心了。<br><strong>2.5&#160;</strong><strong>邮件槽</strong><br>　　邮件槽(Mailslots)提供进程间单向通信能力，任何进程都能建立邮件槽成为邮件槽服务器。其它进程，称为邮件槽客户，可以通过邮件槽的名字给邮件槽服务器进程发送消息。进来的消息一直放在邮件槽中，直到服务器进程读取它为止。一个进程既可以是邮件槽服务器也可以是邮件槽客户，因此可建立多个邮件槽实现进程间的双向通信。<br>　　通过邮件槽可以给本地计算机上的邮件槽、其它计算机上的邮件槽或指定网络区域中所有计算机上有同样名字的邮件槽发送消息。广播通信的消息长度不能超过400字节，非广播消息的长度则受邮件槽服务器指定的最大消息长度的限制。<br>　　邮件槽与命名管道相似，不过它传输数据是通过不可靠的数据报(如TCP/IP协议中的UDP包)完成的，一旦网络发生错误则无法保证消息正确地接收，而命名管道传输数据则是建立在可靠连接基础上的。不过邮件槽有简化的编程接口和给指定网络区域内的所有计算机广播消息的能力，所以邮件槽不失为应用程序发送和接收消息的另一种选择。<br><strong>2.6&#160;</strong><strong>剪贴板</strong><br>　　剪贴板(Clipped Board)实质是Win32 API中一组用来传输数据的函数和消息，为Windows应用程序之间进行数据共享提供了一个中介，Windows已建立的剪切(复制)－粘贴的机制为不同应用程序之间共享不同格式数据提供了一条捷径。当用户在应用程序中执行剪切或复制操作时，应用程序把选取的数据用一种或多种格式放在剪贴板上。然后任何其它应用程序都可以从剪贴板上拾取数据，从给定格式中选择适合自己的格式。<br>　　剪贴板是一个非常松散的交换媒介，可以支持任何数据格式，每一格式由一无符号整数标识，对标准(预定义)剪贴板格式，该值是Win32 API定义的常量；对非标准格式可以使用Register Clipboard Format函数注册为新的剪贴板格式。利用剪贴板进行交换的数据只需在数据格式上一致或都可以转化为某种格式就行。但剪贴板只能在基于Windows的程序中使用，不能在网络上使用。<br><strong>2.7&#160;</strong><strong>动态数据交换</strong><br>　　动态数据交换(DDE)是使用共享内存在应用程序之间进行数据交换的一种进程间通信形式。应用程序可以使用DDE进行一次性数据传输，也可以当出现新数据时，通过发送更新值在应用程序间动态交换数据。<br>　　DDE和剪贴板一样既支持标准数据格式(如文本、位图等)，又可以支持自己定义的数据格式。但它们的数据传输机制却不同，一个明显区别是剪贴板操作几乎总是用作对用户指定操作的一次性应答－如从菜单中选择Paste命令。尽管DDE也可以由用户启动，但它继续发挥作用一般不必用户进一步干预。DDE有三种数据交换方式：<br>　　(1) 冷链：数据交换是一次性数据传输，与剪贴板相同。<br>　　(2) 温链：当数据交换时服务器通知客户，然后客户必须请求新的数据。<br>　　(3) 热链：当数据交换时服务器自动给客户发送数据。<br>　　DDE交换可以发生在单机或网络中不同计算机的应用程序之间。开发者还可以定义定制的DDE数据格式进行应用程序之间特别目的IPC，它们有更紧密耦合的通信要求。大多数基于Windows的应用程序都支持DDE。<br><strong>2.8&#160;</strong><strong>对象连接与嵌入</strong><br>　　应用程序利用对象连接与嵌入(OLE)技术管理复合文档(由多种数据格式组成的文档)，OLE提供使某应用程序更容易调用其它应用程序进行数据编辑的服务。例如，OLE支持的字处理器可以嵌套电子表格，当用户要编辑电子表格时OLE库可自动启动电子表格编辑器。当用户退出电子表格编辑器时，该表格已在原始字处理器文档中得到更新。在这里电子表格编辑器变成了字处理器的扩展，而如果使用DDE，用户要显式地启动电子表格编辑器。<br>　　同DDE技术相同，大多数基于Windows的应用程序都支持OLE技术。<br><strong>2.9&#160;</strong><strong>动态连接库</strong><br>　　Win32动态连接库(DLL)中的全局数据可以被调用DLL的所有进程共享，这就又给进程间通信开辟了一条新的途径，当然访问时要注意同步问题。<br>　　虽然可以通过DLL进行进程间数据共享，但从数据安全的角度考虑，我们并不提倡这种方法，使用带有访问权限控制的共享内存的方法更好一些。<br><strong>2.10&#160;</strong><strong>远程过程调用</strong><br>　　Win32 API提供的远程过程调用(RPC)使应用程序可以使用远程调用函数，这使在网络上用RPC进行进程通信就像函数调用那样简单。RPC既可以在单机不同进程间使用也可以在网络中使用。<br>　　由于Win32 API提供的RPC服从OSF-DCE(Open Software Foundation Distributed Computing Environment)标准。所以通过Win32 API编写的RPC应用程序能与其它操作系统上支持DEC的RPC应用程序通信。使用RPC开发者可以建立高性能、紧密耦合的分布式应用程序。<br><strong>2.11 NetBios</strong><strong>函数</strong><br>　　Win32 API提供NetBios函数用于处理低级网络控制，这主要是为IBM NetBios系统编写与Windows的接口。除非那些有特殊低级网络功能要求的应用程序，其它应用程序最好不要使用NetBios函数来进行进程间通信。<br><strong>2.12 Sockets</strong><br>　　Windows Sockets规范是以U.C.Berkeley大学BSD UNIX中流行的Socket接口为范例定义的一套Windows下的网络编程接口。除了Berkeley Socket原有的库函数以外，还扩展了一组针对Windows的函数，使程序员可以充分利用Windows的消息机制进行编程。<br>　　现在通过Sockets实现进程通信的网络应用越来越多，这主要的原因是Sockets的跨平台性要比其它IPC机制好得多，另外WinSock 2.0不仅支持TCP/IP协议，而且还支持其它协议(如IPX)。Sockets的唯一缺点是它支持的是底层通信操作，这使得在单机的进程间进行简单数据传递不太方便，这时使用下面将介绍的WM_COPYDATA消息将更合适些。<br><strong>2.13 WM_COPYDATA</strong><strong>消息</strong><br>　　WM_COPYDATA是一种非常强大却鲜为人知的消息。当一个应用向另一个应用传送数据时，发送方只需使用调用SendMessage函数，参数是目的窗口的句柄、传递数据的起始地址、WM_COPYDATA消息。接收方只需像处理其它消息那样处理WM_COPY DATA消息，这样收发双方就实现了数据共享。<br>　　WM_COPYDATA是一种非常简单的方法，它在底层实际上是通过文件映射来实现的。它的缺点是灵活性不高，并且它只能用于Windows平台的单机环境下。</p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; ">&#160;</p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; "><strong>3&#160;</strong><strong>结束语</strong></p><p style="line-height: 150%; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; ">　　Win32 API为应用程序实现进程间通信提供了如此多种选择方案，那么开发者如何进行选择呢？通常在决定使用哪种IPC方法之前应考虑下一些问题，如应用程序是在网络环境下还是在单机环境下工作等。</p></span>
<img src ="http://www.cppblog.com/xushaohua/aggbug/74015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2009-02-17 11:18 <a href="http://www.cppblog.com/xushaohua/archive/2009/02/17/74015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BCD码</title><link>http://www.cppblog.com/xushaohua/archive/2007/12/24/39499.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Mon, 24 Dec 2007 04:34:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2007/12/24/39499.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/39499.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2007/12/24/39499.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/39499.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/39499.html</trackback:ping><description><![CDATA[即BCD代码。Binary-Coded Decimal&#8206;，简称BCD，称BCD码或二-十进制代码，亦称二进码十进数。是一种<a href="http://baike.baidu.com/view/18536.htm" target=_blank><u><font color=#0000ff>二进制</font></u></a>的数字编码形式，用二进制编码的<a href="http://baike.baidu.com/view/359301.htm" target=_blank><u><font color=#0000ff>十进制</font></u></a>代码。这种编码形式利用了四个位元来储存一个十进制的数码，使二进制和十进制之间的转换得以快捷的进行。这种编码技巧，最常用于会计系统的设计里，因为会计制度经常需要对很长的数字串作准确的计算。相对于一般的浮点式记数法，采用BCD码，既可保存数值的精确度，又可免却使电脑作浮点运算时所耗费的时间。此外，对于其他需要高精确度的计算，BCD编码亦很常用。<br><br>由于十进制数共有0、1、2、&#8230;&#8230;、9十个数码，因此，至少需要4位二进制码来表示1位十进制数。4位二进制码共有2^4=16种码组，在这16种代码中，可以任选10种来表示10个十进制数码，共有N=16！/（16-10）！约等于2.9乘以10的10次方种方案。常用的BCD代码列于末。<br><br><strong>常用BCD编码方式</strong><br>最常用的BCD编码，就是使用"0"至"9"这十个数值的二进码来表示。这种编码方式，在中国大陆称之为&#8220;8421码&#8221;。除此以外，对应不同需求，各人亦开发了不同的编码方法，以适应不同的需求。这些编码，大致可以分成有权码和无权码两种：<br><br>有权BCD码，如：8421(最常用)、2421、5421&#8230; <br>无权BCD码，如：余3码、格雷码&#8230; <br><br>常用<span>BCD编码表</span>
<div align=center>
<table cellSpacing=0 cellPadding=0 width="74%" border=1>
    <tbody>
        <tr>
            <td>
            <div align=center>
            <table cellSpacing=0 cellPadding=0 width=410 border=0>
                <tbody>
                    <tr>
                        <td width=90>
                        <p>&#160;</p>
                        </td>
                        <td width=67>
                        <p align=center><span>8421码</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>5421码</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>2421码</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>5211码</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>余<span>3码</span></span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>0</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0000</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0000</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0000</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0000</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0000</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>1</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0001</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0001</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0001</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0001</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0100</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>2</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0010</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0010</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0010</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0100</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0101</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>3</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0011</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0011</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0011</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0101</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0110</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>4</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0100</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0100</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0100</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0111</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>0111</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>5</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0101</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1000</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0101</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>1000</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1000</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>6</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0110</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1001</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0110</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>1001</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1001</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>7</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>0111</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1010</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>0111</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>1100</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1010</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>8</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>1000</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1011</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>1110</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>1101</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1011</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>9</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>1001</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1100</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>1111</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>1111</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>1100</span></p>
                        </td>
                    </tr>
                    <tr>
                        <td width=90>
                        <p align=center><span>权</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>8421</span></p>
                        </td>
                        <td width=60>
                        <p align=center><span>5421</span></p>
                        </td>
                        <td width=66>
                        <p align=center><span>2421</span></p>
                        </td>
                        <td width=67>
                        <p align=center><span>5211</span></p>
                        </td>
                        <td width=60>
                        <p>&nbsp;</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </div>
            <p>&#160;</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<span><font size=3>非压缩式和压缩式BCD码<br>&nbsp;&nbsp;&nbsp; BCD又分为两种，非压缩式和压缩式两种。<br>&nbsp;&nbsp;&nbsp; 前面这种81存成 &#8220;08,01&#8221; 是非压缩式，而压缩式会存成 &#8220;81h&#8221; (直接以十六进制储存)。非压缩的BCD码只有低四位有效，而压缩的BCD码则将高四位也用上了，就是说一个字节有两个BCD码。BCD是用0和1表示十进制，如0000表示0，0001表示1，0010表示2。而压缩的BCD是用00表示0，01表示1，10表示2，110表示3等。<br>&nbsp;&nbsp;&nbsp; 例：<br>&nbsp;&nbsp;&nbsp; 1234表示成非压缩的BCD码是00000001000000100000001100000100，也就是0x01020304；而压缩BCD码则表示成0001001000110100，也就是0x1234。<br>&nbsp;&nbsp;&nbsp; 但压缩的BCD并不固定，可看情况而定，所要的就是用最少的位数表示尽可能多的数。</font><br></span>
<img src ="http://www.cppblog.com/xushaohua/aggbug/39499.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2007-12-24 12:34 <a href="http://www.cppblog.com/xushaohua/archive/2007/12/24/39499.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]编写高效的数据库连接池</title><link>http://www.cppblog.com/xushaohua/archive/2007/12/21/39172.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Thu, 20 Dec 2007 17:42:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2007/12/21/39172.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/39172.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2007/12/21/39172.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/39172.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/39172.html</trackback:ping><description><![CDATA[<p><font face="Times New Roman" size=2>相关技术：</font></p>
<ul>
    <li><font face="Times New Roman" size=2>连接池</font>
    <li><font face="Times New Roman" size=2>引用记数</font>
    <li><font face="Times New Roman" size=2>多线程</font>
    <li><font face="Times New Roman" size=2>Timer类运行基理</font>
    <li><font face="Times New Roman" size=2>C#.Net</font>&nbsp;&nbsp; </li>
</ul>
<p><font face="Times New Roman" size=2>适宜人群</font></p>
<ul>
    <li><font face="Times New Roman" size=2>数据库应用程序程序员</font>
    <li><font face="Times New Roman" size=2>系统分析员</font>
    <li><font face="Times New Roman" size=2>模块设计师</font>
    <li>有一定功底的程序员 </li>
</ul>
<p>目录</p>
<ul>
    <li><font size=2>引言</font>
    <ol>
        <li><font face="Times New Roman" size=2>数据库连接池（Connection Pool）的工作原理</font> </li>
    </ol>
    <li><font face="Times New Roman" size=2>连接池关键问题分析</font>
    <ol>
        <li><font face="Times New Roman" size=2>并发问题</font>
        <li><font face="Times New Roman" size=2>事务处理</font>
        <li><font face="Times New Roman" size=2>连接池的分配与释放</font>
        <li><font face="Times New Roman" size=2>连接池的配置与维护</font> </li>
    </ol>
    <li>
    <div align=left><font face="Times New Roman" size=2>关键议题</font></div>
    <ol>
        <li>
        <div align=left><font face="Times New Roman" size=2>引用记数</font></div>
        <li>
        <div align=left>如何实现事务处理</div>
        <li>
        <div align=left>
        <div align=left>&nbsp;管理连接池</div>
        </div>
        </li>
    </ol>
    <li>
    <div align=left>
    <div align=left>结合代码说明</div>
    </div>
    <ol>
        <li>
        <div align=left>构造方法</div>
        <li>
        <div align=left><font size=2>启动服务StartService</font></div>
        <li>
        <div align=left><font size=2>停止服务StopService</font></div>
        <li>
        <div align=left><font size=2>申请&nbsp;GetConnectionFormPool</font></div>
        <li>
        <div align=left><font size=2>释放DisposeConnection</font></div>
        <li>
        <div align=left><font size=2>如何更新属性</font></div>
        <li>
        <div align=left><font size=2>如何确定连接是否失效</font></div>
        <li>
        <div align=left><font size=2>使用线程管理连接池</font></div>
        <ol>
            <li>
            <div align=left><font size=2>threadCreate</font></div>
            <li>
            <div align=left><font size=2>threadCheck</font></div>
            </li>
        </ol>
        <li>
        <div align=left><font size=2></font>
        <p>&nbsp;<font size=2>其他</font></p>
        </div>
        </li>
    </ol>
    </li>
</ul>
<hr>
<p><font color=#ff0000 size=3>引言</font></p>
<p><font face="Times New Roman" size=2>一般的数据库应用程序大致都遵循下面的步骤:</font></p>
<ol>
    <li><font face="Times New Roman"><font size=2><font color=#ff99cc>初始化程序</font> </font></font>
    <li><font face="Times New Roman"><font size=2><font color=#ff99cc>用户在UI上输入操作</font> </font></font>
    <li><font face="Times New Roman"><font size=2><font color=#ff99cc>由用户操作产生数据库操作</font> </font></font>
    <li><font face="Times New Roman"><font size=2><font color=#ff99cc>将数据库操作递交到数据库服务器</font> </font></font>
    <li><font face="Times New Roman"><font color=#ff99cc size=2>.... (重复2~4)</font></font>
    <li><font face="Times New Roman"><font size=2><font color=#ff99cc>关闭应用程序</font> </font></font></li>
</ol>
<p><font face="Times New Roman" size=2>　　而本文则着重讲解上面第<font color=#ff0000>4</font>步骤.在着一步骤中我们经常是,打开数据库连接操作数据库,最后关闭数据库.<br></font><font face="Times New Roman" size=2>　　在服务器端程序设计上与数据库的操作显得十分重要,因为你要处理的数据操作十分巨大.如果频繁创建数据库连接频繁关闭数据库连接则会引起效率低下甚至引发程序崩溃.<br>　　也许我们可以有另一种操作数据库的形式,我们可以在程序运行时打开一个数据库连接,让这个连接永久存在直到程序'死亡',那么这样做也有不安全隐患,我们知道一个对象存在时间越长或被使用次数越多则它表现的越不稳定,着不稳定因素是由于对象内部可能存在的潜在设计问题产生,对于数据库连接对象道理也一样.我们不能保证一个Connection对象里面能一点问题不存在.所以我们也不敢长时间将它长时间占用内存.<br></font><font face="Times New Roman" size=2>　　既然有这么多的问题由此我们需要一个能帮我们维护数据库连接的东西-它就是<font color=#ff0000>连接池</font>,网上有很多的连接池例子,但是多数都是简单的例子,或者介绍比较复杂的连接池原理,没有一个比较完整介绍和实现连接池的例子.这里就介绍你如何自己制作一个连接池.<br></font><font face="Times New Roman" size=2>　　对于共享资源，有一个很著名的设计模式：资源池（Resource Pool）。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决我们的问题，可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个&#8220;缓冲池&#8221;。预先在缓冲池中放入一定数量的连接，当需要建立数据库连接时，只需从&#8220;缓冲池&#8221;中取出一个，使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况，为系统开发﹑测试及性能调整提供依据。连接池的基本工作原理见下图。</font></p>
<p align=center><font face="Times New Roman" size=3>数据库连接池（Connection Pool）的工作原理</font></p>
<p align=center><font face="Times New Roman" size=2><img height=227 alt="" src="http://www.mx68.com/WebDeveloper/UploadFiles_5122/200601/2006118234027410.gif" width=563></font></p>
<p align=left><font face="Times New Roman" size=2><font face=Arial color=#ff0000 size=3></font></font></p>
<p><font color=#ff0000 size=3>&nbsp;连接池关键问题分析</font></p>
<p align=left><font face="Times New Roman" size=2>　　1、并发问题</font></p>
<p align=left><font face="Times New Roman" size=2>　　为了使连接管理服务具有最大的通用性，必须考虑多线程环境，即并发问题。这个问题相对比较好解决，因为各个语言自身提供了对并发管理的支持像java,c#等等，使用synchronized(java)lock(C#)关键字即可确保线程是同步的。使用方法可以参考，相关文献。</font></p>
<p align=left><font face="Times New Roman" size=2>　　２、事务处理</font></p>
<p align=left><font face="Times New Roman" size=2>　　我们知道，事务具有原子性，此时要求对数据库的操作符合&#8220;ALL-ALL-NOTHING&#8221;原则,即对于一组SQL语句要么全做，要么全不做。<br></font><font face="Times New Roman" size=2>　　我们知道当２个线程公用一个连接Connection对象，而且各自都有自己的事务要处理时候，对于连接池是一个很头疼的问题，因为即使Connection类提供了相应的事务支持，可是我们仍然不能确定那个数据库操作是对应那个事务的，这是由于我们有２个线程都在进行事务操作而引起的。为此我们可以使用</font><font face="Times New Roman" size=2>每一个事务独占一个连接来实现，虽然这种方法有点浪费连接池资源但是可以大大降低事务管理的复杂性。</font></p>
<p align=left><font face="Times New Roman" size=2>　　３、连接池的分配与释放</font></p>
<p align=left><font face="Times New Roman" size=2>　　连接池的分配与释放，对系统的性能有很大的影响。合理的分配与释放，可以提高连接的复用度，从而降低建立新连接的开销，同时还可以加快用户的访问速度。<br></font><font face="Times New Roman" size=2>　　对于连接的管理可使用一个List。即把已经创建的连接都放入List中去统一管理。每当用户请求一个连接时，系统检查这个List中有没有可以分配的连接。如果有就把那个最合适的连接分配给他<font color=#339966>（如何能找到最合适的连接文章将在关键议题中指出</font>）；如果没有就抛出一个异常给用户，List中连接是否可以被分配由一个线程来专门管理捎后我会介绍这个线程的具体实现。 </font></p>
<p>&nbsp;<font face="Times New Roman" size=2>　　４、连接池的配置与维护</font></p>
<p align=left><font face="Times New Roman" size=2>　　连接池中到底应该放置多少连接，才能使系统的性能最佳？系统可采取设置最小连接数（minConnection）和最大连接数（maxConnection）等参数来控制连接池中的连接。比方说，最小连接数是系统启动时连接池所创建的连接数。如果创建过多，则系统启动就慢，但创建后系统的响应速度会很快；如果创建过少，则系统启动的很快，响应起来却慢。这样，可以在开发时，设置较小的最小连接数，开发起来会快，而在系统实际使用时设置较大的，因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目，具体设置多少，要看系统的访问量，可通过软件需求上得到。<br></font><font face="Times New Roman" size=2>　　如何确保连接池中的最小连接数呢？有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测，如果发现连接数量小于最小连接数，则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。 </font></p>
<img src ="http://www.cppblog.com/xushaohua/aggbug/39172.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2007-12-21 01:42 <a href="http://www.cppblog.com/xushaohua/archive/2007/12/21/39172.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[MSDN]使用连接池</title><link>http://www.cppblog.com/xushaohua/archive/2007/12/21/39171.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Thu, 20 Dec 2007 17:33:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2007/12/21/39171.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/39171.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2007/12/21/39171.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/39171.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/39171.html</trackback:ping><description><![CDATA[<div class=title>使用连接池<!----></div>
<!--content type: DocStudio. Transform: devdiv2mtps.xslt.-->
<div id=mainSection>
<div id=mainBody>
<p>
<p>连接到数据库服务器通常由几个需要很长时间的步骤组成。必须建立物理通道（例如套接字或命名管道），必须与服务器进行初次握手，必须分析连接字符串信息，必须由服务器对连接进行身份验证，必须运行检查以便在当前事务中登记，等等。 </p>
<p>实际上，大多数应用程序仅使用一个或几个不同的连接配置。这意味着在执行应用程序期间，许多相同的连接将反复地打开和关闭。为了使打开的连接成本最低，ADO.NET 使用称为<em>连接池</em>的优化方法。</p>
<p>连接池减少新连接需要打开的次数。<em>池进程</em>保持物理连接的所有权。通过为每个给定的连接配置保留一组活动连接来管理连接。只要用户在连接上调用 Open，池进程就会检查池中是否有可用的连接。如果某个池连接可用，会将该连接返回给调用者，而不是打开新连接。应用程序在该连接上调用 Close 时，池进程会将连接返回到活动连接池集中，而不是真正关闭连接。连接返回到池中之后，即可在下一个 Open 调用中重复使用。</p>
<p>只有配置相同的连接可以建立池连接。ADO.NET 同时保留多个池，每个配置一个池。连接由连接字符串以及 Windows 标识（在使用集成的安全性时）分为多个池。</p>
<p>池连接可以大大提高应用程序的性能和可缩放性。默认情况下，ADO.NET 中启用连接池。除非显式禁用，否则，连接在应用程序中打开和关闭时，池进程将对连接进行优化。还可以提供几个连接字符串修饰符来控制连接池的行为。有关更多信息，请参见本主题后面的&#8220;使用连接字符串关键字控制连接池&#8221;。</p>
<h1 class=heading>池的创建和分配</h1>
<div class=seeAlsoNoToggleSection id=sectionSection0>
<p>在初次打开连接时，将根据完全匹配算法创建连接池，该算法将池与连接中的连接字符串关联。每个连接池与不同的连接字符串关联。打开新连接时，如果连接字符串并非与现有池完全匹配，将创建一个新池。按进程、按应用程序域、按连接字符串以及（在使用集成的安全性时）按 Windows 标识来建立池连接。</p>
<p>在以下 C# 示例中创建了三个新的 <a id=ctl00_rs1_mainContentContainer_ctl01 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl01',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/sd2728ad(VS.80).aspx"><u><font color=#0000ff>SqlConnection</font></u></a> 对象，但是管理时只需要两个连接池。注意，根据为 <tt>Initial Catalog</tt> 分配的值，第一个和第二个连接字符串有所不同。</p>
<div class=code id=ctl00_rs1_mainContentContainer_ctl02_other>
<pre class=code id=ctl00_rs1_mainContentContainer_ctl02other space="preserve">using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// Pool A is created.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=pubs"))
{
connection.Open();
// Pool B is created because the connection strings differ.
}
using (SqlConnection connection = new SqlConnection(
"Integrated Security=SSPI;Initial Catalog=Northwind"))
{
connection.Open();
// The connection string matches pool A.
}</pre>
</div>
<p>如果 MinPoolSize 在连接字符串中未指定或指定为零，池中的连接将在一段时间不活动后关闭。但是，如果指定的 MinPoolSize 大于零，在 AppDomain 被卸载并且进程结束之前，连接池不会被破坏。非活动或空池的维护只需要最少的系统开销。</p>
<div class=alert>
<table width="100%">
    <tbody>
        <tr>
            <th align=left><img class=note alt=Note src="http://msdn2.microsoft.com/zh-cn/library/8xx3tyca.note(zh-cn,VS.80).gif">注意</th>
        </tr>
        <tr>
            <td>
            <p>如果发生致命错误（例如故障转移或注册表中的别名更改），池将自动清除。</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<h1 class=heading>添加连接</h1>
<div class=seeAlsoNoToggleSection id=sectionSection1>
<p>连接池是为每个唯一的连接字符串创建的。当创建一个池后，将创建多个连接对象并将其添加到该池中，以满足最小池大小的要求。连接根据需要添加到池中，但是不能超过指定的最大池大小（默认值为 100）。连接在关闭或断开时释放回池中。 </p>
<p>在请求 SqlConnection 对象时，如果存在可用的连接，将从池中获取该对象。连接要可用，必须未使用，具有匹配的事务上下文或未与任何事务上下文关联，并且具有与服务器的有效链接。</p>
<p>连接池进程通过在连接释放回池中时重新分配连接，来满足这些连接请求。如果已达到最大池大小且不存在可用的连接，则该请求将会排队。然后，池进程尝试重新建立任何连接，直到到达超时时间（默认值为 15 秒）。如果池进程在连接超时之前无法满足请求，将引发异常。 </p>
<div class=alert>
<table width="100%">
    <tbody>
        <tr>
            <th align=left><img class=note alt="Caution note" src="http://msdn2.microsoft.com/zh-cn/library/8xx3tyca.Caution(zh-cn,VS.80).gif">警告</th>
        </tr>
        <tr>
            <td>
            <p>我们建议您在使用完连接时一定要关闭连接，以便连接可以返回池。要关闭连接，可以使用 Connection 对象的 Close 或 Dispose 方法，也可以通过在 C# 的 using 语句中或在 Visual Basic 的 Using 语句中打开所有连接。不是显式关闭的连接可能不会添加或返回到池中。例如，如果连接已超出范围但没有显式关闭，则仅当达到最大池大小而该连接仍然有效时，该连接才会返回到连接池中。有关更多信息，请参见 Visual Basic 的<a id=ctl00_rs1_mainContentContainer_ctl03 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl03',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/yh598w02(VS.80).aspx"><u><font color=#0000ff>using 语句（C# 参考）</font></u></a>或<a id=ctl00_rs1_mainContentContainer_ctl04 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl04',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/wydd5hkd(VS.80).aspx"><u><font color=#0000ff>如何：释放系统资源</font></u></a>。</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div class=alert>
<table width="100%">
    <tbody>
        <tr>
            <th align=left><img class=note alt=Note src="http://msdn2.microsoft.com/zh-cn/library/8xx3tyca.note(zh-cn,VS.80).gif">注意</th>
        </tr>
        <tr>
            <td>
            <p>不要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 Close 或 Dispose。在终结器中，仅释放类直接拥有的非托管资源。如果类不拥有任何非托管资源，则不要在类定义中包含 Finalize 方法。有关更多信息，请参见<a id=ctl00_rs1_mainContentContainer_ctl05 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl05',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/0xy59wtx(VS.80).aspx"><u><font color=#0000ff>垃圾回收</font></u></a>。</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<h1 class=heading>移除连接</h1>
<div class=seeAlsoNoToggleSection id=sectionSection2>
<p>连接池进程定期扫描连接池，查找没有通过 Close 或 Dispose 关闭的未用连接，并重新建立找到的连接。如果应用程序没有显式关闭或断开其连接，连接池进程可能需要很长时间才能重新建立连接，所以，最好确保在连接中显式调用 Close 和 Dispose。</p>
<p>如果连接长时间空闲，或池进程检测到与服务器的连接已断开，连接池进程会将该连接从池中移除。注意，只有在尝试与服务器进行通信之后才能检测到断开的连接。如果发现某连接不再连接到服务器，则会将其标记为无效。无效连接只有在关闭或重新建立后，才会从连接池中移除。</p>
<p>如果存在与已消失的服务器的连接，那么即使连接池管理程序未检测到已断开的连接并将其标记为无效，仍有可能将此连接从池中取出。这种情况是因为检查连接是否仍有效的系统开销将造成与服务器的另一次往返，从而抵消了池进程的优势。发生此情况时，初次尝试使用该连接将检测连接是否曾断开，并引发异常。</p>
</div>
<h1 class=heading>清除池</h1>
<div class=seeAlsoNoToggleSection id=sectionSection3>
<p>ADO.NET 2.0 引入了两种新的方法来清除池：<a id=ctl00_rs1_mainContentContainer_ctl06 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl06',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/565tk4bs(VS.80).aspx"><u><font color=#0000ff>ClearAllPools</font></u></a> 和 <a id=ctl00_rs1_mainContentContainer_ctl07 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl07',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/tw22a676(VS.80).aspx"><u><font color=#0000ff>ClearPool</font></u></a>。ClearAllPools 清除给定提供程序的连接池，ClearPool 清除与特定连接关联的连接池。如果在调用时连接正在使用，将进行相应的标记。连接关闭时，将被丢弃，而不是返回池中。</p>
</div>
<h1 class=heading>事务支持</h1>
<div class=seeAlsoNoToggleSection id=sectionSection4>
<p>连接是根据事务上下文来从池中取出并进行分配的。除非在连接字符串中指定了 <tt>Enlist=false</tt>，否则，连接池将确保连接在 <a id=ctl00_rs1_mainContentContainer_ctl08 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl08',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/f1a9t75e(VS.80).aspx"><u><font color=#0000ff>Current</font></u></a> 上下文中登记。如果连接使用登记的 System.Transactions 事务关闭并返回池中，连接将保留在池中，以便使用相同 System.Transactions 事务对该连接池的下一次请求将返回相同的连接。如果该事务没有可用连接，在该连接打开时，将自动注册该连接。</p>
<p>当连接关闭时，它将被释放回池中，并根据其事务上下文放入相应的子部分。因此，即使分布式事务仍然挂起，仍可以关闭该连接而不会生成错误。这样，您就可以在随后提交或中止分布式事务。</p>
</div>
<h1 class=heading>使用连接字符串关键字控制连接池</h1>
<div class=seeAlsoNoToggleSection id=sectionSection5>
<p>SqlConnection 对象的 ConnectionString 属性支持连接字符串键/值对，可以用于调整连接池逻辑的行为。有关更多信息，请参见 <a id=ctl00_rs1_mainContentContainer_ctl09 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl09',this);" tabIndex=0 href="http://msdn2.microsoft.com/zh-cn/library/f28szy5b(VS.80).aspx"><u><font color=#0000ff>ConnectionString</font></u></a>。</p>
</div>
<h1 class=heading>池碎片</h1>
<div class=seeAlsoNoToggleSection id=sectionSection6>
<p>池碎片是许多 Web 应用程序中的一个常见问题，应用程序可能会创建大量在进程退出后才会释放的池。这样，将打开大量的连接，占用许多内存，从而影响性能。</p>
<h3 class=subHeading>因为集成安全性产生的池碎片</h3>
<div class=subSection>
<p>连接根据连接字符串以及用户标识来建立池连接。因此，如果使用网站上的基本身份验证或 Windows 身份验证以及集成的安全登录，每个用户将获得一个池。尽管这样可以提高单个用户的后续数据库请求的性能，但是该用户无法利用其他用户建立的连接。这样还使每个用户至少产生一个与数据库服务器的连接。这对特定 Web 应用程序结构会产生副作用，因为开发人员需要衡量安全性和审计要求。</p>
</div>
<h3 class=subHeading>因为许多数据库产生的池碎片</h3>
<div class=subSection>
<p>许多 Internet 服务提供商在一台服务器上托管多个网站。他们可能使用单个数据库确认窗体身份验证登录，然后为该用户或用户组打开与特定数据库的连接。与身份验证数据库的连接将建立池连接，供每个用户使用。但是，每个数据库的连接存在一个独立的池，因此增加了与服务器的连接数。</p>
<p>这也会对应用程序设计产生副作用。但是，可以通过一个相对简单的方式避免此副作用，而又不会影响连接 SQL Server 时的安全性。不是为每个用户或组连接独立的数据库，而是连接到服务器上的相同数据库，然后执行 Transact-SQL USE 语句来切换为所需的数据库。以下代码段演示入如何创建与 master 数据库的初始连接，然后切换到 <tt>databaseName</tt> 字符串变量中指定的所需数据库。</p>
<div class=code id=ctl00_rs1_mainContentContainer_ctl11_CSharp>C#:<br><span style="COLOR: green">// Assumes that command is a SqlCommand object.</span><br><span style="COLOR: blue">using</span> (SqlConnection connection = <span style="COLOR: blue">new</span> SqlConnection(<br>&nbsp; <span style="COLOR: maroon">"Server=MSSQL1;uid=xxx;pwd=xxx;database=master"</span>))<br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; connection.Open();<br>&nbsp;&nbsp;&nbsp; command.ExecuteNonQuery(<span style="COLOR: maroon">"USE "</span> + databaseName);<br>&nbsp; }<br></div>
</div>
</div>
<h1 class=heading>应用程序角色和连接池</h1>
<div class=seeAlsoNoToggleSection id=sectionSection7>
<p>通过调用 sp_setapprole 系统存储过程激活了 SQL Server 应用程序角色之后，该连接的安全上下文无法重置。但是，如果启用了池，连接将返回池，在重复使用池连接时会出错。</p>
<p>如果使用的是 SQL Server 应用程序角色，我们建议您在连接字符串中为应用程序禁用连接池。有关更多信息，请参见知识库文章&#8220;<a id=ctl00_rs1_mainContentContainer_ctl12 onclick="javascript:Track('ctl00_rs1_mainContentContainer_ctl00|ctl00_rs1_mainContentContainer_ctl12',this);" tabIndex=0 href="http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q229564"><u><font color=#0000ff>SQL application role errors with OLE DB resource pooling</font></u></a>&#8221;。</p>
</div>
</div>
</div>
<img src ="http://www.cppblog.com/xushaohua/aggbug/39171.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2007-12-21 01:33 <a href="http://www.cppblog.com/xushaohua/archive/2007/12/21/39171.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]VC中基于 Windows 的精确定时</title><link>http://www.cppblog.com/xushaohua/archive/2007/12/04/37817.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Tue, 04 Dec 2007 12:56:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2007/12/04/37817.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/37817.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2007/12/04/37817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/37817.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/37817.html</trackback:ping><description><![CDATA[中国科学院光电技术研究所 <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#121;&#122;&#121;&#115;&#101;&#97;&#108;&#64;&#49;&#50;&#54;&#46;&#99;&#111;&#109;"><u><font color=#0000ff>游志宇</font></u></a><br><br>在工业生产控制系统中，有许多需要定时完成的操作，如定时显示当前时间，定时刷新屏幕上的进度条，上位<wbr> 机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的实时控制系统和数据采集系统中，就更需要精确定时操作。<br>　　众所周知，Windows 是基于消息机制的系统，任何事件的执行都是通过发送和接收消息来完成的。<wbr> 这样就带来了一些问题，如一旦计算机的CPU被某个进程占用，或系统资源紧张时，发送到消息队列<wbr> 中的消息就暂时被挂起，得不到实时处理。因此，不能简单地通过Windows消息引发一个对定时要求<wbr> 严格的事件。另外，由于在Windows中已经封装了计算机底层硬件的访问，所以，要想通过直接利用<wbr> 访问硬件来完成精确定时，也比较困难。所以在实际应用时，应针对具体定时精度的要求，采取相适 应的定时方法。<br>　　VC中提供了很多关于时间操作的函数，利用它们控制程序能够精确地完成定时和计时操作。本文详细介绍了<wbr> VC中基于Windows的精确定时的七种方式，如下图所示：<br><img height=419 alt="" src="http://www.cppblog.com/images/cppblog_com/xushaohua/MultiTimerDemoimg.gif" width=639 border=0><br>图一 图像描述 <br><br>　　方式一：VC中的WM_TIMER消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时<wbr> 间隔，如SetTimer(0,200,NULL)即为设置200ms的时间间隔。然后在应用程序中增加定时响应函数<wbr> OnTimer()，并在该函数中添加响应的处理语句，用来完成到达定时时间的操作。这种定时方法非常<wbr> 简单，可以实现一定的定时功能，但其定时功能如同Sleep()函数的延时功能一样，精度非常低，最小<wbr> 计时精度仅为30ms，CPU占用低，且定时器消息在多任务操作系统中的优先级很低，不能得到及时响<wbr> 应，往往不能满足实时控制环境下的应用。只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。如示例工程中的Timer1。 <br>　　方式二：VC中使用sleep()函数实现延时，它的单位是ms，如延时2秒，用sleep(2000)。精度非常<wbr> 低，最小计时精度仅为30ms，用sleep函数的不利处在于延时期间不能处理其他的消息，如果时间太<wbr> 长，就好象死机一样，CPU占用率非常高，只能用于要求不高的延时程序中。如示例工程中的Timer2。<br>　　方式三：利用COleDateTime类和COleDateTimeSpan类结合WINDOWS的消息处理过程来实现秒级延时。如示例工程中的Timer3和Timer3_1。以下是实现2秒的延时代码：<br>COleDateTime&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; start_time = COleDateTime::GetCurrentTime();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COleDateTimeSpan&nbsp; end_time= COleDateTime::GetCurrentTime()-start_time;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(end_time.GetTotalSeconds()&lt; 2) //实现延时2秒<br>&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MSG&nbsp;&nbsp; msg;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetMessage(&amp;msg,NULL,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TranslateMessage(&amp;msg); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DispatchMessage(&amp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //以上四行是实现在延时或定时期间能处理其他的消息，<br>　　　　　　 //虽然这样可以降低CPU的占有率，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //但降低了延时或定时精度，实际应用中可以去掉。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end_time = COleDateTime::GetCurrentTime()-start_time;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }//这样在延时的时候我们也能够处理其他的消息。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>方式四：在精度要求较高的情况下，VC中可以利用GetTickCount()函数，该函数的返回值是<wbr> &nbsp;DWORD型，表示以ms为单位的计算机启动后经历的时间间隔。精度比WM_TIMER消息映射高，在较<wbr> 短的定时中其计时误差为15ms，在较长的定时中其计时误差较低，如果定时时间太长，就好象死机一样，CPU占用率非常高，只能用于要求不高的延时程序中。如示例工程中的Timer4和Timer4_1。下列代码可以实现50ms的精确定时：<br>
<pre>       DWORD dwStart = GetTickCount();
DWORD dwEnd   = dwStart;
do
{
dwEnd = GetTickCount()-dwStart;
}while(dwEnd &lt;50);</pre>
为使GetTickCount()函数在延时或定时期间能处理其他的消息，可以把代码改为：<br>
<pre>       DWORD dwStart = GetTickCount();
DWORD dwEnd   = dwStart;
do
{
MSG   msg;
GetMessage(&amp;msg,NULL,0,0);
TranslateMessage(&amp;msg);
DispatchMessage(&amp;msg);
dwEnd = GetTickCount()-dwStart;
}while(dwEnd &lt;50);</pre>
虽然这样可以降低CPU的占有率，并在延时或定时期间也能处理其他的消息，但降低了延时或定时精度。<br>　　方式五：与GetTickCount()函数类似的多媒体定时器函数DWORD timeGetTime(void)，该函数定时精<wbr> 度为ms级，返回从Windows启动开始经过的毫秒数。微软公司在其多媒体Windows中提供了精确定时器的底<wbr> 层API持，利用多媒体定时器可以很精确地读出系统的当前时间，并且能在非常精确的时间间隔内完成一<wbr> 个事件、函数或过程的调用。不同之处在于调用DWORD timeGetTime(void) 函数之前必须将 Winmm.lib&nbsp;<wbr> 和 Mmsystem.h 添加到工程中，否则在编译时提示DWORD timeGetTime(void)函数未定义。由于使用该<wbr> 函数是通过查询的方式进行定时控制的，所以，应该建立定时循环来进行定时事件的控制。如示例工程中的Timer5和Timer5_1。<br>　　方式六：使用多媒体定时器timeSetEvent()函数，该函数定时精度为ms级。利用该函数可以实现周期性的函数调用。如示例工程中的Timer6和Timer6_1。函数的原型如下： <br>
<pre>       MMRESULT timeSetEvent（ UINT uDelay,
UINT uResolution,
LPTIMECALLBACK lpTimeProc,
WORD dwUser,
UINT fuEvent ）</pre>
　　该函数设置一个定时回调事件，此事件可以是一个一次性事件或周期性事件。事件一旦被激活，便调用指定的回调函数，<wbr> 成功后返回事件的标识符代码，否则返回NULL。函数的参数说明如下：<br>
<pre>       uDelay：以毫秒指定事件的周期。
Uresolution：以毫秒指定延时的精度，数值越小定时器事件分辨率越高。缺省值为1ms。
LpTimeProc：指向一个回调函数。
DwUser：存放用户提供的回调数据。
FuEvent：指定定时器事件类型：
TIME_ONESHOT：uDelay毫秒后只产生一次事件
TIME_PERIODIC ：每隔uDelay毫秒周期性地产生事件。      </pre>
　　具体应用时，可以通过调用timeSetEvent()函数，将需要周期性执行的任务定义在LpTimeProc回调函数<wbr> 中(如：定时采样、控制等)，从而完成所需处理的事件。需要注意的是，任务处理的时间不能大于周期间隔时间。另外，在定时器使用完毕后，<wbr> 应及时调用timeKillEvent()将之释放。 <br>　　方式七：对于精确度要求更高的定时操作，则应该使用QueryPerformanceFrequency()和<wbr> QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows 95及其后续版本使用的精确时间函数，并要求计算机从硬件上支持精确定时器。如示例工程中的Timer7、Timer7_1、Timer7_2、Timer7_3。<br>QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下：<br>
<pre>       BOOL  QueryPerformanceFrequency(LARGE_INTEGER ＊lpFrequency);
BOOL  QueryPerformanceCounter(LARGE_INTEGER ＊lpCount);</pre>
　　数据类型ARGE_INTEGER既可以是一个8字节长的整型数，也可以是两个4字节长的整型数的联合结构，<wbr> 其具体用法根据编译器是否支持64位而定。该类型的定义如下：<br>
<pre>       typedef union _LARGE_INTEGER
{
struct
{
DWORD LowPart ;// 4字节整型数
LONG  HighPart;// 4字节整型数
};
LONGLONG QuadPart ;// 8字节整型数
}LARGE_INTEGER ;</pre>
　　在进行定时之前，先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率，<wbr> 然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数，利用两次获得的计数之差及时钟频率，计算出事件经<wbr> 历的精确时间。下列代码实现1ms的精确定时：<br>
<pre>       LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&amp;litmp);
dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
QueryPerformanceCounter(&amp;litmp);
QPart1 = litmp.QuadPart;// 获得初始值
do
{
QueryPerformanceCounter(&amp;litmp);
QPart2 = litmp.QuadPart;//获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 获得对应的时间值，单位为秒
}while(dfTim&lt;0.001);</pre>
　　其定时误差不超过1微秒，精度与CPU等机器配置有关。 下面的程序用来测试函数Sleep(100)的精确持续时间：<br>
<pre>       LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&amp;litmp);
dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
QueryPerformanceCounter(&amp;litmp);
QPart1 = litmp.QuadPart;// 获得初始值
Sleep(100);
QueryPerformanceCounter(&amp;litmp);
QPart2 = litmp.QuadPart;//获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 获得对应的时间值，单位为秒     </pre>
　　由于Sleep()函数自身的误差，上述程序每次执行的结果都会有微小误差。下列代码实现1微秒的精确定时：<br>
<pre>       LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&amp;litmp);
dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
QueryPerformanceCounter(&amp;litmp);
QPart1 = litmp.QuadPart;// 获得初始值
do
{
QueryPerformanceCounter(&amp;litmp);
QPart2 = litmp.QuadPart;//获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq;// 获得对应的时间值，单位为秒
}while(dfTim&lt;0.000001);</pre>
其定时误差一般不超过0.5微秒，精度与CPU等机器配置有关。
<img src ="http://www.cppblog.com/xushaohua/aggbug/37817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2007-12-04 20:56 <a href="http://www.cppblog.com/xushaohua/archive/2007/12/04/37817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于 Visual C++6.0 的 DLL 编程实现</title><link>http://www.cppblog.com/xushaohua/archive/2007/12/04/37783.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Tue, 04 Dec 2007 05:44:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2007/12/04/37783.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/37783.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2007/12/04/37783.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/37783.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/37783.html</trackback:ping><description><![CDATA[<p align=left><strong><span><font color=#f70938>一、前言</font> </span></strong><span><br><br></span><font color=#f70938><span>　　自从微软推出</span> <span>16</span> <span>位的</span> <span>Windows</span> <span>操作系统起，此后每种版本的</span> <span>Windows</span> <span>操作系统都非常依赖于动态链接库</span> <span>(DLL)</span> <span>中的函数和数据，实际上</span> <span>Windows</span> <span>操作系统中几乎所有的内容都由</span> <span>DLL</span> <span>以一种或另外一种形式代表着，例如显示的字体和图标存储在</span> <span>GDI DLL</span> <span>中、显示</span> <span>Windows</span> <span>桌面和处理用户的输入所需要的代码被存储在一个</span> <span>User DLL</span> <span>中、</span> <span>Windows</span> <span>编程所需要的大量的</span> <span>API</span> <span>函数也被包含在</span> <span>Kernel DLL</span> <span>中。</span> </font><span><br><br></span><font color=#f70938><span>　　在</span> <span>Windows</span> <span>操作系统中使用</span> <span>DLL</span> <span>有很多优点，最主要的一点是多个应用程序、甚至是不同语言编写的应用程序可以共享一个</span> <span>DLL</span> <span>文件，真正实现了资源</span> <span>"</span> <span>共享</span> <span>"</span> <span>，大大缩小了应用程序的执行代码，更加有效的利用了内存；使用</span> <span>DLL</span> <span>的另一个优点是</span> <span>DLL</span> <span>文件作为一个单独的程序模块，封装性、独立性好，在软件需要升级的时候，开发人员只需要修改相应的</span> <span>DLL</span> <span>文件就可以了，而且，当</span> <span>DLL</span> <span>中的函数改变后，只要不是参数的改变</span> <span>,</span> <span>程序代码并不需要重新编译。这在编程时十分有用，大大提高了软件开发和维护的效率。</span> </font><span><br><br></span><font color=#f70938><span>　　既然</span> <span>DLL</span> <span>那么重要，所以搞清楚什么是</span> <span>DLL</span> <span>、如何在</span> <span>Windows</span> <span>操作系统中开发使用</span> <span>DLL</span> <span>是程序开发人员不得不解决的一个问题。本文针对这些问题，通过一个简单的例子，即在一个</span> <span>DLL</span> <span>中实现比较最大、最小整数这两个简单函数，全面地解析了在</span> <span>Visual C++</span> <span>编译环境下编程实现</span> <span>DLL</span> <span>的过程，文章中所用到的程序代码在</span> <span>Windows98</span> <span>系统、</span> <span>Visual C++6.0</span> <span>编译环境下通过。</span> </font><span><br><br></span><font color=#f70938><span>　　<strong>二、</strong></span> <strong><span>DLL</span> </strong><strong><span>的概念</span> </strong></font><span><br><br></span><font color=#f70938><span>　　</span> <span>DLL</span> <span>是建立在客户</span> <span>/</span> <span>服务器通信的概念上，包含若干函数、类或资源的库文件，函数和数据被存储在一个</span> <span>DLL</span> <span>（服务器）上并由一个或多个客户导出而使用，这些客户可以是应用程序或者是其它的</span> <span>DLL</span> <span>。</span> <span>DLL</span> <span>库不同于静态库，在静态库情况下，函数和数据被编译进一个二进制文件（通常扩展名为</span> <span>*.LIB</span> <span>），</span> <span>Visual C++</span> <span>的编译器在处理程序代码时将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为</span> <span>"</span> <span>静态链接</span> <span>"</span> <span>，此时因为应用程序所需的全部内容都是从库中复制了出来，所以静态库本身并不需要与可执行文件一起发行。</span> </font><span><br><br></span><font color=#f70938><span>　　在动态库的情况下，有两个文件，一个是引入库（</span> <span>.LIB</span> <span>）文件，一个是</span> <span>DLL</span> <span>文件，引入库文件包含被</span> <span>DLL</span> <span>导出的函数的名称和位置，</span> <span>DLL</span> <span>包含实际的函数和数据，应用程序使用</span> <span>LIB</span> <span>文件链接到所需要使用的</span> <span>DLL</span> <span>文件，库中的函数和数据并不复制到可执行文件中，因此在应用程序的可执行文件中，存放的不是被调用的函数代码，而是</span> <span>DLL</span> <span>中所要调用的函数的内存地址，这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来，从而节省了内存资源。从上面的说明可以看出，</span> <span>DLL</span> <span>和</span> <span>.LIB</span> <span>文件必须随应用程序一起发行，否则应用程序将会产生错误。</span> </font><span><br><br></span><font color=#f70938><span>　　微软的</span> <span>Visual C++</span> <span>支持三种</span> <span>DLL</span> <span>，它们分别是</span> <span>Non-MFC Dll</span> <span>（非</span> <span>MFC</span> <span>动态库）、</span> <span>Regular Dll</span> <span>（常规</span> <span>DLL</span> <span>）、</span> <span>Extension Dll</span> <span>（扩展</span> <span>DLL</span> <span>）。</span> <span>Non-MFC DLL</span> <span>指的是不用</span> <span>MFC</span> <span>的类库结构，直接用</span> <span>C</span> <span>语言写的</span> <span>DLL</span> <span>，其导出的函数是标准的</span> <span>C</span> <span>接口，能被非</span> <span>MFC</span> <span>或</span> <span>MFC</span> <span>编写的应用程序所调用。</span> <span>Regular DLL:</span> <span>和下述的</span> <span>Extension Dlls</span> <span>一样，是用</span> <span>MFC</span> <span>类库编写的，它的一个明显的特点是在源文件里有一个继承</span> <span>CWinApp</span> <span>的类（注意：此类</span> <span>DLL</span> <span>虽然从</span> <span>CWinApp</span> <span>派生，但没有消息循环）</span> <span>,</span> <span>被导出的函数是</span> <span>C</span> <span>函数、</span> <span>C++</span> <span>类或者</span> <span>C++</span> <span>成员函数（注意不要把术语</span> <span>C++</span> <span>类与</span> <span>MFC</span> <span>的微软基础</span> <span>C++</span> <span>类相混淆），调用常规</span> <span>DLL</span> <span>的应用程序不必是</span> <span>MFC</span> <span>应用程序，只要是能调用类</span> <span>C</span> <span>函数的应用程序就可以，它们可以是在</span> <span>Visual C++</span> <span>、</span> <span>Dephi</span> <span>、</span> <span>Visual Basic</span> <span>、</span> <span>Borland C</span> <span>等编译环境下利用</span> <span>DLL</span> <span>开发应用程序。</span> </font><span><br><br></span><font color=#f70938><span>　　常规</span> <span>DLL</span> <span>又可细分成静态链接到</span> <span>MFC</span> <span>和动态链接到</span> <span>MFC</span> <span>上的，这两种常规</span> <span>DLL</span> <span>的区别将在下面介绍。与常规</span> <span>DLL</span> <span>相比，使用扩展</span> <span>DLL</span> <span>用于导出增强</span> <span>MFC</span> <span>基础类的函数或子类，用这种类型的动态链接库，可以用来输出一个从</span> <span>MFC</span> <span>所继承下来的类。</span> </font><span><br><br></span><font color=#f70938><span>　　扩展</span> <span>DLL</span> <span>是使用</span> <span>MFC</span> <span>的动态链接版本所创建的，并且它只被用</span> <span>MFC</span> <span>类库所编写的应用程序所调用。例如你已经创建了一个从</span> <span>MFC</span> <span>的</span> <span>CtoolBar</span> <span>类的派生类用于创建一个新的工具栏，为了导出这个类，你必须把它放到一个</span> <span>MFC</span> <span>扩展的</span> <span>DLL</span> <span>中。扩展</span> <span>DLL </span><span>和常规</span> <span>DLL</span> <span>不一样，它没有一个从</span> <span>CWinApp</span> <span>继承而来的类的对象，所以，开发人员必须在</span> <span>DLL</span> <span>中的</span> <span>DllMain</span> <span>函数添加初始化代码和结束代码。</span> </font></p>
<p align=left><strong><span><font color=#f70938>三、动态链接库的创建</font> </span></strong><span><br><br></span><font color=#f70938><span>　　在</span> <span>Visual C++6.0</span> <span>开发环境下，打开</span> <span>FileNewProject</span> <span>选项，可以选择</span> <span>Win32 Dynamic-Link Library</span> <span>或</span> <span>MFC AppWizard[dll]</span> <span>来以不同的方式来创建</span> <span>Non-MFC Dll</span> <span>、</span> <span>Regular Dll</span> <span>、</span> <span>Extension Dll</span> <span>等不同种类的动态链接库。</span> </font><span><br><br></span><font color=#f70938><span>　　</span> <span>1</span> <span>．</span> <span>Win32 Dynamic-Link Library</span> <span>方式创建</span> <span>Non-MFC DLL</span> <span>动态链接库</span> </font><span><br><br></span><font color=#f70938><span>　　每一个</span> <span>DLL</span> <span>必须有一个入口点，这就象我们用</span> <span>C</span> <span>编写的应用程序一样，必须有一个</span> <span>WINMAIN</span> <span>函数一样。在</span> <span>Non-MFC DLL</span> <span>中</span> <span>DllMain</span> <span>是一个缺省的入口函数，你不需要编写自己的</span> <span>DLL</span> <span>入口函数，用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果应用程序的</span> <span>DLL</span> <span>需要分配额外的内存或资源时，或者说需要对每个进程或线程初始化和清除操作时，需要在相应的</span> <span>DLL</span> <span>工程的</span> <span>.CPP</span> <span>文件中对</span> <span>DllMain()</span> <span>函数按照下面的格式书写。</span> </font><span><br></span><span><font color=#f70938>　</font> </span></p>
<p align=left><span><font color=#f70938>　</font> </span></p>
<table cellPadding=0 width="100%" border=0 FCK__ShowTableBorders?>
    <tbody>
        <tr>
            <td>
            <p align=left><span><font color=#f70938>BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)<br>{<br>switch( ul_reason_for_call )<br>{<br>case DLL_PROCESS_ATTACH:<br>.......<br>case DLL_THREAD_ATTACH:<br>.......<br>case DLL_THREAD_DETACH:<br>.......<br>case DLL_PROCESS_DETACH:<br>.......<br>}<br>return TRUE;<br>}</font> </span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><font color=#f70938><span>　　参数中，</span> <span>hMoudle</span> <span>是动态库被调用时所传递来的一个指向自己的句柄</span> <span>(</span> <span>实际上，它是指向</span> <span>_DGROUP</span> <span>段的一个选择符</span> <span>)</span> <span>；</span> <span>ul_reason_for_call</span> <span>是一个说明动态库被调原因的标志，当进程或线程装入或卸载动态链接库的时候，操作系统调用入口函数，并说明动态链接库被调用的原因，它所有的可能值为：</span> <span>DLL_PROCESS_ATTACH: </span><span>进程被调用、</span> <span>DLL_THREAD_ATTACH: </span><span>线程被调用、</span> <span>DLL_PROCESS_DETACH: </span><span>进程被停止、</span> <span>DLL_THREAD_DETACH: </span><span>线程被停止；</span> <span>lpReserved</span> <span>为保留参数。到此为止，</span> <span>DLL</span> <span>的入口函数已经写了，剩下部分的实现也不难，你可以在</span> <span>DLL</span> <span>工程中加入你所想要输出的函数或变量了。</span> </font><span><br><br></span><font color=#f70938><span>　　我们已经知道</span> <span>DLL</span> <span>是包含若干个函数的库文件，应用程序使用</span> <span>DLL</span> <span>中的函数之前，应该先导出这些函数，以便供给应用程序使用。要导出这些函数有两种方法，一是在定义函数时使用导出关键字</span> <span>_declspec(dllexport)</span> <span>，另外一种方法是在创建</span> <span>DLL</span> <span>文件时使用模块定义文件</span> <span>.Def</span> <span>。需要读者注意的是在使用第一种方法的时候，不能使用</span> <span>DEF</span> <span>文件。下面通过两个例子来说明如何使用这两种方法创建</span> <span>DLL</span> <span>文件。</span> </font><span><br><br></span><font color=#f70938><span>　　</span> <span>1</span> <span>）使用导出函数关键字</span> <span>_declspec(dllexport)</span> <span>创建</span> <span>MyDll.dll</span> <span>，该动态链接库中有两个函数，分别用来实现得到两个数的最大和最小数。在</span> <span>MyDll.h</span> <span>和</span> <span>MyDLL.cpp</span> <span>文件中分别输入如下原代码：</span> </font><span><br></span><span><font color=#f70938>　</font> </span></p>
<table cellPadding=0 width="100%" border=0 FCK__ShowTableBorders?>
    <tbody>
        <tr>
            <td>
            <p align=left><span><font color=#f70938>//MyDLL.h<br>extern "C" _declspec(dllexport) int Max(int a, int b);<br>extern "C" _declspec(dllexport) int Min(int a, int b);<br>//MyDll.cpp<br>＃i nclude<br>＃i nclude"MyDll.h"<br>int Max(int a, int b)<br>{<br>if(a&gt;=b)return a;<br>else<br>return b;<br>}<br>int Min(int a, int b)<br>{<br>if(a&gt;=b)return b;<br>else<br>return a;<br>}</font> </span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><font color=#f70938><span>　　该动态链接库编译成功后，打开</span> <span>MyDll</span> <span>工程中的</span> <span>debug</span> <span>目录，可以看到</span> <span>MyDll.dll</span> <span>、</span> <span>MyDll.lib</span> <span>两个文件。</span> <span>LIB</span> <span>文件中包含</span> <span>DLL</span> <span>文件名和</span> <span>DLL</span> <span>文件中的函数名等，该</span> <span>LIB</span> <span>文件只是对应该</span> <span>DLL</span> <span>文件的</span> <span>"</span> <span>映像文件</span> <span>"</span> <span>，与</span> <span>DLL</span> <span>文件中，</span> <span>LIB</span> <span>文件的长度要小的多，在进行隐式链接</span> <span>DLL</span> <span>时要用到它。读者可能已经注意到在</span> <span>MyDll.h</span> <span>中有关键字</span> <span>"extern C"</span> <span>，它可以使其他编程语言访问你编写的</span> <span>DLL</span> <span>中的函数。</span> </font><span><br><br></span><font color=#f70938><span>　　</span> <span>2</span> <span>）用</span> <span>.def</span> <span>文件创建工程</span> </font><font color=#f70938><span>MyDll<br><br></span><span>　　为了用</span> <span>.def</span> <span>文件创建</span> <span>DLL</span> <span>，请先删除上个例子创建的工程中的</span> <span>MyDll.h</span> <span>文件，保留</span> <span>MyDll.cpp</span> <span>并在该文件头删除</span> <span>＃i nclude MyDll.h</span> <span>语句，同时往该工程中加入一个文本文件，命名为</span> <span>MyDll.def</span> <span>，再在该文件中加入如下代码：</span> </font><span><br><br><font color=#f70938>LIBRARY MyDll<br>EXPORTS<br>Max<br>Min<br><br></font></span><font color=#f70938><span>　　其中</span> <span>LIBRARY</span> <span>语句说明该</span> <span>def</span> <span>文件是属于相应</span> <span>DLL</span> <span>的，</span> <span>EXPORTS</span> <span>语句下列出要导出的函数名称。我们可以在</span> <span>.def</span> <span>文件中的导出函数后加</span> <span>@n</span> <span>，如</span> <span>Max@1</span> <span>，</span> <span>Min@2</span> <span>，表示要导出的函数顺序号，在进行显式连时可以用到它。该</span> <span>DLL</span> <span>编译成功后，打开工程中的</span> <span>Debug</span> <span>目录，同样也会看到</span> <span>MyDll.dll</span> <span>和</span> <span>MyDll.lib</span> <span>文件。</span> </font><span><br><br></span><font color=#f70938><span>　　</span> <span>2</span> <span>．</span> <span>MFC AppWizard[dll]</span> <span>方式生成常规</span> <span>/</span> <span>扩展</span> </font><font color=#f70938><span>DLL<br><br></span><span>　　在</span> <span>MFC AppWizard[dll]</span> <span>下生成</span> <span>DLL</span> <span>文件又有三种方式，在创建</span> <span>DLL</span> <span>是，要根据实际情况选择创建</span> <span>DLL</span> <span>的方式。一种是常规</span> <span>DLL</span> <span>静态链接到</span> <span>MFC</span> <span>，另一种是常规</span> <span>DLL</span> <span>动态链接到</span> <span>MFC</span> <span>。两者的区别是：前者使用的是</span> <span>MFC</span> <span>的静态链接库，生成的</span> <span>DLL</span> <span>文件长度大，一般不使用这种方式，后者使用</span> <span>MFC</span> <span>的动态链接库，生成的</span> <span>DLL</span> <span>文件长度小；动态链接到</span> <span>MFC</span> <span>的规则</span> <span>DLL</span> <span>所有输出的函数应该以如下语句开始：</span> </font><font color=#f70938><span><br></span><span>　</span> </font></p>
<table cellPadding=0 width="100%" border=0 FCK__ShowTableBorders?>
    <tbody>
        <tr>
            <td>
            <p align=left><font color=#f70938><span>AFX_MANAGE_STATE(AfxGetStaticModuleState( )) //</span> <span>此语句用来正确地切换</span> <span>MFC</span> <span>模块状态</span> </font></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><font color=#f70938><span>　　最后一种是</span> <span>MFC</span> <span>扩展</span> <span>DLL</span> <span>，这种</span> <span>DLL</span> <span>特点是用来建立</span> <span>MFC</span> <span>的派生类，</span> <span>Dll</span> <span>只被用</span> <span>MFC</span> <span>类库所编写的应用程序所调用。前面我们已经介绍过，</span> <span>Extension DLLs </span><span>和</span> <span>Regular DLLs</span> <span>不一样，它没有一个从</span> <span>CWinApp</span> <span>继承而来的类的对象，编译器默认了一个</span> <span>DLL</span> <span>入口函数</span> <span>DLLMain()</span> <span>作为对</span> <span>DLL</span> <span>的初始化，你可以在此函数中实现初始化</span> <span>,</span> <span>代码如下：</span> </font><span><br></span><span><font color=#f70938>　</font> </span></p>
<table cellPadding=0 width="100%" border=0 FCK__ShowTableBorders?>
    <tbody>
        <tr>
            <td>
            <p align=left><font color=#f70938><span>BOOL WINAPI APIENTRY DLLMain(HINSTANCE hinstDll</span> <span>，</span> <span>DWORD reason </span><span>，</span> </font><font color=#f70938><span>LPVOID flmpload)<br>{<br>switch(reason)<br>{<br>&#8230;&#8230;&#8230;&#8230;&#8230;//</span> <span>初始化代码；</span> </font><span><br><font color=#f70938>}<br>return true;<br>}</font> </span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><font color=#f70938><span>　　参数</span> <span>hinstDll</span> <span>存放</span> <span>DLL</span> <span>的句柄，参数</span> <span>reason</span> <span>指明调用函数的原因，</span> <span>lpReserved</span> <span>是一个被系统所保留的参数。对于隐式链接是一个非零值，对于显式链接值是零。</span> </font><span><br><br></span><font color=#f70938><span>　　在</span> <span>MFC</span> <span>下建立</span> <span>DLL</span> <span>文件，会自动生成</span> <span>def</span> <span>文件框架，其它与建立传统的</span> <span>Non-MFC DLL</span> <span>没有什么区别，只要在相应的头文件写入关键字</span> <span>_declspec(dllexport)</span> <span>函数类型和函数名等，或在生成的</span> <span>def</span> <span>文件中</span> <span>EXPORTS</span> <span>下输入函数名就可以了。需要注意的是在向其它开发人员分发</span> <span>MFC</span> <span>扩展</span> <span>DLL </span><span>时，不要忘记提供描述</span> <span>DLL</span> <span>中类的头文件以及相应的</span> <span>.LIB</span> <span>文件和</span> <span>DLL</span> <span>本身，此后开发人员就能充分利用你开发的扩展</span> <span>DLL</span> <span>了。<br><br>　应用程序使用<span>DLL</span><span>可以采用两种方式：一种是隐式链接，另一种是显式链接。在使用</span><span>DLL</span><span>之前首先要知道</span><span>DLL</span><span>中函数的结构信息。</span><span>Visual C++6.0</span><span>在</span><span>VCin</span><span>目录下提供了一个名为</span><span>Dumpbin.exe</span><span>的小程序，用它可以查看</span><span>DLL</span><span>文件中的函数结构。另外，</span><span>Windows</span><span>系统将遵循下面的搜索顺序来定位</span><span>DLL</span><span>：</span><span> 1</span><span>．包含</span><span>EXE</span><span>文件的目录，</span><span>2</span><span>．进程的当前工作目录，</span><span> 3</span><span>．</span><span>Windows</span><span>系统目录，</span><span> 4</span><span>．</span><span>Windows</span><span>目录，</span><span>5</span><span>．列在</span><span>Path</span><span>环境变量中的一系列目录。</span><span><br><br></span><span>　　</span><span>1</span><span>．隐式链接</span><span><br><br></span><span>　　隐式链接就是在程序开始执行时就将</span><span>DLL</span><span>文件加载到应用程序当中。实现隐式链接很容易，只要将导入函数关键字</span><span>_declspec(dllimport)</span><span>函数名等写到应用程序相应的头文件中就可以了。下面的例子通过隐式链接调用</span><span>MyDll.dll</span><span>库中的</span><span>Min</span><span>函数。首先生成一个项目为</span><span>TestDll</span><span>，在</span><span>DllTest.h</span><span>、</span><span>DllTest.cpp</span><span>文件中分别输入如下代码：</span><span><br></span><span>　</span></span> </font></p>
<p align=left><span>　</span> </p>
<p align=left>&nbsp;</p>
<table cellPadding=0 width="100%" border=0 FCK__ShowTableBorders?>
    <tbody>
        <tr>
            <td>
            <p align=left><span>//Dlltest.h<br>#pragma comment(lib</span> <span>，</span> <span>"MyDll.lib")<br>extern "C"_declspec(dllimport) int Max(int a,int b);<br>extern "C"_declspec(dllimport) int Min(int a,int b);<br>//TestDll.cpp<br>＃i nclude<br>＃i nclude"Dlltest.h"<br>void main()<br>{int a;<br>a=min(8,10)<br>printf("</span> <span>比较的结果为</span> <span>%d "</span> <span>，</span> <span>a);<br>}<br></span><span>　</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><span>　　在创建</span> <span>DllTest.exe</span> <span>文件之前，要先将</span> <span>MyDll.dll</span> <span>和</span> <span>MyDll.lib</span> <span>拷贝到当前工程所在的目录下面，也可以拷贝到</span> <span>windows</span> <span>的</span> <span>System</span> <span>目录下。如果</span> <span>DLL</span> <span>使用的是</span> <span>def</span> <span>文件，要删除</span> <span>TestDll.h</span> <span>文件中关键字</span> <span>extern "C"</span> <span>。</span> <span>TestDll.h</span> <span>文件中的关键字</span> <span>Progam commit</span> <span>是要</span> <span>Visual C+</span> <span>的编译器在</span> <span>link</span> <span>时，链接到</span> <span>MyDll.lib</span> <span>文件，当然，开发人员也可以不使用</span> <span>#pragma comment(lib</span> <span>，</span> <span>"MyDll.lib")</span> <span>语句，而直接在工程的</span> <span>Setting-&gt;Link</span> <span>页的</span> <span>Object/Moduls</span> <span>栏填入</span> <span>MyDll.lib</span> <span>既可。</span> <span><br><br></span><span>　　</span> <span>2</span> <span>．显式链接</span> <span><br><br></span><span>　　显式链接是应用程序在执行过程中随时可以加载</span> <span>DLL</span> <span>文件，也可以随时卸载</span> <span>DLL</span> <span>文件，这是隐式链接所无法作到的，所以显式链接具有更好的灵活性，对于解释性语言更为合适。不过实现显式链接要麻烦一些。在应用程序中用</span> <span>LoadLibrary</span> <span>或</span> <span>MFC</span> <span>提供的</span> <span>AfxLoadLibrary</span> <span>显式的将自己所做的动态链接库调进来，动态链接库的文件名即是上述两个函数的参数，此后再用</span> <span>GetProcAddress()</span> <span>获取想要引入的函数。自此，你就可以象使用如同在应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前，应该用</span> <span>FreeLibrary</span> <span>或</span> <span>MFC</span> <span>提供的</span> <span>AfxFreeLibrary</span> <span>释放动态链接库。下面是通过显式链接调用</span> <span>DLL</span> <span>中的</span> <span>Max</span> <span>函数的例子。</span> <span><br></span><span>　</span> </p>
<p align=left>&nbsp;</p>
<table cellPadding=0 width="100%" border=0 FCK__ShowTableBorders?>
    <tbody>
        <tr>
            <td>
            <p align=left><span>＃i nclude <br>＃i nclude<br>void main(void)<br>{<br>typedef int(*pMax)(int a,int b);<br>typedef int(*pMin)(int a,int b);<br>HINSTANCE hDLL;<br>PMax Max<br>HDLL=LoadLibrary("MyDll.dll");//</span> <span>加载动态链接库</span> <span>MyDll.dll</span> <span>文件；</span> <span><br>Max=(pMax)GetProcAddress(hDLL,"Max");<br>A=Max(5,8);<br>Printf("</span> <span>比较的结果为</span> <span>%d "</span> <span>，</span> <span>a);<br>FreeLibrary(hDLL);//</span> <span>卸载</span> <span>MyDll.dll</span> <span>文件；</span> <span><br>}</span> </p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><span>　　在上例中使用类型定义关键字</span> <span>typedef</span> <span>，定义指向和</span> <span>DLL</span> <span>中相同的函数原型指针，然后通过</span> <span>LoadLibray()</span> <span>将</span> <span>DLL</span> <span>加载到当前的应用程序中并返回当前</span> <span>DLL</span> <span>文件的句柄，然后通过</span> <span>GetProcAddress()</span> <span>函数获取导入到应用程序中的函数指针，函数调用完毕后，使用</span> <span>FreeLibrary()</span> <span>卸载</span> <span>DLL</span> <span>文件。在编译程序之前，首先要将</span> <span>DLL</span> <span>文件拷贝到工程所在的目录或</span> <span>Windows</span> <span>系统目录下。</span> <span><br><br></span><span>　　使用显式链接应用程序编译时不需要使用相应的</span> <span>Lib</span> <span>文件。另外，使用</span> <span>GetProcAddress()</span> <span>函数时，可以利用</span> <span>MAKEINTRESOURCE()</span> <span>函数直接使用</span> <span>DLL</span> <span>中函数出现的顺序号，如将</span> <span>GetProcAddress(hDLL,"Min")</span> <span>改为</span> <span>GetProcAddress(hDLL, MAKEINTRESOURCE(2))</span> <span>（函数</span> <span>Min()</span> <span>在</span> <span>DLL</span> <span>中的顺序号是</span> <span>2</span> <span>），这样调用</span> <span>DLL</span> <span>中的函数速度很快，但是要记住函数的使用序号，否则会发生错误。</span>&nbsp;</p>
<img src ="http://www.cppblog.com/xushaohua/aggbug/37783.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2007-12-04 13:44 <a href="http://www.cppblog.com/xushaohua/archive/2007/12/04/37783.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[后记]大瓶子与小瓶子的问题 </title><link>http://www.cppblog.com/xushaohua/archive/2006/11/15/15181.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Wed, 15 Nov 2006 06:09:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/15/15181.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/15181.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/15/15181.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/15181.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/15181.html</trackback:ping><description><![CDATA[以下是用C#语言对问题的描述<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> System;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> Client<br /><img id="Codehighlighter1_28_142_Open_Image" onclick="this.style.display='none'; Codehighlighter1_28_142_Open_Text.style.display='none'; Codehighlighter1_28_142_Closed_Image.style.display='inline'; Codehighlighter1_28_142_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_28_142_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_28_142_Closed_Text.style.display='none'; Codehighlighter1_28_142_Open_Image.style.display='inline'; Codehighlighter1_28_142_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_28_142_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_28_142_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Main ()<br /><img id="Codehighlighter1_63_140_Open_Image" onclick="this.style.display='none'; Codehighlighter1_63_140_Open_Text.style.display='none'; Codehighlighter1_63_140_Closed_Image.style.display='inline'; Codehighlighter1_63_140_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_63_140_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_63_140_Closed_Text.style.display='none'; Codehighlighter1_63_140_Open_Image.style.display='inline'; Codehighlighter1_63_140_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />   </span><span id="Codehighlighter1_63_140_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_63_140_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      A a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> A();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      B b </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> B();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      a.b </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> b;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />      b.a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> a;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />   }</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A<br /><img id="Codehighlighter1_153_170_Open_Image" onclick="this.style.display='none'; Codehighlighter1_153_170_Open_Text.style.display='none'; Codehighlighter1_153_170_Closed_Image.style.display='inline'; Codehighlighter1_153_170_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_153_170_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_153_170_Closed_Text.style.display='none'; Codehighlighter1_153_170_Open_Image.style.display='inline'; Codehighlighter1_153_170_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_153_170_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_153_170_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> B b;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> B<br /><img id="Codehighlighter1_181_199_Open_Image" onclick="this.style.display='none'; Codehighlighter1_181_199_Open_Text.style.display='none'; Codehighlighter1_181_199_Closed_Image.style.display='inline'; Codehighlighter1_181_199_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_181_199_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_181_199_Closed_Text.style.display='none'; Codehighlighter1_181_199_Open_Image.style.display='inline'; Codehighlighter1_181_199_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_181_199_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_181_199_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />   </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> A a; <br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>为什么这里不用像C++语言描述那样要做一些处理,而且没有报错呢?<br />系统运行后，内存结构如下：<br /><br /><img height="351" src="http://www.cnblogs.com/images/cnblogs_com/zhenyulu/Pic27.gif" width="528" border="0" /><br />与C++语言有不同的是,在C#语言中,class这种自定义的数据类型属于引用类型,所以在声名的时候是一种引用而已.由于是引用，所以也无所谓大瓶子还是小瓶子了。<img src ="http://www.cppblog.com/xushaohua/aggbug/15181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-15 14:09 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/15/15181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大瓶子与小瓶子的问题</title><link>http://www.cppblog.com/xushaohua/archive/2006/11/15/15179.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Wed, 15 Nov 2006 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/15/15179.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/15179.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/15/15179.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/15179.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/15179.html</trackback:ping><description><![CDATA[
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> B;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> A<br /><img id="Codehighlighter1_18_55_Open_Image" onclick="this.style.display='none'; Codehighlighter1_18_55_Open_Text.style.display='none'; Codehighlighter1_18_55_Closed_Image.style.display='inline'; Codehighlighter1_18_55_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_18_55_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_18_55_Closed_Text.style.display='none'; Codehighlighter1_18_55_Open_Image.style.display='inline'; Codehighlighter1_18_55_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_18_55_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_18_55_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    A(</span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #000000">~</span>
						<span style="COLOR: #000000">A(</span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    B b;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />A::A(</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_70_72_Open_Image" onclick="this.style.display='none'; Codehighlighter1_70_72_Open_Text.style.display='none'; Codehighlighter1_70_72_Closed_Image.style.display='inline'; Codehighlighter1_70_72_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_70_72_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_70_72_Closed_Text.style.display='none'; Codehighlighter1_70_72_Open_Image.style.display='inline'; Codehighlighter1_70_72_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_70_72_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_70_72_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />A::</span>
				<span style="COLOR: #000000">~</span>
				<span style="COLOR: #000000">A(</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_87_89_Open_Image" onclick="this.style.display='none'; Codehighlighter1_87_89_Open_Text.style.display='none'; Codehighlighter1_87_89_Closed_Image.style.display='inline'; Codehighlighter1_87_89_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_87_89_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_87_89_Closed_Text.style.display='none'; Codehighlighter1_87_89_Open_Image.style.display='inline'; Codehighlighter1_87_89_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_87_89_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_87_89_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">class</span>
				<span style="COLOR: #000000"> B<br /><img id="Codehighlighter1_100_137_Open_Image" onclick="this.style.display='none'; Codehighlighter1_100_137_Open_Text.style.display='none'; Codehighlighter1_100_137_Closed_Image.style.display='inline'; Codehighlighter1_100_137_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_100_137_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_100_137_Closed_Text.style.display='none'; Codehighlighter1_100_137_Open_Image.style.display='inline'; Codehighlighter1_100_137_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_100_137_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_100_137_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span>
						<span style="COLOR: #0000ff">public</span>
						<span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    B(</span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #000000">~</span>
						<span style="COLOR: #000000">B(</span>
						<span style="COLOR: #0000ff">void</span>
						<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    A a;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />B::B(</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_152_154_Open_Image" onclick="this.style.display='none'; Codehighlighter1_152_154_Open_Text.style.display='none'; Codehighlighter1_152_154_Closed_Image.style.display='inline'; Codehighlighter1_152_154_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_152_154_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_152_154_Closed_Text.style.display='none'; Codehighlighter1_152_154_Open_Image.style.display='inline'; Codehighlighter1_152_154_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_152_154_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_152_154_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />B::</span>
				<span style="COLOR: #000000">~</span>
				<span style="COLOR: #000000">B(</span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000">)<br /><img id="Codehighlighter1_169_171_Open_Image" onclick="this.style.display='none'; Codehighlighter1_169_171_Open_Text.style.display='none'; Codehighlighter1_169_171_Closed_Image.style.display='inline'; Codehighlighter1_169_171_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_169_171_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_169_171_Closed_Text.style.display='none'; Codehighlighter1_169_171_Open_Image.style.display='inline'; Codehighlighter1_169_171_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_169_171_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_169_171_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> main()<br /><img id="Codehighlighter1_185_199_Open_Image" onclick="this.style.display='none'; Codehighlighter1_185_199_Open_Text.style.display='none'; Codehighlighter1_185_199_Closed_Image.style.display='inline'; Codehighlighter1_185_199_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_185_199_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_185_199_Closed_Text.style.display='none'; Codehighlighter1_185_199_Open_Image.style.display='inline'; Codehighlighter1_185_199_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span>
				<span id="Codehighlighter1_185_199_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_185_199_Open_Text">
						<span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>在编译器中编译要报的错误即是:  error C2079: 'A::b' uses undefined class 'B'<br />原因是什么呢?从代码来看,用了类的前视的啊,不应该有什么问题的啊.<br />但因为在分配内存空间的时候,不知道其class B 的大小,所以没有办法为其分配存储空间,随即报出了一个没有定义的错误.<br />其解决的方案有两种,如下事例:<br />方案A:<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> B;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A<br /><img id="Codehighlighter1_18_57_Open_Image" onclick="this.style.display='none'; Codehighlighter1_18_57_Open_Text.style.display='none'; Codehighlighter1_18_57_Closed_Image.style.display='inline'; Codehighlighter1_18_57_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_18_57_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_18_57_Closed_Text.style.display='none'; Codehighlighter1_18_57_Open_Image.style.display='inline'; Codehighlighter1_18_57_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_18_57_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_18_57_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    B b();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />A::A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_72_74_Open_Image" onclick="this.style.display='none'; Codehighlighter1_72_74_Open_Text.style.display='none'; Codehighlighter1_72_74_Closed_Image.style.display='inline'; Codehighlighter1_72_74_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_72_74_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_72_74_Closed_Text.style.display='none'; Codehighlighter1_72_74_Open_Image.style.display='inline'; Codehighlighter1_72_74_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_72_74_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_72_74_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />A::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_89_91_Open_Image" onclick="this.style.display='none'; Codehighlighter1_89_91_Open_Text.style.display='none'; Codehighlighter1_89_91_Closed_Image.style.display='inline'; Codehighlighter1_89_91_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_89_91_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_89_91_Closed_Text.style.display='none'; Codehighlighter1_89_91_Open_Image.style.display='inline'; Codehighlighter1_89_91_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_89_91_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_89_91_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> B<br /><img id="Codehighlighter1_102_141_Open_Image" onclick="this.style.display='none'; Codehighlighter1_102_141_Open_Text.style.display='none'; Codehighlighter1_102_141_Closed_Image.style.display='inline'; Codehighlighter1_102_141_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_102_141_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_102_141_Closed_Text.style.display='none'; Codehighlighter1_102_141_Open_Image.style.display='inline'; Codehighlighter1_102_141_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_102_141_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_102_141_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    A a();<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />B::B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_156_158_Open_Image" onclick="this.style.display='none'; Codehighlighter1_156_158_Open_Text.style.display='none'; Codehighlighter1_156_158_Closed_Image.style.display='inline'; Codehighlighter1_156_158_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_156_158_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_156_158_Closed_Text.style.display='none'; Codehighlighter1_156_158_Open_Image.style.display='inline'; Codehighlighter1_156_158_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_156_158_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_156_158_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />B::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_173_175_Open_Image" onclick="this.style.display='none'; Codehighlighter1_173_175_Open_Text.style.display='none'; Codehighlighter1_173_175_Closed_Image.style.display='inline'; Codehighlighter1_173_175_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_173_175_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_173_175_Closed_Text.style.display='none'; Codehighlighter1_173_175_Open_Image.style.display='inline'; Codehighlighter1_173_175_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_173_175_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_173_175_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main()<br /><img id="Codehighlighter1_189_203_Open_Image" onclick="this.style.display='none'; Codehighlighter1_189_203_Open_Text.style.display='none'; Codehighlighter1_189_203_Closed_Image.style.display='inline'; Codehighlighter1_189_203_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_189_203_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_189_203_Closed_Text.style.display='none'; Codehighlighter1_189_203_Open_Image.style.display='inline'; Codehighlighter1_189_203_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_189_203_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_189_203_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>显示地调用一下其构造函数构造一个具体的实例出来即有了固定的存储空间<br />方案B:<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> B;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A<br /><img id="Codehighlighter1_18_56_Open_Image" onclick="this.style.display='none'; Codehighlighter1_18_56_Open_Text.style.display='none'; Codehighlighter1_18_56_Closed_Image.style.display='inline'; Codehighlighter1_18_56_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_18_56_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_18_56_Closed_Text.style.display='none'; Codehighlighter1_18_56_Open_Image.style.display='inline'; Codehighlighter1_18_56_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_18_56_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_18_56_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    B </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">b;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />A::A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_71_73_Open_Image" onclick="this.style.display='none'; Codehighlighter1_71_73_Open_Text.style.display='none'; Codehighlighter1_71_73_Closed_Image.style.display='inline'; Codehighlighter1_71_73_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_71_73_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_71_73_Closed_Text.style.display='none'; Codehighlighter1_71_73_Open_Image.style.display='inline'; Codehighlighter1_71_73_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_71_73_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_71_73_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />A::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_88_90_Open_Image" onclick="this.style.display='none'; Codehighlighter1_88_90_Open_Text.style.display='none'; Codehighlighter1_88_90_Closed_Image.style.display='inline'; Codehighlighter1_88_90_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_88_90_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_88_90_Closed_Text.style.display='none'; Codehighlighter1_88_90_Open_Image.style.display='inline'; Codehighlighter1_88_90_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_88_90_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_88_90_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> B<br /><img id="Codehighlighter1_101_139_Open_Image" onclick="this.style.display='none'; Codehighlighter1_101_139_Open_Text.style.display='none'; Codehighlighter1_101_139_Closed_Image.style.display='inline'; Codehighlighter1_101_139_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_101_139_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_101_139_Closed_Text.style.display='none'; Codehighlighter1_101_139_Open_Image.style.display='inline'; Codehighlighter1_101_139_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_101_139_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_101_139_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    A </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">a;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />B::B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_154_156_Open_Image" onclick="this.style.display='none'; Codehighlighter1_154_156_Open_Text.style.display='none'; Codehighlighter1_154_156_Closed_Image.style.display='inline'; Codehighlighter1_154_156_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_154_156_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_154_156_Closed_Text.style.display='none'; Codehighlighter1_154_156_Open_Image.style.display='inline'; Codehighlighter1_154_156_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_154_156_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_154_156_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />B::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">B(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /><img id="Codehighlighter1_171_173_Open_Image" onclick="this.style.display='none'; Codehighlighter1_171_173_Open_Text.style.display='none'; Codehighlighter1_171_173_Closed_Image.style.display='inline'; Codehighlighter1_171_173_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_171_173_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_171_173_Closed_Text.style.display='none'; Codehighlighter1_171_173_Open_Image.style.display='inline'; Codehighlighter1_171_173_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_171_173_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_171_173_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main()<br /><img id="Codehighlighter1_187_201_Open_Image" onclick="this.style.display='none'; Codehighlighter1_187_201_Open_Text.style.display='none'; Codehighlighter1_187_201_Closed_Image.style.display='inline'; Codehighlighter1_187_201_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_187_201_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_187_201_Closed_Text.style.display='none'; Codehighlighter1_187_201_Open_Image.style.display='inline'; Codehighlighter1_187_201_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_187_201_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_187_201_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>用指针来存储其一个地址而已,具体的大小等到用的时候再为其实际分配.<img src ="http://www.cppblog.com/xushaohua/aggbug/15179.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-15 14:01 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/15/15179.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C描述MD5算法</title><link>http://www.cppblog.com/xushaohua/archive/2006/11/09/14919.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Thu, 09 Nov 2006 12:54:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/09/14919.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/14919.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/09/14919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/14919.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/14919.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://www.ietf.org/rfc/rfc1321.txt 此为rfc1321.txt   1#include &lt;stdio.h&gt;  2  3typedef struct {  4  5    unsigned int state[4];        6  7    unsigned int count[2];        8  9    unsigned char b...&nbsp;&nbsp;<a href='http://www.cppblog.com/xushaohua/archive/2006/11/09/14919.html'>阅读全文</a><img src ="http://www.cppblog.com/xushaohua/aggbug/14919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-09 20:54 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/09/14919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>初识MD5算法</title><link>http://www.cppblog.com/xushaohua/archive/2006/11/09/14918.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Thu, 09 Nov 2006 12:51:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/09/14918.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/14918.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/09/14918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/14918.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/14918.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: MD5的全称是message-digest algorithm 5（信息-摘要算法），在90年代初由mit laboratory for computer science和rsa data security inc的ronald l. rivest开发出来，经md2、md3和md4发展而来。它的作用是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式（就是把一个任意长度的字节串变...&nbsp;&nbsp;<a href='http://www.cppblog.com/xushaohua/archive/2006/11/09/14918.html'>阅读全文</a><img src ="http://www.cppblog.com/xushaohua/aggbug/14918.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-09 20:51 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/09/14918.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]至C/C++初学者-----------------堆与栈</title><link>http://www.cppblog.com/xushaohua/archive/2006/11/09/14917.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Thu, 09 Nov 2006 12:45:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/09/14917.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/14917.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/09/14917.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/14917.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/14917.html</trackback:ping><description><![CDATA[
		<div>
				<p class="vcerHeading">
						<img src="http://vcer.net/images/item.gif" align="top" />关键词</p>
				<font style="BACKGROUND-COLOR: #ffff00">堆</font> <font style="BACKGROUND-COLOR: #00ffff">栈</font><br /><p class="vcerHeading"><img src="http://vcer.net/images/item.gif" align="top" />摘要</p><br /><p class="vcerHeading"><img src="http://vcer.net/images/item.gif" align="top" />正文</p><div class="vcerParagraph"><p>一、预备知识—程序的内存分配 </p><p>一个由c/C++编译的程序占用的内存分为以下几个部分 </p><p>1、<font style="BACKGROUND-COLOR: #00ffff">栈</font>区（stack）—   由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的<font style="BACKGROUND-COLOR: #00ffff">栈</font>。 </p><p>2、<font style="BACKGROUND-COLOR: #ffff00">堆</font>区（heap） —   一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收 。注意它与数据结构中的<font style="BACKGROUND-COLOR: #ffff00">堆</font>是两回事，分配方式倒是类似于链表，呵呵。 </p><p>3、全局区（静态区）（static）—，全局变量和静态变量的存储是放在一块的，初始化的全局变量和静态变量在一块区域， 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 </p><p>4、文字常量区  —常量字符串就是放在这里的。 程序结束后由系统释放 </p><p>5、程序代码区—存放函数体的二进制代码。 </p><p>二、例子程序 </p><p>这是一个前辈写的，非常详细 </p><p>//main.cpp </p><p>int a = 0; 全局初始化区 </p><p>char *p1; 全局未初始化区 </p><p>main() </p><p>{ </p><p>int b; <font style="BACKGROUND-COLOR: #00ffff">栈</font></p><p>char s[] = "abc"; <font style="BACKGROUND-COLOR: #00ffff">栈</font></p><p>char *p2; <font style="BACKGROUND-COLOR: #00ffff">栈</font></p><p>char *p3 = "123456"; 123456\0在常量区，p3在<font style="BACKGROUND-COLOR: #00ffff">栈</font>上。 </p><p>static int c =0； 全局（静态）初始化区 </p><p>p1 = (char *)malloc(10); </p><p>p2 = (char *)malloc(20); </p><p>分配得来得10和20字节的区域就在<font style="BACKGROUND-COLOR: #ffff00">堆</font>区。 </p><p>strcpy(p1, "123456"); 123456\0放在常量区，编译器可能会将它与p3所指向的"123456"优化成一个地方。 </p><p>} </p><p>二、<font style="BACKGROUND-COLOR: #ffff00">堆</font>和<font style="BACKGROUND-COLOR: #00ffff">栈</font>的理论知识 </p><p>2.1申请方式 </p><p>stack: </p><p>由系统自动分配。 例如，声明在函数中一个局部变量 int b; 系统自动在<font style="BACKGROUND-COLOR: #00ffff">栈</font>中为b开辟空间 </p><p>heap: </p><p>需要程序员自己申请，并指明大小，在c中malloc函数 </p><p>如p1 = (char *)malloc(10); </p><p>在C++中用new运算符 </p><p>如p2 = (char *)malloc(10); </p><p>但是注意p1、p2本身是在<font style="BACKGROUND-COLOR: #00ffff">栈</font>中的。 </p><p>2.2 </p><p>申请后系统的响应 </p><p><font style="BACKGROUND-COLOR: #00ffff">栈</font>：只要<font style="BACKGROUND-COLOR: #00ffff">栈</font>的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示<font style="BACKGROUND-COLOR: #00ffff">栈</font>溢出。 </p><p><font style="BACKGROUND-COLOR: #ffff00">堆</font>：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时， </p><p>会遍历该链表，寻找第一个空间大于所申请空间的<font style="BACKGROUND-COLOR: #ffff00">堆</font>结点，然后将该结点从空闲结点链表中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内存空间中的首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。另外，由于找到的<font style="BACKGROUND-COLOR: #ffff00">堆</font>结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部分重新放入空闲链表中。 </p><p>2.3申请大小的限制 </p><p><font style="BACKGROUND-COLOR: #00ffff">栈</font>：在Windows下,<font style="BACKGROUND-COLOR: #00ffff">栈</font>是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意思是<font style="BACKGROUND-COLOR: #00ffff">栈</font>顶的地址和<font style="BACKGROUND-COLOR: #00ffff">栈</font>的最大容量是系统预先规定好的，在WINDOWS下，<font style="BACKGROUND-COLOR: #00ffff">栈</font>的大小是2M（也有的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过<font style="BACKGROUND-COLOR: #00ffff">栈</font>的剩余空间时，将提示overflow。因此，能从<font style="BACKGROUND-COLOR: #00ffff">栈</font>获得的空间较小。 </p><p><font style="BACKGROUND-COLOR: #ffff00">堆</font>：<font style="BACKGROUND-COLOR: #ffff00">堆</font>是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。<font style="BACKGROUND-COLOR: #ffff00">堆</font>的大小受限于计算机系统中有效的虚拟内存。由此可见，<font style="BACKGROUND-COLOR: #ffff00">堆</font>获得的空间比较灵活，也比较大。 </p><p>2.4申请效率的比较： </p><p><font style="BACKGROUND-COLOR: #00ffff">栈</font>由系统自动分配，速度较快。但程序员是无法控制的。 </p><p><font style="BACKGROUND-COLOR: #ffff00">堆</font>是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便. </p><p>另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在<font style="BACKGROUND-COLOR: #ffff00">堆</font>，也不是在<font style="BACKGROUND-COLOR: #00ffff">栈</font>是直接在进程的地址空间中保留一快内存，虽然用起来最不方便。但是速度快，也最灵活。 </p><p>2.5<font style="BACKGROUND-COLOR: #ffff00">堆</font>和<font style="BACKGROUND-COLOR: #00ffff">栈</font>中的存储内容 </p><p><font style="BACKGROUND-COLOR: #00ffff">栈</font>： 在函数调用时，第一个进<font style="BACKGROUND-COLOR: #00ffff">栈</font>的是主函数中后的下一条指令（函数调用语句的下一条可执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入<font style="BACKGROUND-COLOR: #00ffff">栈</font>的，然后是函数中的局部变量。注意静态变量是不入<font style="BACKGROUND-COLOR: #00ffff">栈</font>的。 </p><p>当本次函数调用结束后，局部变量先出<font style="BACKGROUND-COLOR: #00ffff">栈</font>，然后是参数，最后<font style="BACKGROUND-COLOR: #00ffff">栈</font>顶指针指向最开始存的地址，也就是主函数中的下一条指令，程序由该点继续运行。 </p><p><font style="BACKGROUND-COLOR: #ffff00">堆</font>：一般是在<font style="BACKGROUND-COLOR: #ffff00">堆</font>的头部用一个字节存放<font style="BACKGROUND-COLOR: #ffff00">堆</font>的大小。<font style="BACKGROUND-COLOR: #ffff00">堆</font>中的具体内容有程序员安排。 </p><p>2.6存取效率的比较 </p><p>char s1[] = "aaaaaaaaaaaaaaa"; </p><p>char *s2 = "bbbbbbbbbbbbbbbbb"; </p><p>aaaaaaaaaaa是在运行时刻赋值的； </p><p>而bbbbbbbbbbb是在编译时就确定的； </p><p>但是，在以后的存取中，在<font style="BACKGROUND-COLOR: #00ffff">栈</font>上的数组比指针所指向的字符串(例如<font style="BACKGROUND-COLOR: #ffff00">堆</font>)快。 </p><p>比如： </p><p>#include </p><p>void main() </p><p>{ </p><p>char a = 1; </p><p>char c[] = "1234567890"; </p><p>char *p ="1234567890"; </p><p>a = c[1]; </p><p>a = p[1]; </p><p>return; </p><p>} </p><p>对应的汇编代码 </p><p>10: a = c[1]; </p><p>00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] </p><p>0040106A 88 4D FC mov byte ptr [ebp-4],cl </p><p>11: a = p[1]; </p><p>0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] </p><p>00401070 8A 42 01 mov al,byte ptr [edx+1] </p><p>00401073 88 45 FC mov byte ptr [ebp-4],al </p><p>第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到edx中，在根据edx读取字符，显然慢了。 </p><p>2.7小结： </p><p><font style="BACKGROUND-COLOR: #ffff00">堆</font>和<font style="BACKGROUND-COLOR: #00ffff">栈</font>的区别可以用如下的比喻来看出： </p><p>使用<font style="BACKGROUND-COLOR: #00ffff">栈</font>就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自由度小。 </p><p>使用<font style="BACKGROUND-COLOR: #ffff00">堆</font>就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由度大。</p></div></div>
<img src ="http://www.cppblog.com/xushaohua/aggbug/14917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-09 20:45 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/09/14917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C中的跳转语句[非goto]</title><link>http://www.cppblog.com/xushaohua/archive/2006/11/04/14672.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Sat, 04 Nov 2006 13:18:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/04/14672.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/14672.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/04/14672.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/14672.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/14672.html</trackback:ping><description><![CDATA[
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">stdio.h</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 2</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span>
				<span style="COLOR: #000000">&lt;</span>
				<span style="COLOR: #000000">setjmp.h</span>
				<span style="COLOR: #000000">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 3</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />jmp_buf buf;<br /></span>
				<span style="COLOR: #008080"> 4</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 5</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">static</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> babana()<br /></span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_74_148_Open_Image" onclick="this.style.display='none'; Codehighlighter1_74_148_Open_Text.style.display='none'; Codehighlighter1_74_148_Closed_Image.style.display='inline'; Codehighlighter1_74_148_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_74_148_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_74_148_Closed_Text.style.display='none'; Codehighlighter1_74_148_Open_Image.style.display='inline'; Codehighlighter1_74_148_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_74_148_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_74_148_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 7</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">in babana()\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080"> 8</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    longjmp(buf,</span>
						<span style="COLOR: #000000">1</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080"> 9</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">never see me\n</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">10</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">12</span>
				<span style="COLOR: #000000">
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">int</span>
				<span style="COLOR: #000000"> main()<br /></span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_162_286_Open_Image" onclick="this.style.display='none'; Codehighlighter1_162_286_Open_Text.style.display='none'; Codehighlighter1_162_286_Closed_Image.style.display='inline'; Codehighlighter1_162_286_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_162_286_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_162_286_Closed_Text.style.display='none'; Codehighlighter1_162_286_Open_Image.style.display='inline'; Codehighlighter1_162_286_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span id="Codehighlighter1_162_286_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.cppblog.com/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_162_286_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">14</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">if</span>
						<span style="COLOR: #000000">(setjmp(buf))<br /></span>
						<span style="COLOR: #008080">15</span>
						<span style="COLOR: #000000">
								<img id="Codehighlighter1_182_214_Open_Image" onclick="this.style.display='none'; Codehighlighter1_182_214_Open_Text.style.display='none'; Codehighlighter1_182_214_Closed_Image.style.display='inline'; Codehighlighter1_182_214_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_182_214_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_182_214_Closed_Text.style.display='none'; Codehighlighter1_182_214_Open_Image.style.display='inline'; Codehighlighter1_182_214_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_182_214_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_182_214_Open_Text">
								<span style="COLOR: #000000">{<br /></span>
								<span style="COLOR: #008080">16</span>
								<span style="COLOR: #000000">
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        printf(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">back in main\n</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">);<br /></span>
								<span style="COLOR: #008080">17</span>
								<span style="COLOR: #000000">
										<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">18</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">else</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">19</span>
						<span style="COLOR: #000000">
								<img id="Codehighlighter1_223_273_Open_Image" onclick="this.style.display='none'; Codehighlighter1_223_273_Open_Text.style.display='none'; Codehighlighter1_223_273_Closed_Image.style.display='inline'; Codehighlighter1_223_273_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_223_273_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_223_273_Closed_Text.style.display='none'; Codehighlighter1_223_273_Open_Image.style.display='inline'; Codehighlighter1_223_273_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span>
						<span id="Codehighlighter1_223_273_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.cppblog.com/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_223_273_Open_Text">
								<span style="COLOR: #000000">{<br /></span>
								<span style="COLOR: #008080">20</span>
								<span style="COLOR: #000000">
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        printf(</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">first time through\n</span>
								<span style="COLOR: #000000">"</span>
								<span style="COLOR: #000000">);<br /></span>
								<span style="COLOR: #008080">21</span>
								<span style="COLOR: #000000">
										<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        babana();<br /></span>
								<span style="COLOR: #008080">22</span>
								<span style="COLOR: #000000">
										<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span>
						</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">23</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span>
						<span style="COLOR: #0000ff">return</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">;<br /></span>
						<span style="COLOR: #008080">24</span>
						<span style="COLOR: #000000">
								<img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div> setjmp()首先被调用,并且返回0.<br />goto是不能跳出当前函数的,而longjmp甚至可以跳到其他文件的函数中去(估计就是为什么要在名字里加个long的原因吧,:)).<br />但 longjmp只能跳回到曾经去过的地方,而setjmp正是标记到过的地方,所以从这角度来想的话,longjmp更像是"从何处来"而不是goto"去哪里".<br /><br />这也可以所就是C++中" catch "," throw " 的一个起源吧.<img src ="http://www.cppblog.com/xushaohua/aggbug/14672.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-04 21:18 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/04/14672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>匈牙利命名法的来历和介绍</title><link>http://www.cppblog.com/xushaohua/archive/2006/11/02/14591.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Thu, 02 Nov 2006 15:07:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/02/14591.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/14591.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/02/14591.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/14591.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/14591.html</trackback:ping><description><![CDATA[匈牙利命名法是一种编程时的命名规范。基本原则是：变量名＝属性＋类型＋对象描述，其中每一对象的名称都要求有明确含义，可以取对象名字全称或名字的一部分。命名要基于容易记忆容易理解的原则。保证名字的连贯性是非常重要的。 <br /><br />举例来说，表单的名称为form，那么在匈牙利命名法中可以简写为frm，则当表单变量名称为Switchboard时，变量全称应该为frmSwitchboard。这样可以很容易从变量名看出Switchboard是一个表单，同样，如果此变量类型为标签，那么就应命名成lblSwitchboard。可以看出，匈牙利命名法非常便于记忆，而且使变量名非常清晰易懂，这样，增强了代码的可读性，方便各程序员之间相互交流代码。 <br /><br />这种命名技术是由一位能干的Microsoft程序员查尔斯·西蒙尼(Charles Simonyi) 提出的，他出生在匈牙利。在 Microsoft 公司中和他一起工作的人被教会使用这种约定。这对他们来说一切都很正常。但对那些 Simonyi 领导的项目组之外的人来说却感到很奇特，他们认为这是死板的表达方式，甚至说带有这样奇怪的外观是因为它是用匈牙利文写的。从此这种命名方式就被叫做匈牙利命名法。 <br /><br />据说这种命名法是一位叫 Charles Simonyi 的匈牙利程序员发明的，后来他在微软呆了几年，于是 <br />这种命名法就通过微软的各种产品和文档资料向世界传播开了。现在，大部分程序员不管自己使用 <br />什么软件进行开发，或多或少都使用了这种命名法。这种命名法的出发点是把量名变按：属性+类型 <br />+对象 描述的顺序组合起来，以使程序员作变量时对变量的类型和其它属性有直观的了解，下面 <br />是HN变量命名规范，其中也有一些是我个人的偏向： <br /><br />属性部分 <br />全局变量 <br />g_ <br />常量 <br />c_ <br />c++类成员变量 <br />m_ <br />静态变量 <br />s_ <br /><br />类型部分 <br />指针 <br />p <br />函数 <br />fn <br />无效 <br />v <br />句柄 <br />h <br />长整型 <br />l <br />布尔 <br />b <br />浮点型（有时也指文件） <br />f <br />双字 <br />dw <br />字符串 <br />sz <br />短整型 <br />n <br />双精度浮点 <br />d <br />计数 <br />c（通常用cnt） <br />字符 <br />ch（通常用c） <br />整型 <br />i（通常用n） <br />字节 <br />by <br />字 <br />w <br />实型 <br />r <br />无符号 <br />u <br /><br />描述部分 <br />最大 <br />Max <br />最小 <br />Min <br />初始化 <br />Init <br />临时变量 <br />T（或Temp） <br />源对象 <br />Src <br />目的对象 <br />Dest <br /><br /><br /><br />这里顺便写几个例子： <br />hwnd ： h 是类型描述，表示句柄， wnd 是变量对象描述，表示窗口，所以 hwnd 表示窗口句柄； <br />pfnEatApple ： pfn 是类型描述，表示指向函数的指针， EatApple 是变量对象描述，所以它表示 <br />指向 EatApple 函数的函数指针变量。 <br />g_cch ： g_ 是属性描述，表示全局变量，c 和 ch 分别是计数类型和字符类型，一起表示变量类 <br />型，这里忽略了对象描述，所以它表示一个对字符进行计数的全局变量。 <br />上面就是HN命名法的一般规则。 <br /><br /><br />小结:匈牙利命名法 <br /><br />匈牙利命名法 <br /><br /><br />MFC、句柄、控件及结构的命名规范 Windows类型 样本变量 MFC类 样本变量 <br />HWND hWnd； CWnd* pWnd； <br />HDLG hDl*； **ialog* pDlg； <br />HDC hDC； CDC* pDC； <br />HGDIOBJ hGdiObj； CGdiObject* pGdiObj； <br />HPEN hPen； CPen* pPen； <br />HBRUSH hBrush； CBrush* pBrush； <br />HFONT hFont； CFont* pFont； <br />HBITMAP hBitmap； CBitmap* pBitmap； <br />HPALETTE hPaltte； CPalette* pPalette； <br />HRGN hRgn； CRgn* pRgn； <br />HMENU hMenu； CMenu* pMenu； <br />HWND hCtl； CState* pState； <br />HWND hCtl； CButton* pButton； <br />HWND hCtl； CEdit* pEdit； <br />HWND hCtl； CListBox* pListBox； <br />HWND hCtl； CComboBox* pComboBox； <br />HWND hCtl； CScrollBar* pScrollBar； <br />HSZ hszStr； CString pStr； <br />POINT pt； CPoint pt； <br />SIZE size； CSize size； <br />RECT rect； CRect rect； <br /><br /><br />一般前缀命名规范 前缀 类型 实例 <br />C 类或结构 CDocument，CPrintInfo <br />m_ 成员变量 m_pDoc，m_nCustomers <br /><br /><br />变量命名规范 前缀 类型 描述 实例 <br />ch char 8位字符 chGrade <br />ch TCHAR 如果_UNICODE定义，则为16位字符 chName <br />b BOOL 布尔值 bEnable <br />n int 整型（其大小依赖于操作系统） nLength <br />n UINT 无符号值（其大小依赖于操作系统） nHeight <br />w WORD 16位无符号值 wPos <br />l LONG 32位有符号整型 lOffset <br />dw DWORD 32位无符号整型 dwRange <br />p * 指针 pDoc <br />lp FAR* 远指针 lpszName <br />lpsz LPSTR 32位字符串指针 lpszName <br />lpsz LPCSTR 32位常量字符串指针 lpszName <br />lpsz LPCTSTR 如果_UNICODE定义，则为32位常量字符串指针 lpszName <br />h handle Windows对象句柄 hWnd <br />lpfn callback 指向CALLBACK函数的远指针 <br /><br /><br />前缀 符号类型 实例 范围 <br />IDR_ 不同类型的多个资源共享标识 IDR_MAIINFRAME 1～0x6FFF <br />IDD_ 对话框资源 IDD_SPELL_CHECK 1～0x6FFF <br />HIDD_ 对话框资源的Help上下文 HIDD_SPELL_CHECK 0x20001～0x26FF <br />IDB_ 位图资源 IDB_COMPANY_LOGO 1～0x6FFF <br />IDC_ 光标资源 IDC_PENCIL 1～0x6FFF <br />IDI_ 图标资源 IDI_NOTEPAD 1～0x6FFF <br />ID_ 来自菜单项或工具栏的命令 ID_TOOLS_SPELLING 0x8000～0xDFFF <br />HID_ 命令Help上下文 HID_TOOLS_SPELLING 0x18000～0x1DFFF <br />IDP_ 消息框提示 IDP_INVALID_PARTNO 8～0xDEEF <br />HIDP_ 消息框Help上下文 HIDP_INVALID_PARTNO 0x30008～0x3DEFF <br />IDS_ 串资源 IDS_COPYRIGHT 1～0x7EEF <br />IDC_ 对话框内的控件 IDC_RECALC 8～0xDEEF <br /><br /><br />Microsoft MFC宏命名规范 名称 类型 <br />_AFXDLL 唯一的动态连接库（Dynamic Link Library，DLL）版本 <br />_ALPHA 仅编译DEC Alpha处理器 <br />_DEBUG 包括诊断的调试版本 <br />_MBCS 编译多字节字符集 <br />_UNICODE 在一个应用程序中打开Unicode <br />AFXAPI MFC提供的函数 <br />CALLBACK 通过指针回调的函数 <br /><br /><br />库标识符命名法 标识符 值和含义 <br />u ANSI（N）或Unicode（U） <br />d 调试或发行：D = 调试；忽略标识符为发行。 <br /><br /><br />静态库版本命名规范 库 描述 <br />NAFXCWD.LIB 调试版本：MFC静态连接库 <br />NAFXCW.LIB 发行版本：MFC静态连接库 <br />UAFXCWD.LIB 调试版本：具有Unicode支持的MFC静态连接库 <br />UAFXCW.LIB 发行版本：具有Unicode支持的MFC静态连接库 <br /><br /><br />动态连接库命名规范 名称 类型 <br />_AFXDLL 唯一的动态连接库（DLL）版本 <br />WINAPI Windows所提供的函数 <br /><br /><br />Windows.h中新的命名规范 类型 定义描述 <br />WINAPI 使用在API声明中的FAR PASCAL位置，如果正在编写一个具有导出API人口点的DLL，则可以在自己的API中使用该类型 <br />CALLBACK 使用在应用程序回叫例程，如窗口和对话框过程中的FAR PASCAL的位置 <br />LPCSTR 与LPSTR相同，只是LPCSTR用于只读串指针，其定义类似（const cha* **R*） <br />UINT 可移植的无符号整型类型，其大小由主机环境决定（对于Windows NT和Windows 9x为32位）；它是unsigned int的同义词 <br />LRESULT 窗口程序返回值的类型 <br />LPARAM 声明lParam所使用的类型，lParam是窗口程序的第四个参数 <br />WPARAM 声明wParam所使用的类型，wParam是窗口程序的第三个参数 <br />LPVOID 一般指针类型，与（void *）相同，可以用来代替LPSTR<img src ="http://www.cppblog.com/xushaohua/aggbug/14591.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-02 23:07 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/02/14591.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>回调函数</title><link>http://www.cppblog.com/xushaohua/archive/2006/11/02/14584.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Thu, 02 Nov 2006 14:58:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/11/02/14584.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/14584.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/11/02/14584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/14584.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/14584.html</trackback:ping><description><![CDATA[一、回调函数的概念 <br />    回调函数是一个程序员不能显式调用的函数；通过将回调函数的地址传给调用者从而实现调用。<br /><br />二两个demo<br /><br />----------------------------------------------------------------------------------------------------------------<br />void caller(void(*ptr)())<br />{<br />ptr(); /* 调用ptr指向的函数 */ <br />}<br /><br />void func();<br /><br />int main()<br />{<br />p = func; <br />caller(p);    /* 传递函数地址到caller ,caller调用指针p指向的函数*/<br />}<br /><br /> 如果赋了不同的值给p（不同函数地址），那么调用者将调用不同地址的函数。赋值可以发生在运行时，这样使你能实现动态绑定。<br />-------------------------------------------------------------------------------------------------------------<br /><br />typedef int(*CallBack)(char *p) ; // 声明CallBack 类型的函数指针 <br /><br />int A(char *p); // 回调函数 <br /><br />B(CallBack lpCall,char *pProvide)<br />{<br />　........... // B 的自己实现功能语句<br />　lpCall(PpProvide); // 借助回调完成的功能 ，也就是A函数来处理的。 <br />　........... // B 的自己实现功能语句<br />}<br />// -------------- 使用例子 -------------<br />main()<br />{<br />char *p = "hello!";<br />B(A, p);<br />}<br /><img src ="http://www.cppblog.com/xushaohua/aggbug/14584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-11-02 22:58 <a href="http://www.cppblog.com/xushaohua/archive/2006/11/02/14584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC中获取程序运行的路径</title><link>http://www.cppblog.com/xushaohua/archive/2006/10/31/14443.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Tue, 31 Oct 2006 13:56:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/10/31/14443.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/14443.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/10/31/14443.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/14443.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/14443.html</trackback:ping><description><![CDATA[        在程序中有时候需要加载磁盘上资源文件的绝对路径（例如VC6中的FLASH播放组件），为了很好的实现这个功能我们就必须得获取到其资源所在的绝对路径，那么怎么来获取这个绝对的路径呢？好，现在让下面的例子来解开这个迷惑吧！~<br />一、常规的做法：<br />1.用API GetModuleFileName来获取可执行行文件的路径；<br />2.将获取的字符串中的最后一个 '\\'之后的字符全部去掉；<br />3.剩下的字符串即是我们所需要的；<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080"> 1</span><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">CString CXXXX::GetPath()<br /></span><span style="COLOR: #008080"> 2</span><span style="COLOR: #000000"><img id="Codehighlighter1_26_258_Open_Image" onclick="this.style.display='none'; Codehighlighter1_26_258_Open_Text.style.display='none'; Codehighlighter1_26_258_Closed_Image.style.display='inline'; Codehighlighter1_26_258_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_26_258_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_26_258_Closed_Text.style.display='none'; Codehighlighter1_26_258_Open_Image.style.display='inline'; Codehighlighter1_26_258_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_26_258_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_26_258_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080"> 3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> path[</span><span style="COLOR: #000000">256</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\0</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    GetModuleFileName(NULL, path, </span><span style="COLOR: #000000">256</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080"> 5</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> path </span><span style="COLOR: #000000">+</span><span style="COLOR: #000000"> strlen(path);<br /></span><span style="COLOR: #008080"> 6</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(p </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> NULL </span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"> p</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">path </span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\\</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #008080"> 7</span><span style="COLOR: #000000"><img id="Codehighlighter1_167_178_Open_Image" onclick="this.style.display='none'; Codehighlighter1_167_178_Open_Text.style.display='none'; Codehighlighter1_167_178_Closed_Image.style.display='inline'; Codehighlighter1_167_178_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_167_178_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_167_178_Closed_Text.style.display='none'; Codehighlighter1_167_178_Open_Image.style.display='inline'; Codehighlighter1_167_178_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_167_178_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_167_178_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080"> 8</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            p</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 9</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> temp[</span><span style="COLOR: #000000">256</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\0</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    strncpy(temp,path,(p</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">path));<br /></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> CString(temp);<br /></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div><br />二、利用C库函数来去掉后缀<br /> 
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">TCHAR path[MAX_PATH];<br /></span><span style="COLOR: #008080">2</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /> GetModuleFileName(NULL, path, MAX_PATH);<br /></span><span style="COLOR: #008080">3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">strrchr(path,</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\\</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">) </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\0</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;    <br />       // path 即为需要的路径</span></div><img src ="http://www.cppblog.com/xushaohua/aggbug/14443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-10-31 21:56 <a href="http://www.cppblog.com/xushaohua/archive/2006/10/31/14443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CString, BSTR, LPCTSTR </title><link>http://www.cppblog.com/xushaohua/archive/2006/10/21/13954.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Sat, 21 Oct 2006 08:12:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/10/21/13954.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/13954.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/10/21/13954.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/13954.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/13954.html</trackback:ping><description><![CDATA[CString是一个动态TCHAR数组，BSTR是一种专有格式的字符串（需要用系统提供的函数来操纵，LPCTSTR只是一个常量的TCHAR指针。<br><br>CString 是一个完全独立的类，动态的TCHAR数组，封装了 + 等操作符和字符串操作方法。<br>typedef OLECHAR FAR* BSTR;<br>typedef const char * LPCTSTR;<br><br><strong><font face=Verdana size=3>vc++中各种字符串的表示法</font></strong>
<p>首先char* 是指向ANSI字符数组的指针，其中每个字符占据8位（有效数据是除掉最高位的其他7位），这里保持了与传统的C,C++的兼容。</p>
<p>LP的含义是长指针(long pointer)。LPSTR是一个指向以&#8216;\0&#8217;结尾的ANSI字符数组的指针，与char*可以互换使用，在win32中较多地使用LPSTR。<br>而LPCSTR中增加的&#8216;C&#8217;的含义是&#8220;CONSTANT&#8221;（常量），表明这种数据类型的实例不能被使用它的API函数改变，除此之外，它与LPSTR是等同的。<br>1.LP表示长指针,在win16下有长指针(LP)和短指针(P)的区别,而在win32下是没有区别的,都是32位.所以这里的LP和P是等价的.<br>2.C表示const<br>3.T是什么东西呢,我们知道TCHAR在采用Unicode方式编译时是wchar_t,在普通时编译成char.</p>
<p>为了满足程序代码国际化的需要，业界推出了Unicode标准，它提供了一种简单和一致的表达字符串的方法，所有字符中的字节都是16位的值，其数量也可以满足差不多世界上所有书面语言字符的编码需求，开发程序时使用Unicode（类型为wchar_t)是一种被鼓励的做法。</p>
<p>LPWSTR与LPCWSTR由此产生，它们的含义类似于LPSTR与LPCSTR，只是字符数据是16位的wchar_t而不是char。</p>
<p>然后为了实现两种编码的通用，提出了TCHAR的定义：<br>如果定义_UNICODE，声明如下：<br>typedef wchar_t TCHAR;<br>如果没有定义_UNICODE，则声明如下：<br>typedef char TCHAR;</p>
<p>LPTSTR和LPCTSTR中的含义就是每个字符是这样的TCHAR。</p>
<p>CString类中的字符就是被声明为TCHAR类型的，它提供了一个封装好的类供用户方便地使用。</p>
<p>LPCTSTR:<br>&nbsp;&nbsp;&nbsp;&nbsp; #ifdef _UNICODE<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef const wchar_t * LPCTSTR;<br>&nbsp;&nbsp;&nbsp;&nbsp; #else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef const char * LPCTSTR;<br>&nbsp;&nbsp;&nbsp;&nbsp; #endif</p>
<strong>如何将CString类型的变量赋给char*类型的变量<br></strong>1、GetBuffer函数：<br>使用CString::GetBuffer函数。<br>char *p; <br>CString str="hello"; <br>p=str.GetBuffer(str.GetLength()); <br>str.ReleaseBuffer();
<p>将CString转换成char * 时<br>CString str("aaaaaaa");<br>strcpy(str.GetBuffer(10),"aa");<br>str.ReleaseBuffer();<br>当我们需要字符数组时调用GetBuffer(int n),其中n为我们需要的字符数组的长度.使用完成后一定要马上调用ReleaseBuffer();<br>还有很重要的一点就是,在能使用const char *的地方,就不要使用char *</p>
<p>2、memcpy： <br>CString mCS=_T("cxl"); <br>char mch[20]; <br>memcpy(mch,mCS,20); </p>
<p>3、用LPCTSTR强制转换： 尽量不使用<br>char *ch; <br>CString str; <br>ch=(LPSTR)(LPCTSTR)str; </p>
<p>CString str = "good";<br>char *tmp;<br>sprintf(tmp,"%s",(LPTSTR)(LPCTSTR)str); </p>
<p>4、<br>CString Msg; <br>Msg=Msg+"abc"; <br>LPTSTR lpsz; <br>lpsz = new TCHAR[Msg.GetLength()+1]; <br>_tcscpy(lpsz, Msg); <br>char * psz; <br>strcpy(psz,lpsz); </p>
<p><br><strong><font face=Verdana size=3>CString类向const char *转换</font></strong><br>char a[100];<br>CString str("aaaaaa");<br>strncpy(a,(LPCTSTR)str,sizeof(a));<br>或者如下:<br>strncpy(a,str,sizeof(a));<br>以上两种用法都是正确地. 因为strncpy的第二个参数类型为const char *.所以编译器会自动将CString类转换成const char *.</p>
<p><font face=Verdana size=3><strong>CString转LPCTSTR (const char *)<br></strong></font>CString cStr;<br>const char *lpctStr=(LPCTSTR)cStr;</p>
<p><strong><font face=Verdana size=3>LPCTSTR转CString</font></strong><br>LPCTSTR lpctStr;<br>CString cStr=lpctStr;</p>
<p><strong><font face=Verdana size=3>将char*类型的变量赋给CString型的变量</font></strong><br>可以直接赋值，如： <br>CString myString = "This is a test"; <br>也可以利用构造函数，如： <br>CString s1("Tom");</p>
<p><font face=Verdana size=3><strong>将CString类型的变量赋给char []类型(字符串)的变量<br></strong></font>1、sprintf()函数<br>CString str = "good";<br>char tmp[200] ;<br>sprintf(tmp, "%s",(LPCSTR)str);&nbsp;&nbsp;<br>(LPCSTR)str这种强制转换相当于(LPTSTR)(LPCTSTR)str <br>CString类的变量需要转换为(char*)的时,使用(LPTSTR)(LPCTSTR)str </p>
<p>然而，LPCTSTR是const char *,也就是说，得到的字符串是不可写的！将其强制转换成LPTSTR去掉const，是极为危险的！<br>一不留神就会完蛋！要得到char *,应该用GetBuffer()或GetBufferSetLength()，用完后再调用ReleaseBuffer()。</p>
<p>2、strcpy()函数<br>CString str;<br>char c[256];<br>strcpy(c, str); </p>
<p>char mychar[1024];<br>CString source="Hello";<br>strcpy((char*)&amp;mychar,(LPCTSTR)source); </p>
<p><br><strong><font face=Verdana size=3>关于CString的使用<br></font></strong>1、指定 CString 形参<br>&nbsp;&nbsp;&nbsp; 对于大多数需要字符串参数的函数，最好将函数原型中的形参指定为一个指向字符 (LPCTSTR) 而非 CString 的 const 指针。<br>当将形参指定为指向字符的 const 指针时，可将指针传递到 TCHAR 数组（如字符串 ["hi there"]）或传递到 CString 对象。<br>CString 对象将自动转换成 LPCTSTR。任何能够使用 LPCTSTR 的地方也能够使用 CString 对象。</p>
<p>2、如果某个形参将不会被修改，则也将该参数指定为常数字符串引用（即 const CString&amp;）。如果函数要修改该字符串，<br>则删除 const 修饰符。如果需要默认为空值，则将其初始化为空字符串 [""]，如下所示：<br>void AddCustomer( const CString&amp; name, const CString&amp; address, const CString&amp; comment = "" ); </p>
<p>3、对于大多数函数结果，按值返回 CString 对象即可。</p>
<p><br><strong><font face=Verdana size=4>串的基本运算</font></strong><br>&nbsp;&nbsp;&nbsp; 对于串的基本运算，很多高级语言均提供了相应的运算符或标准的库函数来实现。<br>为叙述方便，先定义几个相关的变量：<br>&nbsp;&nbsp;&nbsp; char s1[20]="dir/bin/appl",s2[20]="file.asm",s3[30],*p;<br>&nbsp;&nbsp;&nbsp; int result;<br>&nbsp;&nbsp;&nbsp; 下面以C语言中串运算介绍串的基本运算 <br>1、求串长<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int strlen(char *s);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //求串s的长度<br>&nbsp;&nbsp;&nbsp; 【例】printf("%d",strlen(s1));&nbsp;&nbsp;&nbsp; //输出s1的串长12</p>
<p>2、串复制<br>&nbsp;&nbsp;&nbsp; char *strcpy(char *to,*from)；//将from串复制到to串中，并返回to开始处指针<br>&nbsp;&nbsp;&nbsp; 【例】strcpy(s3,s1);&nbsp; //s3="dir/bin/appl",s1串不变</p>
<p><br>3、联接<br>&nbsp;&nbsp;&nbsp; char *strcat(char *to,char *from);//将from串复制到to串的末尾，<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //并返回to串开始处的指针<br>&nbsp;&nbsp;&nbsp; 【例】strcat(s3,"/");&nbsp;&nbsp;&nbsp; //s3="dir/bin/appl/"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat(s3,s2);&nbsp;&nbsp;&nbsp;&nbsp; //s3="dir/bin/appl/file.asm"</p>
<p>4、串比较<br>&nbsp;&nbsp;&nbsp; int strcmp(char *s1,char *s2);//比较s1和s2的大小，<br>&nbsp;&nbsp;&nbsp;&nbsp; //当s1&lt;s2、s1&gt;s2和s1=s2时，分别返回小于0、大于0和等于0的值 <br>&nbsp;&nbsp;&nbsp; 【例】result=strcmp("baker","Baker");&nbsp;&nbsp;&nbsp; //result&gt;0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result=strcmp("12","12");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//result=0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result=strcmp("Joe","joseph")&nbsp;&nbsp; //result&lt;0</p>
<p>5、字符定位<br>&nbsp;&nbsp;&nbsp; char *strchr(char *s,char c);//找c在字符串s中第一次出现的位置，<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;&nbsp;&nbsp;&nbsp;&nbsp; //若找到，则返回该位置，否则返回NULL<br>&nbsp;&nbsp;&nbsp; 【例】p=strchr(s2,'.');&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //p指向"file"之后的位置<br>　　　　　if(p) strcpy(p,".cpp");&nbsp;&nbsp;&nbsp;&nbsp; //s2="file.cpp" </p>
<p>&nbsp; 注意：<br>&nbsp;&nbsp;&nbsp; 　①上述操作是最基本的，其中后 4个操作还有变种形式：strncpy，strncath和strnchr。<br>&nbsp;&nbsp;&nbsp; 　②其它的串操作见C的&lt;string.h&gt;。在不同的高级语言中，对串运算的种类及符号都不尽相同<br>&nbsp;&nbsp;&nbsp; 　③其余的串操作一般可由这些基本操作组合而成</p>
<p>&nbsp;&nbsp;&nbsp; 【例】求子串的操作可如下实现：<br>&nbsp;&nbsp;&nbsp; void substr(char *sub,char *s,int pos,int len){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //s和sub是字符数组，用sub返回串s的第pos个字符起长度为len的子串<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //其中0&lt;=pos&lt;=strlen(s)-1,且数组sub至少可容纳len+1个字符。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;if (pos&lt;0||pos&gt;strlen(s)-1||len&lt;0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Error("parameter error!");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;strncpy(sub,&amp;s[pos],len);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //从s[pos]起复制至多len个字符到sub<br>--- <a href="http://www.cppblog.com/colelhx/archive/2007/09/13/32116.html">http://www.cppblog.com/colelhx/archive/2007/09/13/32116.html</a></p>
<img src ="http://www.cppblog.com/xushaohua/aggbug/13954.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-10-21 16:12 <a href="http://www.cppblog.com/xushaohua/archive/2006/10/21/13954.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单文件分割（06川大考研最后一题）</title><link>http://www.cppblog.com/xushaohua/archive/2006/10/18/13819.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Wed, 18 Oct 2006 08:50:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/10/18/13819.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/13819.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/10/18/13819.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/13819.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/13819.html</trackback:ping><description><![CDATA[闲暇无事，写点代码以打发无聊的时间。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080"> 1</span><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 2</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdlib.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080"> 3</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /><br /></span><span style="COLOR: #008080"> 4</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #008080"> 5</span><span style="COLOR: #000000"><img id="Codehighlighter1_55_1108_Open_Image" onclick="this.style.display='none'; Codehighlighter1_55_1108_Open_Text.style.display='none'; Codehighlighter1_55_1108_Closed_Image.style.display='inline'; Codehighlighter1_55_1108_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_55_1108_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_55_1108_Closed_Text.style.display='none'; Codehighlighter1_55_1108_Open_Image.style.display='inline'; Codehighlighter1_55_1108_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif" align="top" /></span><span id="Codehighlighter1_55_1108_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_55_1108_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080"> 6</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    FILE </span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">out</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 7</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    <br /></span><span style="COLOR: #008080"> 8</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> block;<br /></span><span style="COLOR: #008080"> 9</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">buffer;<br /></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i;<br /></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000"> size;<br /></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> num </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> src[</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">],dest[</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">],temp[</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">];<br /></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">***********************************************\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">请输入要分割的文件的位置：  </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    scanf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%s</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,src);<br /></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">请输入要分割成的小文件的个数：  </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    scanf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%d</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">num);<br /></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">请输入要分割后文件保存位置：  </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    scanf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%s</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,dest);<br /></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ((</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> fopen(src,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">rb</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)) </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> NULL)<br /></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img id="Codehighlighter1_413_458_Open_Image" onclick="this.style.display='none'; Codehighlighter1_413_458_Open_Text.style.display='none'; Codehighlighter1_413_458_Closed_Image.style.display='inline'; Codehighlighter1_413_458_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_413_458_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_413_458_Closed_Text.style.display='none'; Codehighlighter1_413_458_Open_Image.style.display='inline'; Codehighlighter1_413_458_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_413_458_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_413_458_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Open File Fail\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        exit(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">26</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    fseek(</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0L</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">27</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    size </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> ftell(</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">28</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    rewind(</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">29</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    block </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> size</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">num; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 每一个文件的大小</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #008080">30</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /></span><span style="COLOR: #000000">    buffer </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)malloc(block);<br /></span><span style="COLOR: #008080">31</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" /><br /></span><span style="COLOR: #008080">32</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> num;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #008080">33</span><span style="COLOR: #000000"><img id="Codehighlighter1_595_980_Open_Image" onclick="this.style.display='none'; Codehighlighter1_595_980_Open_Text.style.display='none'; Codehighlighter1_595_980_Closed_Image.style.display='inline'; Codehighlighter1_595_980_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_595_980_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_595_980_Closed_Text.style.display='none'; Codehighlighter1_595_980_Open_Image.style.display='inline'; Codehighlighter1_595_980_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_595_980_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_595_980_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080">34</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> ch[</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">];<br /></span><span style="COLOR: #008080">35</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        strcpy(temp,dest);<br /></span><span style="COLOR: #008080">36</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        itoa((i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">),ch,</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">37</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        strcat(temp,ch);<br /></span><span style="COLOR: #008080">38</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        strcat(temp,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">.dat</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">39</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(fread(buffer,block,</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #008080">40</span><span style="COLOR: #000000"><img id="Codehighlighter1_732_781_Open_Image" onclick="this.style.display='none'; Codehighlighter1_732_781_Open_Text.style.display='none'; Codehighlighter1_732_781_Closed_Image.style.display='inline'; Codehighlighter1_732_781_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_732_781_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_732_781_Closed_Text.style.display='none'; Codehighlighter1_732_781_Open_Image.style.display='inline'; Codehighlighter1_732_781_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_732_781_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_732_781_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080">41</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Read File Error\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">42</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            exit(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">43</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">44</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">((</span><span style="COLOR: #0000ff">out</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> fopen(temp,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">wb</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)) </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> NULL)<br /></span><span style="COLOR: #008080">45</span><span style="COLOR: #000000"><img id="Codehighlighter1_824_872_Open_Image" onclick="this.style.display='none'; Codehighlighter1_824_872_Open_Text.style.display='none'; Codehighlighter1_824_872_Closed_Image.style.display='inline'; Codehighlighter1_824_872_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_824_872_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_824_872_Closed_Text.style.display='none'; Codehighlighter1_824_872_Open_Image.style.display='inline'; Codehighlighter1_824_872_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_824_872_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_824_872_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080">46</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Open File Fail\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">47</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            exit(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">48</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">49</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(fwrite(buffer,block,</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #0000ff">out</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br /></span><span style="COLOR: #008080">50</span><span style="COLOR: #000000"><img id="Codehighlighter1_912_962_Open_Image" onclick="this.style.display='none'; Codehighlighter1_912_962_Open_Text.style.display='none'; Codehighlighter1_912_962_Closed_Image.style.display='inline'; Codehighlighter1_912_962_Closed_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_912_962_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_912_962_Closed_Text.style.display='none'; Codehighlighter1_912_962_Open_Image.style.display='inline'; Codehighlighter1_912_962_Open_Text.style.display='inline';" src="http://www.cppblog.com/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />        </span><span id="Codehighlighter1_912_962_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/images/dot.gif" /></span><span id="Codehighlighter1_912_962_Open_Text"><span style="COLOR: #000000">{<br /></span><span style="COLOR: #008080">51</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Write File Error\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">52</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />            exit(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">53</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />        }</span></span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">54</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />        fclose(</span><span style="COLOR: #0000ff">out</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">55</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">56</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    fclose(</span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">57</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    free(buffer);<br /></span><span style="COLOR: #008080">58</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Cut Over\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">59</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">***********************************************\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">60</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">61</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span><span style="COLOR: #000000"><br /></span><span style="COLOR: #008080">62</span><span style="COLOR: #000000"><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" /></span></div>简单就是美的了。<img src ="http://www.cppblog.com/xushaohua/aggbug/13819.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-10-18 16:50 <a href="http://www.cppblog.com/xushaohua/archive/2006/10/18/13819.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)用C语言编写Windows服务程序的五个步骤 </title><link>http://www.cppblog.com/xushaohua/archive/2006/10/15/13714.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Sun, 15 Oct 2006 10:40:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/10/15/13714.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/13714.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/10/15/13714.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/13714.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/13714.html</trackback:ping><description><![CDATA[前一段时间我写了一篇通过写服务的形式来达到一些监视程序运行的目的的文章，至于如何在windows下写服务我没有详细介绍，今天就让我们一起看看如何来写服务程序。<br /><br />     Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识，C（不是C++）是最佳选择。本文将建立并实现一个简单的服务程序，其功能是查询系统中可用物理内存数量，然后将结果写入一个文本文件。最后，你可以用所学知识编写自己的 Windows 服务。<br />　　当初我写第一个 NT 服务时，我到 MSDN 上找例子。在那里我找到了一篇 Nigel Thompson 写的文章：“Creating a Simple Win32 Service in C++”，这篇文章附带一个 C++ 例子。虽然这篇文章很好地解释了服务的开发过程，但是，我仍然感觉缺少我需要的重要信息。我想理解通过什么框架，调用什么函数，以及何时调用，但 C++ 在这方面没有让我轻松多少。面向对象的方法固然方便，但由于用类对底层 Win32 函数调用进行了封装，它不利于学习服务程序的基本知识。这就是为什么我觉得 C 更加适合于编写初级服务程序或者实现简单后台任务的服务。在你对服务程序有了充分透彻的理解之后，用 C++ 编写才能游刃有余。当我离开原来的工作岗位，不得不向另一个人转移我的知识的时候，利用我用 C 所写的例子就非常容易解释 NT 服务之所以然。<br />　　服务是一个运行在后台并实现勿需用户交互的任务的控制台程序。Windows NT/2000/XP 操作系统提供为服务程序提供专门的支持。人们可以用服务控制面板来配置安装好的服务程序，也就是 Windows 2000/XP 控制面板|管理工具中的“服务”（或在“开始”|“运行”对话框中输入 services.msc /s——译者注）。可以将服务配置成操作系统启动时自动启动，这样你就不必每次再重启系统后还要手动启动服务。<br />　　本文将首先解释如何创建一个定期查询可用物理内存并将结果写入某个文本文件的服务。然后指导你完成生成，安装和实现服务的整个过程。<br /><br /><br />第一步：主函数和全局定义<br /><br />首先，包含所需的头文件。例子要调用 Win32 函数（windows.h）和磁盘文件写入（stdio.h）：<br /><br />#include <br />#include <br />接着，定义两个常量：<br /><br />#define SLEEP_TIME 5000<br />#define LOGFILE "C:\\MyServices\\memstatus.txt"<br />SLEEP_TIME 指定两次连续查询可用内存之间的毫秒间隔。在第二步中编写服务工作循环的时候要使用该常量。<br />LOGFILE 定义日志文件的路径，你将会用 WriteToLog 函数将内存查询的结果输出到该文件，WriteToLog 函数定义如下：<br /><br />int WriteToLog(char* str)<br />{<br />    FILE* log;<br />    log = fopen(LOGFILE, "a+");<br />    if (log == NULL)<br />    return -1;<br />    fprintf(log, "%s\n", str);<br />    fclose(log);<br />    return 0;<br />}<br />声明几个全局变量，以便在程序的多个函数之间共享它们值。此外，做一个函数的前向定义：<br /><br />SERVICE_STATUS ServiceStatus; <br />SERVICE_STATUS_HANDLE hStatus; <br /><br />void ServiceMain(int argc, char** argv); <br />void ControlHandler(DWORD request); <br />int InitService();<br />　　现在，准备工作已经就绪，你可以开始编码了。服务程序控制台程序的一个子集。因此，开始你可以定义一个 main 函数，它是程序的入口点。对于服务程序来说，main 的代码令人惊讶地简短，因为它只创建分派表并启动控制分派机。<br /><br />void main() <br />{ <br />    SERVICE_TABLE_ENTRY ServiceTable[2];<br />    ServiceTable[0].lpServiceName = "MemoryStatus";<br />    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;<br />    <br />    ServiceTable[1].lpServiceName = NULL;<br />    ServiceTable[1].lpServiceProc = NULL;<br /><br />    // 启动服务的控制分派机线程<br />    StartServiceCtrlDispatcher(ServiceTable); <br />}<br />　　一个程序可能包含若干个服务。每一个服务都必须列于专门的分派表中（为此该程序定义了一个 ServiceTable 结构数组）。这个表中的每一项都要在 SERVICE_TABLE_ENTRY 结构之中。它有两个域：<br /><br />lpServiceName: 指向表示服务名称字符串的指针；当定义了多个服务时，那么这个域必须指定； <br />lpServiceProc: 指向服务主函数的指针（服务入口点）； <br />　　分派表的最后一项必须是服务名和服务主函数域的 NULL 指针，文本例子程序中只宿主一个服务，所以服务名的定义是可选的。<br />　　服务控制管理器（SCM：Services Control Manager）是一个管理系统所有服务的进程。当 SCM 启动某个服务时，它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程，该线程运行分派表中每个服务的 ServiceMain 函数（本文例子中只有一个服务）分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。<br /><br />注意：如果 StartServiceCtrlDispatcher 函数30秒没有被调用，便会报错，为了避免这种情况，我们必须在 ServiceMain 函数中（参见本文例子）或在非主函数的单独线程中初始化服务分派表。本文所描述的服务不需要防范这样的情况。<br /><br />　　分派表中所有的服务执行完之后（例如，用户通过“服务”控制面板程序停止它们），或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。<br /><br /><br />第二步：ServiceMain 函数<br /><br />　　Listing 1 展示了 ServiceMain 的代码。该函数是服务的入口点。它运行在一个单独的线程当中，这个线程是由控制分派器创建的。ServiceMain 应该尽可能早早为服务注册控制处理器。这要通过调用 RegisterServiceCtrlHadler 函数来实现。你要将两个参数传递给此函数：服务名和指向 ControlHandlerfunction 的指针。<br />　　它指示控制分派器调用 ControlHandler 函数处理 SCM 控制请求。注册完控制处理器之后，获得状态句柄（hStatus）。通过调用 SetServiceStatus 函数，用 hStatus 向 SCM 报告服务的状态。<br />Listing 1 展示了如何指定服务特征和其当前状态来初始化 ServiceStatus 结构，ServiceStatus 结构的每个域都有其用途： <br /><br />dwServiceType：指示服务类型，创建 Win32 服务。赋值 SERVICE_WIN32； <br />dwCurrentState：指定服务的当前状态。因为服务的初始化在这里没有完成，所以这里的状态为 SERVICE_START_PENDING； <br />dwControlsAccepted：这个域通知 SCM 服务接受哪个域。本文例子是允许 STOP 和 SHUTDOWN 请求。处理控制请求将在第三步讨论； <br />dwWin32ExitCode 和 dwServiceSpecificExitCode：这两个域在你终止服务并报告退出细节时很有用。初始化服务时并不退出，因此，它们的值为 0； <br />dwCheckPoint 和 dwWaitHint：这两个域表示初始化某个服务进程时要30秒以上。本文例子服务的初始化过程很短，所以这两个域的值都为 0。 <br />　　调用 SetServiceStatus 函数向 SCM 报告服务的状态时。要提供 hStatus 句柄和 ServiceStatus 结构。注意 ServiceStatus 一个全局变量，所以你可以跨多个函数使用它。ServiceMain 函数中，你给结构的几个域赋值，它们在服务运行的整个过程中都保持不变，比如：dwServiceType。<br />　　在报告了服务状态之后，你可以调用 InitService 函数来完成初始化。这个函数只是添加一个说明性字符串到日志文件。如下面代码所示：<br /><br />// 服务初始化<br />int InitService() <br />{ <br />    int result;<br />    result = WriteToLog("Monitoring started.");<br />    return(result); <br />}<br />　　在 ServiceMain 中，检查 InitService 函数的返回值。如果初始化有错（因为有可能写日志文件失败），则将服务状态置为终止并退出 ServiceMain：<br /><br />error = InitService(); <br />if (error) <br />{<br />    // 初始化失败，终止服务<br />    ServiceStatus.dwCurrentState = SERVICE_STOPPED; <br />    ServiceStatus.dwWin32ExitCode = -1; <br />    SetServiceStatus(hStatus, &amp;ServiceStatus); <br />    // 退出 ServiceMain<br />    return; <br />}<br />如果初始化成功，则向 SCM 报告状态：<br /><br />// 向 SCM 报告运行状态 <br />ServiceStatus.dwCurrentState = SERVICE_RUNNING; <br />SetServiceStatus (hStatus, &amp;ServiceStatus);<br />接着，启动工作循环。每五秒钟查询一个可用物理内存并将结果写入日志文件。<br /><br />如 Listing 1 所示，循环一直到服务的状态为 SERVICE_RUNNING 或日志文件写入出错为止。状态可能在 ControlHandler 函数响应 SCM 控制请求时修改。<br /><br /><br />第三步：处理控制请求<br /><br />　　在第二步中，你用 ServiceMain 函数注册了控制处理器函数。控制处理器与处理各种 Windows 消息的窗口回调函数非常类似。它检查 SCM 发送了什么请求并采取相应行动。<br />　　每次你调用 SetServiceStatus 函数的时候，必须指定服务接收 STOP 和 SHUTDOWN 请求。Listing 2 示范了如何在 ControlHandler 函数中处理它们。<br />　　STOP 请求是 SCM 终止服务的时候发送的。例如，如果用户在“服务”控制面板中手动终止服务。SHUTDOWN 请求是关闭机器时，由 SCM 发送给所有运行中服务的请求。两种情况的处理方式相同：<br /><br />写日志文件，监视停止； <br />向 SCM 报告 SERVICE_STOPPED 状态； <br />　　由于 ServiceStatus 结构对于整个程序而言为全局量，ServiceStatus 中的工作循环在当前状态改变或服务终止后停止。其它的控制请求如：PAUSE 和 CONTINUE 在本文的例子没有处理。<br />　　控制处理器函数必须报告服务状态，即便 SCM 每次发送控制请求的时候状态保持相同。因此，不管响应什么请求，都要调用 SetServiceStatus。<br /><br />第四步：安装和配置服务<br /><br />　　程序编好了，将之编译成 exe 文件。本文例子创建的文件叫 MemoryStatus.exe，将它拷贝到 C:\MyServices 文件夹。为了在机器上安装这个服务，需要用 SC.EXE 可执行文件，它是 Win32 Platform SDK 中附带的一个工具。（译者注：Visaul Studio .NET 2003 IDE 环境中也有这个工具，具体存放位置在：C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\Bin\winnt）。使用这个实用工具可以安装和移除服务。其它控制操作将通过服务控制面板来完成。以下是用命令行安装 MemoryStatus 服务的方法：<br /><br />sc create MemoryStatus binpath= c:\MyServices\MemoryStatus.exe<br />　　发出此创建命令。指定服务名和二进制文件的路径（注意 binpath= 和路径之间的那个空格）。安装成功后，便可以用服务控制面板来控制这个服务。用控制面板的工具栏启动和终止这个服务。<br /><br />　MemoryStatus 的启动类型是手动，也就是说根据需要来启动这个服务。右键单击该服务，然后选择上下文菜单中的“属性”菜单项，此时显示该服务的属性窗口。在这里可以修改启动类型以及其它设置。你还可以从“常规”标签中启动/停止服务。以下是从系统中移除服务的方法：<br /><br />sc delete MemoryStatus<br />指定 “delete” 选项和服务名。此服务将被标记为删除，下次西通重启后，该服务将被完全移除。<br />第五步：测试服务<br /><br />　　从服务控制面板启动 MemoryStatus 服务。如果初始化不出错，表示启动成功。过一会儿将服务停止。检查一下 C:\MyServices 文件夹中 memstatus.txt 文件的服务输出。在我的机器上输出是这样的：<br /><br />Monitoring started.<br />273469440<br />273379328<br />273133568<br />273084416<br />Monitoring stopped.<br />　　为了测试 MemoryStatus 服务在出错情况下的行为，可以将 memstatus.txt 文件设置成只读。这样一来，服务应该无法启动。<br />　　去掉只读属性，启动服务，在将文件设成只读。服务将停止执行，因为此时日志文件写入失败。如果你更新服务控制面板的内容，会发现服务状态是已经停止。<br />原文：Yevgeny Menaker<br />翻译：Northtibet <img src ="http://www.cppblog.com/xushaohua/aggbug/13714.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-10-15 18:40 <a href="http://www.cppblog.com/xushaohua/archive/2006/10/15/13714.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>文件系统监控</title><link>http://www.cppblog.com/xushaohua/archive/2006/10/15/13707.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Sun, 15 Oct 2006 05:37:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/10/15/13707.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/13707.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/10/15/13707.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/13707.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/13707.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: NET Framework 类库  FileSystemWatcher 类  侦听文件系统更改通知，并在目录或目录中的文件发生更改时引发事件。 命名空间:System.IO程序集:System（在 system.dll 中）继承层次结构System.Object   System.MarshalByRefObject     System.ComponentModel.Component ...&nbsp;&nbsp;<a href='http://www.cppblog.com/xushaohua/archive/2006/10/15/13707.html'>阅读全文</a><img src ="http://www.cppblog.com/xushaohua/aggbug/13707.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-10-15 13:37 <a href="http://www.cppblog.com/xushaohua/archive/2006/10/15/13707.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]WINDOWS键盘事件监控原理及应用</title><link>http://www.cppblog.com/xushaohua/archive/2006/10/15/13704.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Sun, 15 Oct 2006 04:37:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/10/15/13704.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/13704.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/10/15/13704.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/13704.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/13704.html</trackback:ping><description><![CDATA[一、在WINDOWS键盘事件上挂接监控函数的方法<br /><br />WINDOW下可进行挂接的过滤函数包括11种：<br /><br />WH_CALLWNDPROC 窗口函数的过滤函数<br /><br />WH_CBT 计算机培训过滤函数<br /><br />WH_DEBUG 调试过滤函数<br /><br />WH_GETMESSAGE 获取消息过滤函数<br /><br />WH_HARDWARE 硬件消息过滤函数<br /><br />WH_JOURNALPLAYBACK 消息重放过滤函数<br /><br />WH_JOURNALRECORD 消息记录过滤函数<br /><br />WH_MOUSE 鼠标过滤函数<br /><br />WH_MSGFILTER 消息过滤函数<br /><br />WH_SYSMSGFILTER 系统消息过滤函数<br /><br />WH_KEYBOARD 键盘过滤函数<br /><br />其中键盘过滤函数是最常用最有用的过滤函数类型，不管是哪一种类型的过滤函数，其挂接的基本方法都是相同的。<br />WINDOW调用挂接的反调函数时总是先调用挂接链首的那个函数，因此必须将键盘挂钩函数利用函数SetWindowsHookEx()将其挂接在函数链首。至于消息是否传递给函数链的下一个函数是由每个具体函数功能确定的，如果消息需要传统给下一个函数，可调用API函数的CallNextHookEx()来实现，如果不传递直接返回即可。挂接函数可以是用来监控所有线程消息的全局性函数，也可以是单独监控某一线程的局部性函数。如果挂接函数是局部函数，可以将它放到一个.DLL动态链接库中，也可以放在一个局部模块中；如果挂接函数是全局的，那么必须将其放在一个.DLL动态链接库中。挂接函数必须严格按照下述格式进行声明，以键盘挂钩函数为例：<br /><br />int FAR PASCAL KeyboardProc(int nCode,WORD wParam,DWORD lParam)<br /><br />其中KeyboardProc为定义挂接函数名，该函数必须在模块定义文件中利用EXPORTS命令进行说明；nCode决定挂接函数是否对当前消息进行处理；wParam和lParam为具体的消息内容。<br /><br /><br /><br />二、键盘事件挂接函数的安装与下载<br /><br />在程序中可以利用函数SetWindowsHookEx()来挂接过滤函数，在挂接函数时必须指出该挂接函数的类型、函数的入口地址以及函数是全局性的还是局部性的，挂接函数的具体调用格式如下：<br /><br />SetWindowsHookEx(iType,iProc,hInst,iCode)<br /><br />其中iType为挂接函数类型，键盘类型为WH_KEYBOARD,iProc为挂接函数地址，hInst为挂接函数链接库实例句柄，iCode为监控代码－0表示全局性函数。如果挂接函数需要将消息传递给下一个过滤函数，则在该挂接函数返回前还需要调用一次CallNextHookEx()函数，当需要下载挂接函数时，只要调用一次UnhookWindowsHookEx(iProc)函数即可实现。如果函数是全局性的，那么它必须放在一个.DLL动态链接库中，这时该函数调用方法可以和其它普通.DLL函数一样有三种：<br /><br />1.在DEF定义文件中直接用函数名或序号说明：<br /><br />EXPORTS<br /><br />WEP @1 RESIDENTNAME<br /><br />InitHooksDll @2<br /><br />InstallFilter @3<br /><br />KeyboardProc @4<br /><br />用序号说明格式为：链接库名.函数名(如本例中说明方法为KEYDLL.KeyboardProc)。<br /><br />2.在应用程序中利用函数直接调用：<br /><br />首先在应用程序中利用LoadLibrary(LPSTR "链接库名")将动态链接库装入，并取得装载库模块句柄hInst,然后直接利用GetProcAddress(HINSTANCE hInst,LPSTR "函数过程名")获取函数地址，然后直接调用该地址即可，程序结束前利用函数FreeLibrary( )释放装入的动态链接库即可。<br /><br />3.利用输入库.LIB方法<br /><br />利用IMPLIB.EXE程序在建立动态链接库的同时建立相应的输入库.LIB，然后直接在项目文件中增加该输入库。<br /><br /><br /><br />三、WINDOWS挂钩监控函数的实现步骤<br /><br />WINDOWS挂钩函数只有放在动态链接库DLL中才能实现所有事件的监控功能。在.DLL中形成挂钩监控函数基本方法及其基本结构如下：<br /><br />１、首先声明DLL中的变量和过程；<br /><br />２、然后编制DLL主模块LibMain()，建立模块实例；<br /><br />３、建立系统退出DLL机制WEP()函数；<br /><br />４、完成DLL初始化函数InitHooksDll(),传递主窗口程序句柄；<br /><br />５、编制挂钩安装和下载函数InstallFilter()；<br /><br />６、编制挂钩函数KeyboardProc()，在其中设置监控功能，并确定继续调下一个钩<br /><br />子函数还是直接返回WINDOWS应用程序。<br /><br />７、在WINDOWS主程序中需要初始化DLL并安装相应挂钩函数，由挂接的钩子函数负<br /><br />责与主程序通信；<br /><br />８、在不需要监控时由下载功能卸掉挂接函数。<br /><br />四、WINDOWS下键盘挂钩监控函数的应用技术<br /><br /><br /><br />目前标准的104 键盘上都有两个特殊的按键，其上分别用WINDOW程序徽标和鼠标下拉列表标识，本文暂且分别称为Micro左键和Micro右键，前者用来模拟鼠标左键激活开始菜单，后者用来模拟鼠标右键激活属性菜单。这两个特殊按键只有在按下后立即抬起即完成 CLICK过程才能实现其功能，并且没有和其它按键进行组合使用。由于WINDOWS 系统中将按键划分得更加详细，使应用程序中很难灵活定义自己的专用快捷键，比如在开发.IME等应用程序时很难找到不与WORD8.0等其它应用程序冲突的功能按键。如果将标准104键盘中的这两个特殊按键作为模拟CTRL和ALT 等专用按键，使其和其它按键组合，就可以在自己的应用程序中自由地设置专用功能键，为应用程序实现各种功能快捷键提供灵活性。正常情况下WINDOWS 键盘事件驱动程序并不将这两个按键的消息进行正常解释，这就必须利用键盘事件的挂钩监控函数来实现其特定的功能。其方法如下：<br /><br />１、首先编制如下一个简单动态链接库程序，并编译成DLL文件。<br /><br />#include "windows.h"<br /><br />int FAR PASCAL LibMain(HANDLE hModule,UINT wDataSeg,UINT cbHeapSize,LPSTR lpszCmdLine);<br /><br />int WINAPI WEP(int bSystemExit);<br /><br />int WINAPI InitHooksDll(HWND hwndMainWindow);<br /><br />int WINAPI InstallFilter(BOOL nCode);<br /><br />LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam);<br /><br />static HANDLE hInstance; // 全局句柄<br /><br />static HWND hWndMain; // 主窗口句柄<br /><br />static int InitCalled=0; // 初始化标志<br /><br />static HHOOK hKeyHook;<br /><br />FARPROC lpfnKeyHook=(FARPROC)KeyHook;<br /><br />BOOL HookStates=FALSE;<br /><br />int FAR PASCAL LibMain(<br /><br />HANDLE hModule,<br /><br />UINT wDataSeg,<br /><br />UINT cbHeapSize,<br /><br />LPSTR lpszCmdLine)<br /><br />{<br /><br />if (cbHeapSize!=0) UnlockData(0);<br /><br />hInstance = hModule;<br /><br />return 1;<br /><br />}<br /><br />int WINAPI WEP (int bSystemExit)<br /><br />{ return 1;}<br /><br />int WINAPI InitHooksDll(HWND hwndMainWindow)<br /><br />{ hWndMain = hwndMainWindow;<br /><br />InitCalled = 1;<br /><br />return (0);<br /><br />}<br /><br />int WINAPI InstallFilter(BOOL nCode)<br /><br />{ if (InitCalled==0) return (-1);<br /><br />if (nCode==TRUE) {<br /><br />hKeyHook=SetWindowsHookEx(WH_KEYBOARD,<br /><br />(HOOKPROC)lpfnKeyHook,hInstance,0);<br /><br />HookStates=TRUE;<br /><br />} else {<br /><br />UnhookWindowsHookEx(hKeyHook);<br /><br />HookStates=FALSE;<br /><br />}<br /><br />return(0);<br /><br />}<br /><br />LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam)<br /><br />{<br /><br />static BOOL msflag=FALSE;<br /><br />if(nCode&gt;=0) {<br /><br />if(HookStates==TRUE){<br /><br />if((wParam==0xff)|| //WIN3.X下按键值<br /><br />(wParam==0x5b)||(wParam==0x5c)){//WIN95下按键值<br /><br />if((i==0x15b)||(i==0x15c)){ //按键按下处理<br /><br />msflag=TRUE;<br /><br />PostMessage(hWndMain,0x7fff,0x1,0x3L);<br /><br />} else if((i==0xc15b)||(i==0xc15c)){//按键抬起处理<br /><br />msflag=FALSE;<br /><br />PostMessage(hWndMain,0x7fff,0x2,0x3L);<br /><br />}<br /><br />}<br /><br />}<br /><br />}<br /><br />return((int)CallNextHookEx(hKeyHook,nCode,wParam,lParam));<br /><br />}<br /><br />该程序的主要功能是监控键盘按键消息，将两个特殊按键Micro按下和抬起消息转换成自定义类型的消息，并将自定义消息发送给应用程序主窗口函数。<br /><br />２、在应用程序主函数中建立窗口后，调用InitHooksDll()函数来初始化动态链接库，并将应用程序主窗口句柄传递给链接库，然后调用InstallFilter()函数挂接键盘事件监控回调函数。<br /><br />InitHooksDll(hIMEWnd); //初始化DLL<br /><br />InstallFilter(TRUE); //安装键盘回调函数<br /><br />３、在应用程序主窗口函数处理自定义消息时，保存Micro按键的状态，供组合按键处理时判断使用。<br /><br />switch (iMessage) {<br /><br />case 0x7fff: //自定义消息类型<br /><br />if(lParam==0x3L){//设置Micro键的状态<br /><br />if(wParam==0x1) MicroFlag=TRUE;<br /><br />else if(wParam==0x2) MicroFlag=FALSE;<br /><br />}<br /><br />break;<br /><br />４、在进行按键组合处理时，首先判断Micro键是否按下，然后再进行其它按键的判断处理。<br /><br />case WM_KEYDOWN: // 按键按下处理<br /><br />if(MicroFlag==TRUE){//Micro键按下<br /><br />if((BYTE)HIBYTE(wParam)==0x5b){<br /><br />//Micro+"["组合键<br /><br />......//按键功能处理<br /><br />} else if((BYTE)HIBYTE(wParam)==0x5d){<br /><br />//Micro+"]"组合键<br /><br />......//按键功能处理<br /><br />}<br /><br />}<br /><br />break;<br /><br />５、当应用程序退出时应注意下载键盘监控函数，即调用InstallFilter(FALSE)函数一次。<br /><br />６、利用本文提供的方法设置自己的应用程序功能按键，在保证程序功能按键不会与其它系统发生冲突的同时，有效地利用了系统中现有资源，而且在实现应用程序功能的同时灵活应用了系统中提供的各种功能调用。<img src ="http://www.cppblog.com/xushaohua/aggbug/13704.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-10-15 12:37 <a href="http://www.cppblog.com/xushaohua/archive/2006/10/15/13704.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]鼠标屏幕取词技术的原理和实现</title><link>http://www.cppblog.com/xushaohua/archive/2006/10/02/13227.html</link><dc:creator>shaohua</dc:creator><author>shaohua</author><pubDate>Mon, 02 Oct 2006 12:39:00 GMT</pubDate><guid>http://www.cppblog.com/xushaohua/archive/2006/10/02/13227.html</guid><wfw:comment>http://www.cppblog.com/xushaohua/comments/13227.html</wfw:comment><comments>http://www.cppblog.com/xushaohua/archive/2006/10/02/13227.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xushaohua/comments/commentRss/13227.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xushaohua/services/trackbacks/13227.html</trackback:ping><description><![CDATA[“鼠标屏幕取词”技术是在电子字典中得到广泛地应用的，如四通利方和金山词霸等软件，这个技术看似简单，其实在WINDOWS系统中实现却是非常复杂的，总的来说有两种实现方式：<br />    第一种：采用截获对部分GDI的API调用来实现,如TextOut,TextOutA等。<br />    第二种：对每个设备上下文(DC)做一分Copy,并跟踪所有修改上下文(DC)的操作。      <br />    第二种方法更强大,但兼容性不好，而第一种方法使用的截获WindowsAPI的调用，这项技术的强大可能远远超出了您的想象，毫不夸张的说，利用WindowsAPI拦截技术，你可以改造整个操作系统，事实上很多外挂式Windows中文平台就是这么实现的！而这项技术也正是这篇文章的主题。<br />    截WindowsAPI的调用，具体的说来也可以分为两种方法：<br />    第一种方法通过直接改写WinAPI 在内存中的映像，嵌入汇编代码，使之被调用时跳转到指定的地址运行来截获；第二种方法则改写IAT（Import Address Table 输入地址表），重定向WinAPI函数的调用来实现对WinAPI的截获。<br />    第一种方法的实现较为繁琐，而且在Win95、98下面更有难度，这是因为虽然微软说WIN16的API只是为了兼容性才保留下来，程序员应该尽可能地调用32位的API,实际上根本就不是这样！WIN 9X内部的大部分32位API经过变换调用了同名的16位API，也就是说我们需要在拦截的函数中嵌入16位汇编代码！<br />    我们将要介绍的是第二种拦截方法，这种方法在Win95、98和NT下面运行都比较稳定，兼容性较好。由于需要用到关于Windows虚拟内存的管理、打破进程边界墙、向应用程序的进程空间中注入代码、PE（Portable Executable）文件格式和IAT（输入地址表）等较底层的知识，所以我们先对涉及到的这些知识大概地做一个介绍，最后会给出拦截部分的关键代码。<br />      先说Windows虚拟内存的管理。Windows9X给每一个进程分配了4GB的地址空间，对于NT来说，这个数字是2GB，系统保留了2GB到 4GB之间的地址空间禁止进程访问，而在Win9X中，2GB到4GB这部分虚拟地址空间实际上是由所有的WIN32进程所共享的，这部分地址空间加载了共享Win32 DLL、内存映射文件和VXD、内存管理器和文件系统码，Win9X中这部分对于每一个进程都是可见的，这也是Win9X操作系统不够健壮的原因。Win9X中为16位操作系统保留了0到4MB的地址空间，而在4MB到2GB之间也就是Win32进程私有的地址空间，由于 每个进程的地址空间都是相对独立的，也就是说，如果程序想截获其它进程中的API调用，就必须打破进程边界墙，向其它的进程中注入截获API调用的代码，这项工作我们交给钩子函数（SetWindowsHookEx）来完成，关于如何创建一个包含系统钩子的动态链接库，《电脑高手杂志》在第？期已经有过专题介绍了，这里就不赘述了。所有系统钩子的函数必须要在动态库里，这样的话，当进程隐式或显式调用一个动态库里的函数时，系统会把这个动态库映射到这个进程的虚拟地址空间里，这使得DLL成为进程的一部分，以这个进程的身份执行，使用这个进程的堆栈，也就是说动态链接库中的代码被钩子函数注入了其它GUI进程的地址空间（非GUI进程，钩子函数就无能为力了），<br />当包含钩子的DLL注入其它进程后，就可以取得映射到这个进程虚拟内存里的各个模块（EXE和DLL）的基地址，如：<br />HMODULE hmodule=GetModuleHandle(“Mypro.exe”);<br />在MFC程序中,我们可以用AfxGetInstanceHandle()函数来得到模块的基地址。EXE和DLL被映射到虚拟内存空间的什么地方是由它们的基地址决定的。它们的基地址是在链接时由链接器决定的。当你新建一个Win32工程时，VC＋＋链接器使用缺省的基地址0x00400000。可以通过链接器的BASE选项改变模块的基地址。EXE通常被映射到虚拟内存的0x00400000处，DLL也随之有不同的基地址，通常被映射到不同进程<br />的相同的虚拟地址空间处。<br />系统将EXE和DLL原封不动映射到虚拟内存空间中，它们在内存中的结构与磁盘上的静态文件结构是一样的。即PE (Portable Executable) 文件格式。我们得到了进程模块的基地址以后，就可以根据PE文件的格式穷举这个模块的IMAGE_IMPORT_DESCRIPTOR数组，看看进程空间中是否引入了我们需要截获的函数所在的动态链接库，比如需要截获“TextOutA”，就必须检查“Gdi32.dll”是否被引入了。说到这里，我们有必要介绍一下PE文件的格式，如右图，这是PE文件格式的大致框图，最前面是文件头，我们不必理会，从PE File Optional Header后面开始，就是文件中各个段的说明，说明后面才是真正的段数据，而实际上我们关心的只有一个段，那就是“.idata”段，这个段中包含了所有的引入函数信息，还有IAT（Import Address Table）的RVA（Relative Virtual Address）地址。<br />说到这里，截获WindowsAPI的整个原理就要真相大白了。实际上所有进程对给定的API函数的调用总是通过PE文件的一个地方来转移的，这就是一个该模块(可以是EXE或DLL)的“.idata”段中的IAT输入地址表（Import Address Table）。在那里有所有本模块调用的其它DLL的函数名及地址。对其它DLL的函数调用实际上只是跳转到输入地址表，由输入地址表再跳转到DLL真正的函数入口。
<p>具体来说，我们将通过IMAGE_IMPORT_DESCRIPTOR数组来访问“.idata”段中引入的DLL的信息，然后通过IMAGE_THUNK_DATA数组来针对一个被引入的DLL访问该DLL中被引入的每个函数的信息，找到我们需要截获的函数的跳转地址，然后改成我们自己的函数的地址……具体的做法在后面的关键代码中会有详细的讲解。<br />   讲了这么多原理，现在让我们回到“鼠标屏幕取词”的专题上来。除了API函数的截获，要实现“鼠标屏幕取词”，还需要做一些其它的工作，简单的说来，可以把一个完整的取词过程归纳成以下几个步骤：<br />1． 安装鼠标钩子，通过钩子函数获得鼠标消息。<br />使用到的API函数：SetWindowsHookEx<br />2． 得到鼠标的当前位置，向鼠标下的窗口发重画消息，让它调用系统函数重画窗口。<br />     使用到的API函数：WindowFromPoint，ScreenToClient，InvalidateRect<br />3． 截获对系统函数的调用，取得参数，也就是我们要取的词。<br />对于大多数的Windows应用程序来说，如果要取词，我们需要截获的是“Gdi32.dll”中的“TextOutA”函数。<br />我们先仿照TextOutA函数写一个自己的MyTextOutA函数，如：<br />BOOL WINAPI MyTextOutA(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString)<br />{<br />       // 这里进行输出lpszString的处理<br />           // 然后调用正版的TextOutA函数<br />}<br />把这个函数放在安装了钩子的动态连接库中，然后调用我们最后给出的HookImportFunction函数来截获进程<br />对TextOutA函数的调用，跳转到我们的MyTextOutA函数，完成对输出字符串的捕捉。HookImportFunction的<br />用法：<br /> HOOKFUNCDESC hd;<br /> PROC         pOrigFuns;<br /> hd.szFunc=TextOutA;<br /> hd.pProc=(PROC)MyTextOutA;<br /> HookImportFunction (AfxGetInstanceHandle(),gdi32.dll,&amp;hd,pOrigFuns);<br />下面给出了HookImportFunction的源代码，相信详尽的注释一定不会让您觉得理解截获到底是怎么实现的<br />很难，Ok,Let’s Go：</p><p>///////////////////////////////////////////// Begin ///////////////////////////////////////////////////////////////<br />#include &lt;crtdbg.h&gt;</p><p>// 这里定义了一个产生指针的宏<br />#define MakePtr(cast, ptr, AddValue) (cast)((DWORD)(ptr)+(DWORD)(AddValue))</p><p>// 定义了HOOKFUNCDESC结构,我们用这个结构作为参数传给HookImportFunction函数<br />typedef struct tag_HOOKFUNCDESC<br />{<br />  LPCSTR szFunc; // The name of the function to hook.<br />  PROC pProc;    // The procedure to blast in.<br />} HOOKFUNCDESC , * LPHOOKFUNCDESC;</p><p>// 这个函数监测当前系统是否是WindowNT<br />BOOL IsNT();</p><p>// 这个函数得到hModule -- 即我们需要截获的函数所在的DLL模块的引入描述符(import descriptor)<br />PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule);</p><p>// 我们的主函数<br />BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule, <br />                         LPHOOKFUNCDESC paHookFunc, PROC* paOrigFuncs)<br />{<br />/////////////////////// 下面的代码检测参数的有效性 ////////////////////////////<br /> _ASSERT(szImportModule);<br /> _ASSERT(!IsBadReadPtr(paHookFunc, sizeof(HOOKFUNCDESC)));<br />#ifdef _DEBUG<br /> if (paOrigFuncs) _ASSERT(!IsBadWritePtr(paOrigFuncs, sizeof(PROC)));<br /> _ASSERT(paHookFunc.szFunc);<br /> _ASSERT(*paHookFunc.szFunc != \0);<br />        _ASSERT(!IsBadCodePtr(paHookFunc.pProc));<br />#endif<br /> if ((szImportModule == NULL) || (IsBadReadPtr(paHookFunc, sizeof(HOOKFUNCDESC))))<br /> {<br />  _ASSERT(FALSE);<br />  SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);<br />  return FALSE;<br /> }<br />//////////////////////////////////////////////////////////////////////////////</p><p> // 监测当前模块是否是在2GB虚拟内存空间之上<br /> // 这部分的地址内存是属于Win32进程共享的<br /> if (!IsNT() &amp;&amp; ((DWORD)hModule &gt;= 0x80000000))<br /> {<br />  _ASSERT(FALSE);<br />  SetLastErrorEx(ERROR_INVALID_HANDLE, SLE_ERROR);<br />  return FALSE;<br /> }<br />     // 清零<br /> if (paOrigFuncs) memset(paOrigFuncs, NULL, sizeof(PROC)); </p><p> // 调用GetNamedImportDescriptor()函数,来得到hModule -- 即我们需要<br /> // 截获的函数所在的DLL模块的引入描述符(import descriptor)<br /> PIMAGE_IMPORT_DESCRIPTOR pImportDesc = GetNamedImportDescriptor(hModule, szImportModule);<br /> if (pImportDesc == NULL)<br /> return FALSE; // 若为空,则模块未被当前进程所引入</p><p> //  从DLL模块中得到原始的THUNK信息,因为pImportDesc-&gt;FirstThunk数组中的原始信息已经<br /> //  在应用程序引入该DLL时覆盖上了所有的引入信息,所以我们需要通过取得pImportDesc-&gt;OriginalFirstThunk<br /> //  指针来访问引入函数名等信息<br /> PIMAGE_THUNK_DATA pOrigThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, <br />                                               pImportDesc-&gt;OriginalFirstThunk);</p><p> //  从pImportDesc-&gt;FirstThunk得到IMAGE_THUNK_DATA数组的指针,由于这里在DLL被引入时已经填充了<br /> //  所有的引入信息,所以真正的截获实际上正是在这里进行的<br /> PIMAGE_THUNK_DATA pRealThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc-&gt;FirstThunk);</p><p> //  穷举IMAGE_THUNK_DATA数组,寻找我们需要截获的函数,这是最关键的部分!<br /> while (pOrigThunk-&gt;u1.Function)<br /> {<br />  // 只寻找那些按函数名而不是序号引入的函数<br />  if (IMAGE_ORDINAL_FLAG != (pOrigThunk-&gt;u1.Ordinal &amp; IMAGE_ORDINAL_FLAG))<br />  {<br />   // 得到引入函数的函数名<br />   PIMAGE_IMPORT_BY_NAME pByName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule,<br />               pOrigThunk-&gt;u1.AddressOfData);</p><p>   // 如果函数名以NULL开始,跳过,继续下一个函数   <br />   if (\0 == pByName-&gt;Name[0])<br />    continue;</p><p>   // bDoHook用来检查是否截获成功<br />   BOOL bDoHook = FALSE;</p><p>   // 检查是否当前函数是我们需要截获的函数<br />   if ((paHookFunc.szFunc[0] == pByName-&gt;Name[0]) &amp;&amp;<br />    (strcmpi(paHookFunc.szFunc, (char*)pByName-&gt;Name) == 0))<br />   {<br />    // 找到了!<br />    if (paHookFunc.pProc)<br />    bDoHook = TRUE;<br />   }<br />   if (bDoHook)<br />   {<br />    // 我们已经找到了所要截获的函数,那么就开始动手吧<br />    // 首先要做的是改变这一块虚拟内存的内存保护状态,让我们可以自由存取<br />    MEMORY_BASIC_INFORMATION mbi_thunk;<br />    VirtualQuery(pRealThunk, &amp;mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));<br />    _ASSERT(VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, <br />                        PAGE_READWRITE, &amp;mbi_thunk.Protect));</p><p>    // 保存我们所要截获的函数的正确跳转地址<br />    if (paOrigFuncs)<br />      paOrigFuncs = (PROC)pRealThunk-&gt;u1.Function;</p><p>    // 将IMAGE_THUNK_DATA数组中的函数跳转地址改写为我们自己的函数地址!<br />    // 以后所有进程对这个系统函数的所有调用都将成为对我们自己编写的函数的调用<br />    pRealThunk-&gt;u1.Function = (PDWORD)paHookFunc.pProc;</p><p>    // 操作完毕!将这一块虚拟内存改回原来的保护状态<br />    DWORD dwOldProtect;<br />    _ASSERT(VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, <br />                        mbi_thunk.Protect, &amp;dwOldProtect));<br />    SetLastError(ERROR_SUCCESS);<br />    return TRUE;<br />   }<br />  }<br />  // 访问IMAGE_THUNK_DATA数组中的下一个元素<br />  pOrigThunk++;<br />  pRealThunk++;<br /> }<br /> return TRUE;<br />}</p><p>// GetNamedImportDescriptor函数的实现<br />PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule)<br />{<br /> // 检测参数<br /> _ASSERT(szImportModule);<br /> _ASSERT(hModule);<br /> if ((szImportModule == NULL) || (hModule == NULL))<br /> {<br />  _ASSERT(FALSE);<br />  SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);<br />  return NULL;<br /> }</p><p> // 得到Dos文件头<br /> PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) hModule;</p><p> // 检测是否MZ文件头<br /> if (IsBadReadPtr(pDOSHeader, sizeof(IMAGE_DOS_HEADER)) || <br />  (pDOSHeader-&gt;e_magic != IMAGE_DOS_SIGNATURE))<br /> {<br />  _ASSERT(FALSE);<br />  SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);<br />  return NULL;<br /> }</p><p> // 取得PE文件头<br /> PIMAGE_NT_HEADERS pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader-&gt;e_lfanew);</p><p> // 检测是否PE映像文件<br /> if (IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) || <br />   (pNTHeader-&gt;Signature != IMAGE_NT_SIGNATURE))<br /> {<br />  _ASSERT(FALSE);<br />  SetLastErrorEx(ERROR_INVALID_PARAMETER, SLE_ERROR);<br />  return NULL;<br /> }</p><p> // 检查PE文件的引入段(即 .idata section)<br /> if (pNTHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)<br />  return NULL;</p><p> // 得到引入段(即 .idata section)的指针<br /> PIMAGE_IMPORT_DESCRIPTOR pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader,<br />  pNTHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);</p><p> // 穷举PIMAGE_IMPORT_DESCRIPTOR数组寻找我们需要截获的函数所在的模块<br /> while (pImportDesc-&gt;Name)<br /> {<br />  PSTR szCurrMod = MakePtr(PSTR, pDOSHeader, pImportDesc-&gt;Name);<br />  if (stricmp(szCurrMod, szImportModule) == 0)<br />      break; // 找到!中断循环<br />  // 下一个元素<br />  pImportDesc++;<br /> }</p><p> // 如果没有找到,说明我们寻找的模块没有被当前的进程所引入!<br /> if (pImportDesc-&gt;Name == NULL)<br />  return NULL;</p><p> // 返回函数所找到的模块描述符(import descriptor)<br /> return pImportDesc;<br />}</p><p>// IsNT()函数的实现<br />BOOL IsNT()<br />{<br /> OSVERSIONINFO stOSVI;<br /> memset(&amp;stOSVI, NULL, sizeof(OSVERSIONINFO));<br /> stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);<br /> BOOL bRet = GetVersionEx(&amp;stOSVI);<br /> _ASSERT(TRUE == bRet);<br /> if (FALSE == bRet) return FALSE;<br /> return (VER_PLATFORM_WIN32_NT == stOSVI.dwPlatformId);<br />}<br />/////////////////////////////////////////////// End //////////////////////////////////////////////////////////////////////</p><p>   不知道在这篇文章问世之前，有多少朋友尝试过去实现“鼠标屏幕取词”这项充满了挑战的技术，也只有尝试过的朋友才能体会到其间的不易，尤其在探索API函数的截获时，手头的几篇资料没有一篇是涉及到关键代码的，重要的地方都是一笔代过，MSDN更是显得苍白而无力，也不知道除了IMAGE_IMPORT_DESCRIPTOR和IMAGE_THUNK_DATA，微软还隐藏了多少秘密，好在硬着头皮还是把它给攻克了，希望这篇文章对大家能有所帮助。</p><img src ="http://www.cppblog.com/xushaohua/aggbug/13227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xushaohua/" target="_blank">shaohua</a> 2006-10-02 20:39 <a href="http://www.cppblog.com/xushaohua/archive/2006/10/02/13227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>