liang's profile阿斯提亚神殿——梦幻天子's skyPhotosBlogLists Tools Help
    December 23

    对QQ显IP插件进行了初步的改进

     

     
    原本只能用MESSAGEBOX显示IP,现在做成了类似珊瑚虫的效果:
     
    December 16

    TCPDUMP的使用(转载)

    tcpdump采用命令行方式,它的命令格式为:
      tcpdump [ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ]
              [ -i 网络接口 ] [ -r 文件名] [ -s snaplen ]
              [ -T 类型 ] [ -w 文件名 ] [表达式 ]

      1. tcpdump的选项介绍
       -a    将网络地址和广播地址转变成名字;
       -d    将匹配信息包的代码以人们能够理解的汇编格式给出;
       -dd    将匹配信息包的代码以c语言程序段的格式给出;
       -ddd    将匹配信息包的代码以十进制的形式给出;
       -e    在输出行打印出数据链路层的头部信息;
       -f    将外部的Internet地址以数字的形式打印出来;
       -l    使标准输出变为缓冲行形式;
       -n    不把网络地址转换成名字;
       -t    在输出的每一行不打印时间戳;
       -v    输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息;
       -vv    输出详细的报文信息;
       -c    在收到指定的包的数目后,tcpdump就会停止;
       -F    从指定的文件中读取表达式,忽略其它的表达式;
       -i    指定监听的网络接口;
       -r    从指定的文件中读取包(这些包一般通过-w选项产生);
       -w    直接将包写入文件中,并不分析和打印出来;
       -T    将监听到的包直接解释为指定的类型的报文,常见的类型有rpc (远程过程
    调用)和snmp(简单       网络管理协议;)

      2. tcpdump的表达式介绍
       表达式是一个正则表达式,tcpdump利用它作为过滤报文的条件,如果一个报文满足表
    达式的条件,则这个报文将会被捕获。如果没有给出任何条件,则网络上所有的信息包将会
    被截获。
       在表达式中一般如下几种类型的关键字,一种是关于类型的关键字,主要包括host,
    net,port, 例如 host 210.27.48.2,指明 210.27.48.2是一台主机,net 202.0.0.0 指明
    202.0.0.0是一个网络地址,port 23 指明端口号是23。如果没有指定类型,缺省的类型是
    host.
       第二种是确定传输方向的关键字,主要包括src , dst ,dst or src, dst and src ,
    这些关键字指明了传输的方向。举例说明,src 210.27.48.2 ,指明ip包中源地址是210.27.
    48.2 , dst net 202.0.0.0 指明目的网络地址是202.0.0.0 。如果没有指明方向关键字,则
    缺省是src or dst关键字。
       第三种是协议的关键字,主要包括fddi,ip ,arp,rarp,tcp,udp等类型。Fddi指明是在
    FDDI(分布式光纤数据接口网络)上的特定的网络协议,实际上它是"ether"的别名,fddi和e
    ther具有类似的源地址和目的地址,所以可以将fddi协议包当作ether的包进行处理和分析。
    其他的几个关键字就是指明了监听的包的协议内容。如果没有指定任何协议,则tcpdump将会
    监听所有协议的信息包。
       除了这三种类型的关键字之外,其他重要的关键字如下:gateway, broadcast,less,
    greater,还有三种逻辑运算,取非运算是 'not ' '! ', 与运算是'and','&&';或运算 是'o
    r' ,'||';
       这些关键字可以组合起来构成强大的组合条件来满足人们的需要,下面举几个例子来
    说明。
       (1)想要截获所有210.27.48.1 的主机收到的和发出的所有的数据包:
        #tcpdump host 210.27.48.1
       (2) 想要截获主机210.27.48.1 和主机210.27.48.2 或210.27.48.3的通信,使用命令
    :(在命令行中适用   括号时,一定要
        #tcpdump host 210.27.48.1 and \ (210.27.48.2 or 210.27.48.3 \)
       (3) 如果想要获取主机210.27.48.1除了和主机210.27.48.2之外所有主机通信的ip包
    ,使用命令:
        #tcpdump ip host 210.27.48.1 and ! 210.27.48.2
       (4)如果想要获取主机210.27.48.1接收或发出的telnet包,使用如下命令:
        #tcpdump tcp port 23 host 210.27.48.1

      3. tcpdump 的输出结果介绍
       下面我们介绍几种典型的tcpdump命令的输出信息
       (1) 数据链路层头信息
       使用命令#tcpdump --e host ice
       ice 是一台装有linux的主机,她的MAC地址是0:90:27:58:AF:1A
       H219是一台装有SOLARIC的SUN工作站,它的MAC地址是8:0:20:79:5B:46;上一条
    命令的输出结果如下所示:
    21:50:12.847509 eth0 < 8:0:20:79:5b:46 0:90:27:58:af:1a ip 60: h219.33357 > ice.
    telne
    t 0:0(0) ack 22535 win 8760 (DF)
      分析:21:50:12是显示的时间, 847509是ID号,eth0 <表示从网络接口eth0 接受该
    数据包,eth0 >表示从网络接口设备发送数据包, 8:0:20:79:5b:46是主机H219的MAC地址,它
    表明是从源地址H219发来的数据包. 0:90:27:58:af:1a是主机ICE的MAC地址,表示该数据包的
    目的地址是ICE . ip 是表明该数据包是IP数据包,60 是数据包的长度, h219.33357 > ice.
    telnet 表明该数据包是从主机H219的33357端口发往主机ICE的TELNET(23)端口. ack 22535
    表明对序列号是222535的包进行响应. win 8760表明发送窗口的大小是8760.

      (2) ARP包的TCPDUMP输出信息
       使用命令#tcpdump arp
       得到的输出结果是:
      22:32:42.802509 eth0 > arp who-has route tell ice (0:90:27:58:af:1a)
      22:32:42.802902 eth0 < arp reply route is-at 0:90:27:12:10:66 (0:90:27:58:af
    :1a)
      分析: 22:32:42是时间戳, 802509是ID号, eth0 >表明从主机发出该数据包, arp表明是
    ARP请求包, who-has route tell ice表明是主机ICE请求主机ROUTE的MAC地址。 0:90:27:5
    8:af:1a是主机ICE的MAC地址。

      (3) TCP包的输出信息
       用TCPDUMP捕获的TCP包的一般输出信息是:
      src > dst: flags data-seqno ack window urgent options
      src > dst:表明从源地址到目的地址, flags是TCP包中的标志信息,S 是SYN标志, F (F
    IN), P (PUSH) , R (RST) "." (没有标记); data-seqno是数据包中的数据的顺序号, ack是
    下次期望的顺序号, window是接收缓存的窗口大小, urgent表明数据包中是否有紧急指针.
    Options是选项.

      (4) UDP包的输出信息
       用TCPDUMP捕获的UDP包的一般输出信息是:
      route.port1 > ice.port2: udp lenth
      UDP十分简单,上面的输出行表明从主机ROUTE的port1端口发出的一个UDP数据包到主机
    ICE的port2端口,类型是UDP, 包的长度是lenth

    自制QQ显IP外挂

     在CSK的QQ显IP外挂制作教程的帮助下,终于勉强做出了个QQ显IP的功能(真是麻烦,还要反汇编,不过在教程的帮助下还算胜利),以下是截图:
     
    December 12

    MFC下让控件具有XP风格(转载)

    方法一: 
    1.首先确认你在Windows   XP下,因为如果在98或2K下,那除非自己重画画所有界面,要不基本上是无法实现XP风格的。    
       
      2.   新建一个文本文件,把下面这段XML代码粘贴进去    
       
      <?xml   version="1.0"   encoding="UTF-8"   standalone="yes"?>    
      <assembly    
            xmlns="urn:schemas-microsoft-com:asm.v1"    
            manifestVersion="1.0">  
      <assemblyIdentity    
              processorArchitecture="x86"    
              version="5.1.0.0"  
              type="win32"  
              name="test.exe"/>  
              <description>Test   Application</description>  
              <dependency>  
              <dependentAssembly>  
              <assemblyIdentity  
                        type="win32"  
                        name="Microsoft.Windows.Common-Controls"  
                        version="6.0.0.0"  
                        publicKeyToken="6595b64144ccf1df"  
                        language="*"  
                        processorArchitecture="x86"/>  
              </dependentAssembly>  
              </dependency>  
      </assembly>  
       
      不要问我这段代码是什么意思,我也不知道,这段代码其实和任何一种试图实现XP风格时用的XML代码没有本质区别,几乎是一样的。粘贴进去时候存盘,名字随便取一个,反正到后面还是需要修改的。  
       
      3.假设在你的目录c:\abc下有一个可执行文件abc.exe,我们把刚才建立的那个XML的文件拷贝到c:\abc下,并把名字改为abc.exe.manifest,这时候你可以运行abc.exe,看看是不是已经具有了XP风格了?依次类推,在每一个你想改为XP风格的程序的统一目录里建立一个上面说的XML文件,并把名字改为可执行文件的名字加上".manifest"的扩展名(注意,不要把那个exe去掉,就可以了,你可以试着在MSDEV.exe所在目录中搞一个medev.exe.manifest的XML文件,看看VC起了什么变化?是不是资源编辑器里的对话框都变的漂亮了?
     
    方法二:
    首先在RES目录下建一个文件,命名Master.manifest然后用记事本打开放入  
      <?xml   version="1.0"   encoding="UTF-8"   standalone="yes"?>  
      <assembly   xmlns="urn:schemas-microsoft-com:asm.v1"   manifestVersion="1.0">  
      <assemblyIdentity  
              name="Microsoft.Windows.XXXX"  
              processorArchitecture="x86"  
              version="5.1.0.0"  
              type="win32"/>  
      <description>Windows   Shell</description>  
      <dependency>  
              <dependentAssembly>  
                      <assemblyIdentity  
                              type="win32"  
                              name="Microsoft.Windows.Common-Controls"  
                              version="6.0.0.0"  
                              processorArchitecture="x86"  
                              publicKeyToken="6595b64144ccf1df"  
                              language="*"  
                      />  
              </dependentAssembly>  
      </dependency>  
      </assembly>  
      保存..  
       
      然后VC6导入资源,把这个新建的文件导入,类型为24  
      保存..  
       
      用记事本打开rc   文件,   找到自定义资源的地方  
      改成如下   句子  
      IDR_MANIFEST                         24             MOVEABLE   PURE       "res\\Master.manifest"  
       
      MOVABLE   PURE是一定不能少的..保存  
      进入VC6,   把这个自定义资源IDR_MANIFEST的ID改为1(没有引号)  
       
      编译,,看一看是不是有了XP的风格.  
       
      这个程序就不用带第一种方法的那个文件了.  
     
    December 10

    Filtering expression syntax(转载)

    Note: this document has been drawn from the tcpdump man page. The original version can be found at  www.tcpdump.org.

     
    wpcap filters are based on a declarative predicate syntax. A filter is an ASCII string containing a filtering expression. pcap_compile() takes the expression and translates it in a program for the kernel-level packet filter.

    The expression selects which packets will be dumped. If no expression is given, all packets on the net will be accepted by the kernel-level filtering engine. Otherwise, only packets for which expression is `true' will be accepted.

    The expression consists of one or more primitives. Primitives usually consist of an id (name or number) preceded by one or more qualifiers. There are three different kinds of qualifier:

    type
    qualifiers say what kind of thing the id name or number refers to. Possible types are host, net and port. E.g., `host foo', `net 128.3', `port 20'. If there is no type qualifier, host is assumed.
    dir
    qualifiers specify a particular transfer direction to and/or from id. Possible directions are src, dst, src or dst and src and dst. E.g., `src foo', `dst net 128.3', `src or dst port ftp-data'. If there is no dir qualifier, src or dst is assumed. For `null' link layers (i.e. point to point protocols such as slip) the inbound and outbound qualifiers can be used to specify a desired direction.
    proto
    qualifiers restrict the match to a particular protocol. Possible protos are: ether, fddi, tr, ip, ip6, arp, rarp, decnet, tcp and udp. E.g., `ether src foo', `arp net 128.3', `tcp port 21'. If there is no proto qualifier, all protocols consistent with the type are assumed. E.g., `src foo' means `(ip or arp or rarp) src foo' (except the latter is not legal syntax), `net bar' means `(ip or arp or rarp) net bar' and `port 53' means `(tcp or udp) port 53'.

    [`fddi' is actually an alias for `ether'; the parser treats them identically as meaning ``the data link level used on the specified network interface.'' FDDI headers contain Ethernet-like source and destination addresses, and often contain Ethernet-like packet types, so you can filter on these FDDI fields just as with the analogous Ethernet fields. FDDI headers also contain other fields, but you cannot name them explicitly in a filter expression.

    Similarly, `tr' is an alias for `ether'; the previous paragraph's statements about FDDI headers also apply to Token Ring headers.]

    In addition to the above, there are some special `primitive' keywords that don't follow the pattern: gateway, broadcast, less, greater and arithmetic expressions. All of these are described below.

    More complex filter expressions are built up by using the words and, or and not to combine primitives. E.g., `host foo and not port ftp and not port ftp-data'. To save typing, identical qualifier lists can be omitted. E.g., `tcp dst port ftp or ftp-data or domain' is exactly the same as `tcp dst port ftp or tcp dst port ftp-data or tcp dst port domain'.

    Allowable primitives are:

    dst host host
    True if the IPv4/v6 destination field of the packet is host, which may be either an address or a name.
    src host host
    True if the IPv4/v6 source field of the packet is host.
    host host
    True if either the IPv4/v6 source or destination of the packet is host. Any of the above host expressions can be prepended with the keywords, ip, arp, rarp, or ip6 as in:
    ip host host
    which is equivalent to:
    ether proto \ip and host host
    If host is a name with multiple IP addresses, each address will be checked for a match.
    ether dst ehost
    True if the ethernet destination address is ehost. Ehost may be either a name from /etc/ethers or a number (see ethers(3N) for numeric format).
    ether src ehost
    True if the ethernet source address is ehost.
    ether host ehost
    True if either the ethernet source or destination address is ehost.
    gateway host
    True if the packet used host as a gateway. I.e., the ethernet source or destination address was host but neither the IP source nor the IP destination was host. Host must be a name and must be found both by the machine's host-name-to-IP-address resolution mechanisms (host name file, DNS, NIS, etc.) and by the machine's host-name-to-Ethernet-address resolution mechanism (/etc/ethers, etc.). (An equivalent expression is
    ether host ehost and not host host
    which can be used with either names or numbers for host / ehost.) This syntax does not work in IPv6-enabled configuration at this moment.
    dst net net
    True if the IPv4/v6 destination address of the packet has a network number of net. Net may be either a name from /etc/networks or a network number (see networks(4) for details).
    src net net
    True if the IPv4/v6 source address of the packet has a network number of net.
    net net
    True if either the IPv4/v6 source or destination address of the packet has a network number of net.
    net net mask netmask
    True if the IP address matches net with the specific netmask. May be qualified with src or dst. Note that this syntax is not valid for IPv6 net.
    net net/len
    True if the IPv4/v6 address matches net with a netmask len bits wide. May be qualified with src or dst.
    dst port port
    True if the packet is ip/tcp, ip/udp, ip6/tcp or ip6/udp and has a destination port value of port. The port can be a number or a name used in /etc/services (see tcp(4P) and udp(4P)). If a name is used, both the port number and protocol are checked. If a number or ambiguous name is used, only the port number is checked (e.g., dst port 513 will print both tcp/login traffic and udp/who traffic, and port domain will print both tcp/domain and udp/domain traffic).
    src port port
    True if the packet has a source port value of port.
    port port
    True if either the source or destination port of the packet is port. Any of the above port expressions can be prepended with the keywords, tcp or udp, as in:
    tcp src port port
    which matches only tcp packets whose source port is port.
    less length
    True if the packet has a length less than or equal to length. This is equivalent to:
    len <= length.
    greater length
    True if the packet has a length greater than or equal to length. This is equivalent to:
    len >= length.
    ip proto protocol
    True if the packet is an IP packet (see ip(4P)) of protocol type protocol. Protocol can be a number or one of the names icmp, icmp6, igmp, igrp, pim, ah, esp, vrrp, udp, or tcp. Note that the identifiers tcp, udp, and icmp are also keywords and must be escaped via backslash (\), which is \\ in the C-shell. Note that this primitive does not chase the protocol header chain.
    ip6 proto protocol
    True if the packet is an IPv6 packet of protocol type protocol. Note that this primitive does not chase the protocol header chain.
    ip6 protochain protocol
    True if the packet is IPv6 packet, and contains protocol header with type protocol in its protocol header chain. For example,
    ip6 protochain 6
    matches any IPv6 packet with TCP protocol header in the protocol header chain. The packet may contain, for example, authentication header, routing header, or hop-by-hop option header, between IPv6 header and TCP header. The BPF code emitted by this primitive is complex and cannot be optimized by BPF optimizer code in tcpdump, so this can be somewhat slow.
    ip protochain protocol
    Equivalent to ip6 protochain protocol, but this is for IPv4.
    ether broadcast
    True if the packet is an ethernet broadcast packet. The ether keyword is optional.
    ip broadcast
    True if the packet is an IP broadcast packet. It checks for both the all-zeroes and all-ones broadcast conventions, and looks up the local subnet mask.
    ether multicast
    True if the packet is an ethernet multicast packet. The ether keyword is optional. This is shorthand for `ether[0] & 1 != 0'.
    ip multicast
    True if the packet is an IP multicast packet.
    ip6 multicast
    True if the packet is an IPv6 multicast packet.
    ether proto protocol
    True if the packet is of ether type protocol. Protocol can be a number or one of the names ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, or netbeui. Note these identifiers are also keywords and must be escaped via backslash (\).
    [In the case of FDDI (e.g., `fddi protocol arp') and Token Ring (e.g., `tr protocol arp'), for most of those protocols, the protocol identification comes from the 802.2 Logical Link Control (LLC) header, which is usually layered on top of the FDDI or Token Ring header.
    When filtering for most protocol identifiers on FDDI or Token Ring, tcpdump checks only the protocol ID field of an LLC header in so-called SNAP format with an Organizational Unit Identifier (OUI) of 0x000000, for encapsulated Ethernet; it doesn't check whether the packet is in SNAP format with an OUI of 0x000000.
    The exceptions are iso, for which it checks the DSAP (Destination Service Access Point) and SSAP (Source Service Access Point) fields of the LLC header, stp and netbeui, where it checks the DSAP of the LLC header, and atalk, where it checks for a SNAP-format packet with an OUI of 0x080007 and the Appletalk etype.
    In the case of Ethernet, tcpdump checks the Ethernet type field for most of those protocols; the exceptions are iso, sap, and netbeui, for which it checks for an 802.3 frame and then checks the LLC header as it does for FDDI and Token Ring, atalk, where it checks both for the Appletalk etype in an Ethernet frame and for a SNAP-format packet as it does for FDDI and Token Ring, aarp, where it checks for the Appletalk ARP etype in either an Ethernet frame or an 802.2 SNAP frame with an OUI of 0x000000, and ipx, where it checks for the IPX etype in an Ethernet frame, the IPX DSAP in the LLC header, the 802.3 with no LLC header encapsulation of IPX, and the IPX etype in a SNAP frame.]
    decnet src host
    True if the DECNET source address is host, which may be an address of the form ``10.123'', or a DECNET host name. [DECNET host name support is only available on Ultrix systems that are configured to run DECNET.]
    decnet dst host
    True if the DECNET destination address is host.
    decnet host host
    True if either the DECNET source or destination address is host.
    ip, ip6, arp, rarp, atalk, aarp, decnet, iso, stp, ipx, netbeui
    Abbreviations for:
    ether proto p
    where p is one of the above protocols.
    lat, moprc, mopdl
    Abbreviations for:
    ether proto p
    where p is one of the above protocols. Note that tcpdump does not currently know how to parse these protocols.
    vlan [vlan_id]
    True if the packet is an IEEE 802.1Q VLAN packet. If [vlan_id] is specified, only true is the packet has the specified vlan_id. Note that the first vlan keyword encountered in expression changes the decoding offsets for the remainder of expression on the assumption that the packet is a VLAN packet.
    tcp, udp, icmp
    Abbreviations for:
    ip proto p or ip6 proto p
    where p is one of the above protocols.
    iso proto protocol
    True if the packet is an OSI packet of protocol type protocol. Protocol can be a number or one of the names clnp, esis, or isis.
    clnp, esis, isis
    Abbreviations for:
    iso proto p
    where p is one of the above protocols. Note that tcpdump does an incomplete job of parsing these protocols.
    expr relop expr
    True if the relation holds, where relop is one of >, <, >=, <=, =, !=, and expr is an arithmetic expression composed of integer constants (expressed in standard C syntax), the normal binary operators [+, -, *, /, &, |], a length operator, and special packet data accessors. To access data inside the packet, use the following syntax:
    proto [ expr : size ]
    
    Proto is one of ether, fddi, tr, ip, arp, rarp, tcp, udp, icmp or ip6, and indicates the protocol layer for the index operation. Note that tcp, udp and other upper-layer protocol types only apply to IPv4, not IPv6 (this will be fixed in the future). The byte offset, relative to the indicated protocol layer, is given by expr. Size is optional and indicates the number of bytes in the field of interest; it can be either one, two, or four, and defaults to one. The length operator, indicated by the keyword len, gives the length of the packet.

    For example, `ether[0] & 1 != 0' catches all multicast traffic. The expression `ip[0] & 0xf != 5' catches all IP packets with options. The expression `ip[6:2] & 0x1fff = 0' catches only unfragmented datagrams and frag zero of fragmented datagrams. This check is implicitly applied to the tcp and udp index operations. For instance, tcp[0] always means the first byte of the TCP header, and never means the first byte of an intervening fragment.

    Some offsets and field values may be expressed as names rather than as numeric values. The following protocol header field offsets are available: icmptype (ICMP type field), icmpcode (ICMP code field), and tcpflags (TCP flags field).

    The following ICMP type field values are available: icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply.

    The following TCP flags field values are available: tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg.

    Primitives may be combined using:

    A parenthesized group of primitives and operators (parentheses are special to the Shell and must be escaped).
    Negation (`!' or `not').
    Concatenation (`&&' or `and').
    Alternation (`||' or `or').

    Negation has highest precedence. Alternation and concatenation have equal precedence and associate left to right. Note that explicit and tokens, not juxtaposition, are now required for concatenation.

    If an identifier is given without a keyword, the most recent keyword is assumed. For example,

    not host vs and ace
    is short for
    not host vs and host ace
    which should not be confused with
    not ( host vs or ace )

    Expression arguments can be passed to tcpdump as either a single argument or as multiple arguments, whichever is more convenient. Generally, if the expression contains Shell metacharacters, it is easier to pass it as a single, quoted argument. Multiple arguments are concatenated with spaces before being parsed.

    December 09

    MSN SNIFFER制作基本完成

    经过一段时间对MFC的学习,MSN SNIFFER程序的界面终于完成了.以下是截图:
    这里特别感谢为我做TEST的朋友!
    下一阶段打算测试程序的健壮性,增强嗅探能力,适应不同的网络环境.
    不过呢,首先还是研究下另外一个PRP吧...
    December 08

    在对话框中加入工具栏(转载)

    工具栏(ToolBar)是一种非常方便的控件,能大大增加用户操作的效率,但是基于对话框的程序,却不能像使用编辑框(Edit Box)和列表框(List Box)一样,方便地增加工具栏控件。本文将介绍一种在对话框中加入工具栏的方法。


      一、 技术要点分析


      所有的Windows控件(包括工具栏、编辑框等)都派生自CWnd类,这就意味着,我们可以用窗口类的Create()函数把它们“创建”并显示到另一个窗口(例如对话框)上。把工具栏加入到对话框中正是使用了这样的一种方法。

      通常,我们使用CToolBarCtrl类(派生自CWnd类)来创建并管理工具栏控件。使用这个类创建一条工具栏的一般步骤如下:

      1.派生一个CToolBarCtrl的对象;

      2.调用CToolBarCtrl::Create函数创建工具栏对象;

      3.调用CToolBarCtrl::AddBitmap()和CToolBarCtrl::AddString()为工具栏对象加入位图和提示信息;

      4.派生一个TBUTTON数组对象进行工具栏中各按钮的具体设置;

      5.修改主窗口的OnNotify()函数,以显示工具栏上的提示信息。

      以上步骤在下面的范例代码中会有具体体现。


      二、 范例程序的建立与主要代码分析


      利用Visual C++ 的向导生成一个基于对话框的程序,命名为ToolBarInDial。修改主对话框样式如图1。绘出一条工具栏的位图并建立一选单,设置几个子选单项,然后建立一组工具栏的提示信息串(String Table),一旦鼠标在工具栏某项上停留,就会显示提示信息。下面给出程序中的主要代码。

      在主对话框CToolBarInDialDlg的类定义中有如下的变量说明:

      CToolBarCtrl ToolBar;

      int ButtonCount;

      int ButtonBitmap;

      BOOL DoFlag;

      TBUTTON m_Button[5];

      //设置工具栏上具体信息的变量数组

      //主对话框的初始化函数

      BOOL CToolBarInDialDlg::OnInitDialog()

      {

      RECT rect;

      //设置工具栏的显示范围

      rect.top=0; rect.left=0; rect.right=48; rect.bottom=16;

      ToolBar.Create(WS_CHILD|WS_VISIBLE|CCS_TOP|TBSTYLE_TOOLTIPS|CCS_ADJUSTABLE,rect,this,0);

      //建立工具栏并设置工具栏的样式

      ButtonBitmap=ToolBar.AddBitmap(5,IDB_PLAY); //加入工具栏的位图

      ButtonString=ToolBar.AddString(IDS_FIRST);//加入工具栏的提示信息

      //以下代码开始设置各具体的按钮

      m_Buttons[ButtonCount].iBitmap=

      ButtonBitmap+ButtonCount; //ButtonCount初值为0

      m_Buttons[ButtonCount].idCommand=ID_PLAY; //工具栏与选单上某子项对应

      m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

      //设置工具栏按钮为可选

      m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

      //设置工具栏按钮为普通按钮

      m_Buttons[ButtonCount].dwData=0;

      m_Buttons[ButtonCount].iString=IDS_LAST;

       ++ButtonCount;

      //类似地设置第二个按钮

      m_Buttons[ButtonCount].iBitmap=ButtonBitmap+ButtonCount;

      m_Buttons[ButtonCount].idCommand=ID_STOP;

      m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

      m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

      m_Buttons[ButtonCount].dwData=0;

      m_Buttons[ButtonCount].iString=IDS_NEXT;

      ++ButtonCount;

      ……//省略设置剩下的按钮的代码

       ToolBar.AddButtons(ButtonCount,m_Buttons);

      //为工具栏加入按钮并显示在对话框中

       return TRUE;

      }

      //当鼠标在工具栏上停留时,调用这个函数来显示提示信息

      BOOL CToolBarInDialDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULTpResult)

      {

      TOOLTIPTEXTtt;

      tt=(TOOLTIPTEXT)lParam;

      CString Tip;

      switch(tt->hdr.code)

      {

      case TTN_NEEDTEXT:

      //该信息表明要求显示工具栏上的提示

      switch(tt->hdr.idFrom)

      {

      case ID_PLAY:


      图1

      Tip.LoadString(IDS_FIRST); //设置对应于工具栏上ID_PLAY的按钮的提示信息

      break;

      case ID_STOP:

      Tip.LoadString(IDS_NEXT);

      //IDS_FIRST,IDS_NEXT等为一系列CString串

      break;

      ……//类似地设置剩下按钮的提示信息

      }

       strcpy(tt->szText,(LPCSTR)Tip);

       //显示提示信息

      break;

      }

      return CDialog::OnNotify(wParam, lParam, pResult);

      }

      //该演示程序的工具栏能由用户定制,随时增加或删除工具栏中的某一项

      void CToolBarInDialDlg::OnApply()

      {

       switch(DoFlag) //用户选择了增加或删除工具栏中的“退出”按钮

      {

      case TRUE: //增加工具栏上的“退出”按钮

      m_Buttons[ButtonCount].iBitmap=ButtonBitmap+ButtonCount;

      m_Buttons[ButtonCount].idCommand=ID_QUIT;

      m_Buttons[ButtonCount].fsState=TBSTATE_ENABLED;

      m_Buttons[ButtonCount].fsStyle=TBSTYLE_BUTTON;

      m_Buttons[ButtonCount].dwData=0;

      m_Buttons[ButtonCount].iString=IDS_FIRST;

      ToolBar.InsertButton(ButtonCount,&&m_Buttons[ButtonCount]);

      //根据m_Buttons的信息在工具栏的尾部加上一个按钮

      break;

      case FALSE:

      if(ToolBar.GetButtonCount()==4) //删除工具栏上某一特定位置的按钮

      {

      ToolBar.DeleteButton(3);

      //删除工具栏上某一按钮

      }

      break;

      }

      }

      void CToolBarInDialDlg::OnPlay() //响应函数举例

      {

      ……

      //对应选单项的响应函数

      }

      以上程序在中/英文Windows 98、VC++ 6.0环境下编译通过,运行正常。图2为运行中的有工具栏的对话框程序。


      图2   
    December 07

    CTreeCtrl中图标的使用(转载)

    建立一个CTreeCtrl控制成员 m_Tree;

     

    使用图标的方法:

    Step1:   //load icon

    HICON icon[4];

    Icon[0]=AfxGetApp()->LoadIcon(IDI_ICON1);

    Icon[1]=AfxGetApp()->LoadIcon(IDI_ICON2);

     

    Step2:  //创建CImageList

    CImageList *ImageList4Tree = new CImageList;

    ImageList4Tree.Create(16,16,0,4,4); //16,16为图标分辩率,4,4为该list最多能容纳的图标数

    For(int i=0;i<2;i++)

    {

           ImageList4Tree->Add(Icon[i]);  //读入图标

    }

     

    Step3: //使用创建好的CImageList

    m_Tree.SetImageList(ImageList4Tree);

     

    Step4:  //在添加项的同时选用图标

    m_Tree.InsertItem(itemName,0,1,parentItem);  //2个参数是item在添加好后的图标      

                                                                            //3个参数为item在被选中后的图标

    效果图如下:

     
     
    December 03

    对MFC的形象叙述(转载)

    MFC 是一个零组件超级市场,所贩卖的零组件功能以及零组件彼此之间的关系都已定义好;我们选择自己喜欢的零件,兜出一个应用程序
    December 01

    MFC 程序的初始化过程(转载)

    MFC 程序的初始化过程

    MFC 程序也是个Windows 程序,它的内部一定也像第1章所述一样,有窗口注册动

    作,有窗口产生动作,有消息循环动作,也有窗口函数。此刻我并不打算做出Windows

    序,只是想交待给你一个程序流程,这个流程正是任何MFC 程序的初始化过程的简化。

    以下是Frame2 范例程序的类别阶层及其成员。对于那些「除了构造式与析构式之外没

    有其它成员」的类别,我就不在图中展开他们了:

    (本图从Visual C++ 的「Class View 窗口」中获得)

    就如我曾在第1章解释过的,InitApplication InitInstance 现在成了MFC CWinApp

    的两个虚拟函数。前者负责「每一个程序只做一次」的动作,后者负责「每一个执行个

    体都得做一次」的动作。通常,系统会(并且有能力)为你注册一些标准的窗口类别(当

    然也就准备好了一些标准的窗口函数),你(应用程序设计者)应该在你的CMyWinApp

    中改写InitInstance,并在其中把窗口产生出来-- 这样你才有机会在标准的窗口类别中

    指定自己的窗口标题和菜单。下面就是我们新的main 函数:

    // MY.CPP

    CMyWinApp theApp;

    void main()

    {

    CWinApp* pApp = AfxGetApp();

    pApp->InitApplication();

    pApp->InitInstance();

    pApp->Run();

    }

    其中pApp 指向theApp 全域对象。在这里我们开始看到了虚拟函数的妙用(还不熟练者

    请快复习第2章):

    pApp->InitApplication() 调用的是CWinApp::InitApplication

    pApp->InitInstance() 调用的是CMyWinApp::InitInstance(因为CMyWinApp

    写它了),

    pApp->Run() 调用的是CWinApp::Run

    好,请注意以下CMyWinApp::InitInstance 的动作,以及它所引发的行为:

    BOOL CMyWinApp::InitInstance()

    {

    cout << "CMyWinApp::InitInstance \n";

    m_pMainWnd = new CMyFrameWnd; // 引发CMyFrameWnd::CMyFrameWnd 构造式

    return TRUE;

    }

    CMyFrameWnd::CMyFrameWnd()

    {

    Create(); // Create 是虚拟函数,但CMyFrameWnd 未改写它,所以引发父类别的

    // CFrameWnd::Create

    }

    BOOL CFrameWnd::Create()

    {

    cout << "CFrameWnd::Create \n";

    return TRUE;

    }

    BOOL CWnd::CreateEx()

    {

    cout << "CWnd::CreateEx \n";

    PreCreateWindow(); // 这是一个虚拟函数,CWnd 中有定义,CFrameWnd 也改写了

    // 它。

    return TRUE;

    }

    BOOL CFrameWnd::PreCreateWindow()

    {

    cout << "CFrameWnd::PreCreateWindow \n";

    return TRUE;

    }

    以下就是Frame2 的执行结果:

    cl my.cpp mfc.cpp <Enter>

    CWinApp::InitApplication

    CMyWinApp::InitInstance

    CMyFrameWnd::CMyFrameWnd

    CFrameWnd::Create

    CWnd::CreateEx

    CFrameWnd::PreCreateWindow

    CWinApp::Run

    CWinThread::Run