??xml version="1.0" encoding="utf-8" standalone="yes"?>99久久精品国内,亚洲欧洲中文日韩久久AV乱码,av国内精品久久久久影院http://m.shnenglu.com/bigsml/category/2847.htmlzh-cnSat, 20 Dec 2008 02:38:24 GMTSat, 20 Dec 2008 02:38:24 GMT60Pythong logging ?Logging4cplus 的适配?/title><link>http://m.shnenglu.com/bigsml/archive/2008/12/19/69856.html</link><dc:creator>泡?/dc:creator><author>泡?/author><pubDate>Fri, 19 Dec 2008 10:13:00 GMT</pubDate><guid>http://m.shnenglu.com/bigsml/archive/2008/12/19/69856.html</guid><wfw:comment>http://m.shnenglu.com/bigsml/comments/69856.html</wfw:comment><comments>http://m.shnenglu.com/bigsml/archive/2008/12/19/69856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/bigsml/comments/commentRss/69856.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/bigsml/services/trackbacks/69856.html</trackback:ping><description><![CDATA[<p>Python 的logging 模块的Socket ?Logging4cplus ?socket 的格式是不一L, 现实中需要将日志发送到logging4cplus 的服务器, 不得? 写了?Python logging 模块?logging4cplus的Adapter <br></p> <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> <span style="COLOR: #008000">#</span><span style="COLOR: #008000">!/usr/bin/env python</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080"> 2</span> <span style="COLOR: #008000">#</span><span style="COLOR: #008000">-*- coding: gbk -*-</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080"> 3</span> <span style="COLOR: #008000"></span><span style="COLOR: #0000ff">from</span><span style="COLOR: #000000"> struct </span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> pack, unpack <br></span><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080"> 5</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> BufferPack(object):    <br></span><span style="COLOR: #008080"> 6</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> </span><span style="COLOR: #800080">__init__</span><span style="COLOR: #000000">(self):<br></span><span style="COLOR: #008080"> 7</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">''</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080"> 8</span> <span style="COLOR: #000000">        <br></span><span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> addChar(self, s, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):<br></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> pack(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>b</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>c</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, s )<br></span><span style="COLOR: #008080">11</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">12</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> addShort(self, s, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):<br></span><span style="COLOR: #008080">13</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> pack(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>H</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>h</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, s )<br></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">15</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> addInt(self, s, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):<br></span><span style="COLOR: #008080">16</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> pack(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>I</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>i</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, s )<br></span><span style="COLOR: #008080">17</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> addLong(self, s, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):<br></span><span style="COLOR: #008080">19</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> pack(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>L</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>l</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, s )<br></span><span style="COLOR: #008080">20</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">21</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> addString(self, s):<br></span><span style="COLOR: #008080">22</span> <span style="COLOR: #000000">        self.addInt( len(s) ) <br></span><span style="COLOR: #008080">23</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> s <br></span><span style="COLOR: #008080">24</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">25</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> addBuffer(self, s):<br></span><span style="COLOR: #008080">26</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> s.buffer <br></span><span style="COLOR: #008080">27</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">28</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> BufferUnpack(object):<br></span><span style="COLOR: #008080">29</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">30</span> <span style="COLOR: #000000">    char_bits     </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> len( pack(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>b</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, 0) ) <br></span><span style="COLOR: #008080">31</span> <span style="COLOR: #000000">    short_bits     </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> len( pack(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>H</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, 0) ) <br></span><span style="COLOR: #008080">32</span> <span style="COLOR: #000000">    int_bits    </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> len( pack(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>I</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, 0) ) <br></span><span style="COLOR: #008080">33</span> <span style="COLOR: #000000">    long_bits     </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> len( pack(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">>L</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, 0) )    <br></span><span style="COLOR: #008080">34</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">35</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> </span><span style="COLOR: #800080">__init__</span><span style="COLOR: #000000">(self, buffer):<br></span><span style="COLOR: #008080">36</span> <span style="COLOR: #000000">        self.buffer </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> buffer <br></span><span style="COLOR: #008080">37</span> <span style="COLOR: #000000">        self.pos </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> 0<br></span><span style="COLOR: #008080">38</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">39</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> _read_item(self, unpackstr, len):<br></span><span style="COLOR: #008080">40</span> <span style="COLOR: #000000">        v </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> unpack(unpackstr, self.buffer[self.pos:self.pos</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">len] )<br></span><span style="COLOR: #008080">41</span> <span style="COLOR: #000000">        self.pos </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> len <br></span><span style="COLOR: #008080">42</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> v <br></span><span style="COLOR: #008080">43</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">44</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> readChar(self, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):<br></span><span style="COLOR: #008080">45</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> self._read_item(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><b</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><c</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, self.char_bits)<br></span><span style="COLOR: #008080">46</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">47</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> readShort(self, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):    <br></span><span style="COLOR: #008080">48</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> self._read_item(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><H</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><h</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, self.short_bits )<br></span><span style="COLOR: #008080">49</span> <span style="COLOR: #000000">        <br></span><span style="COLOR: #008080">50</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> readInt(self, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):<br></span><span style="COLOR: #008080">51</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> self._read_item(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><I</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><i</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, self.int_bits )<br></span><span style="COLOR: #008080">52</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">53</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> readLong(self, unsigned</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">False):<br></span><span style="COLOR: #008080">54</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> self._read_item(unsigned </span><span style="COLOR: #0000ff">and</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><L</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">or</span><span style="COLOR: #000000"> </span><span style="COLOR: #800000">'</span><span style="COLOR: #800000"><l</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, self.long_bits )<br></span><span style="COLOR: #008080">55</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">56</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> readString(self):<br></span><span style="COLOR: #008080">57</span> <span style="COLOR: #000000">        len </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> self.readInt()<br></span><span style="COLOR: #008080">58</span> <span style="COLOR: #000000">        v </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> self.buffer[self.pos:self.pos</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">len] <br></span><span style="COLOR: #008080">59</span> <span style="COLOR: #000000">        self.pos </span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000"> len<br></span><span style="COLOR: #008080">60</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> v <br></span><span style="COLOR: #008080">61</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">62</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">def</span><span style="COLOR: #000000"> PackMessage( record ):<br></span><span style="COLOR: #008080">63</span> <span style="COLOR: #000000">    bp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> BufferPack()<br></span><span style="COLOR: #008080">64</span> <span style="COLOR: #000000">    bp.addChar(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">, True) <br></span><span style="COLOR: #008080">65</span> <span style="COLOR: #000000">    bp.addChar(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">, True) <br></span><span style="COLOR: #008080">66</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">67</span> <span style="COLOR: #000000">    bp.addString(</span><span style="COLOR: #800000">"</span><span style="COLOR: #800000">{log.servername}</span><span style="COLOR: #800000">"</span><span style="COLOR: #000000">) <br></span><span style="COLOR: #008080">68</span> <span style="COLOR: #000000">    bp.addString(record.name) <br></span><span style="COLOR: #008080">69</span> <span style="COLOR: #000000">    bp.addInt(record.levelno</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">) <br></span><span style="COLOR: #008080">70</span> <span style="COLOR: #000000">    bp.addString(</span><span style="COLOR: #800000">""</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">71</span> <span style="COLOR: #000000">    bp.addString(record.msg)<br></span><span style="COLOR: #008080">72</span> <span style="COLOR: #000000">    bp.addString(str(record.threadName))<br></span><span style="COLOR: #008080">73</span> <span style="COLOR: #000000">    bp.addString(str(record.process))<br></span><span style="COLOR: #008080">74</span> <span style="COLOR: #000000">    bp.addInt( record.created ) <br></span><span style="COLOR: #008080">75</span> <span style="COLOR: #000000">    bp.addInt( record.msecs ) <br></span><span style="COLOR: #008080">76</span> <span style="COLOR: #000000">    bp.addString(record.filename)<br></span><span style="COLOR: #008080">77</span> <span style="COLOR: #000000">    bp.addInt( </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> )     <br></span><span style="COLOR: #008080">78</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">79</span> <span style="COLOR: #000000">    pkg </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> BufferPack()<br></span><span style="COLOR: #008080">80</span> <span style="COLOR: #000000">    pkg.addInt(len(bp.buffer), True) <br></span><span style="COLOR: #008080">81</span> <span style="COLOR: #000000">    pkg.addBuffer( bp ) <br></span><span style="COLOR: #008080">82</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">83</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> pkg.buffer<br></span><span style="COLOR: #008080">84</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">85</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> </span><span style="COLOR: #800080">__name__</span><span style="COLOR: #000000">==</span><span style="COLOR: #800000">"</span><span style="COLOR: #800000">__main__</span><span style="COLOR: #800000">"</span><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">86</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> logging, logging.handlers <br></span><span style="COLOR: #008080">87</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">88</span> <span style="COLOR: #000000">    logger </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> logging.getLogger()<br></span><span style="COLOR: #008080">89</span> <span style="COLOR: #000000">    logging.handlers.SocketHandler.makePickle </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">lambda</span><span style="COLOR: #000000"> self,rc : PackMessage(rc) <br></span><span style="COLOR: #008080">90</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">91</span> <span style="COLOR: #000000">    hdlr </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> logging.handlers.SocketHandler(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">{logserver.ip}</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">, </span><span style="COLOR: #000000">8888</span><span style="COLOR: #000000">) <br></span><span style="COLOR: #008080">92</span> <span style="COLOR: #000000">    formatter </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> logging.Formatter(</span><span style="COLOR: #800000">'</span><span style="COLOR: #800000">%(asctime)s %(levelname)s %(message)s</span><span style="COLOR: #800000">'</span><span style="COLOR: #000000">)<br></span><span style="COLOR: #008080">93</span> <span style="COLOR: #000000">    hdlr.setFormatter(formatter)<br></span><span style="COLOR: #008080">94</span> <span style="COLOR: #000000">    logger.addHandler(hdlr)<br></span><span style="COLOR: #008080">95</span> <span style="COLOR: #000000">    logger.setLevel(logging.NOTSET)<br></span><span style="COLOR: #008080">96</span> <span style="COLOR: #000000">    <br></span><span style="COLOR: #008080">97</span> <span style="COLOR: #000000">    logger.info(</span><span style="COLOR: #800000">"</span><span style="COLOR: #800000">hello</span><span style="COLOR: #800000">"</span><span style="COLOR: #000000">)</span></div> <br>使用的时?<br>1. 在logging 创徏SocketHandler 的时? 需要修改logging.handlers.SocketHandler.makePickle 为方?PackMessage <br>logging.handlers.SocketHandler.makePickle = lambda self,rc : PackMessage(rc) <br><br>2. 需要修改代码中的两部分内容 {log.servername} ?{logserver.ip}<br> <img src ="http://m.shnenglu.com/bigsml/aggbug/69856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/bigsml/" target="_blank">泡?/a> 2008-12-19 18:13 <a href="http://m.shnenglu.com/bigsml/archive/2008/12/19/69856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BHO基础http://m.shnenglu.com/bigsml/archive/2008/12/04/68573.html泡?/dc:creator>泡?/author>Thu, 04 Dec 2008 09:26:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/12/04/68573.htmlhttp://m.shnenglu.com/bigsml/comments/68573.htmlhttp://m.shnenglu.com/bigsml/archive/2008/12/04/68573.html#Feedback0http://m.shnenglu.com/bigsml/comments/commentRss/68573.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/68573.htmlBHO是Browser Helper Object(览器辅助对?

BHO兌原理 (BHO兌的是SHDOCVW,也就是说不只兌IE,下面全部用IE来说?
1.IE的窗口打开?先寻找HKLM下的SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\ 里的CLSID,q些CLSID,都对应着相应的BHO插gQ然后根据这个CLSID到HKCR下的CLSIDs里找到此插g的信息,包括文g位置{?br>2.IEҎ扑ֈ的CLSID信息创徏 BHO 对象,q且查找 IObjectWithSite 接口. (q个接口非常?只有SetSite和GetSite两个Ҏ)
3.IE把IWebBrowser2(览器插?传到 BHO ?SetSite ҎQ用户在此方法中可挂载自q事g处理Ҏ?br>4.H口关闭?IE?null 传到 BHO ?SetSite ҎQ此Ҏ用来L挂蝲的事件处理方法?/p>

~写BHO程
1.创徏IObjectWithSite昑ּ接口Q创?COM cdQ实现承IObjectWithSite接口
2.实现此接口ƈ在SetSiteҎ里加上所要挂载的事g
3.处理事g
4.注册此BHO到注册表中HKLM下的Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects;(HKCR下的CLSIDs是根据上面的路径自动注册?
5?net 下须讄此BHO目?配置属性_>生成 中ؓInterop注册为TrueQ这h能将.net cd文g注册到COM

删除BHO
打开注册表项?HKLM下的Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects 可以看到下面有一些CLSID?q些值对应相关的插g,点击可以在默认值后看到相关插g的名U?可以复制相关CLSID到注册表中搜索相关CLSID,扑ֈ后打开InprocServer32可以看到相关文g的\?至于DLL文g{可以用UEDIT32.exe工具打开查看具体信息,当然也可以用修改E序cȝeXeScope.exe研究一?
h据具体情况删除相关键值和相关文g!

REF:
BHO 的编?nbsp;
VCKBase 关于IE ~程文档中心
C++中用BHO来屏蔽特定网?/a>
览器集成教?自定义浏览器



]]>
深入理解Effictive C++ "条款38: 决不要重新定义承而来的缺省参数? http://m.shnenglu.com/bigsml/archive/2008/10/06/63327.html泡?/dc:creator>泡?/author>Mon, 06 Oct 2008 09:19:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/10/06/63327.htmlhttp://m.shnenglu.com/bigsml/comments/63327.htmlhttp://m.shnenglu.com/bigsml/archive/2008/10/06/63327.html#Feedback1http://m.shnenglu.com/bigsml/comments/commentRss/63327.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/63327.html看条?8 的时候不是很理解, 于是写了个测试代?

#include<iostream> 
using namespace std; 

class A{
public:
    
virtual void show(int a=145)
    {
        cout
<<"A: a="<<a<<endl; 
    }   
}; 

class B: public A 

public
    
void show(int b)
    { 
        cout
<<"B: b="<<b<<endl; 
    } 
}; 
class C: public B 

public
    
void show(int c=999)
    { 
        cout
<<"C: c="<<c<<endl; 
    } 
};
class D: public C 

public
    
void show()
    { 
        cout
<<"D:\n"
    }
}; 

void main() 
{
    A 
*pp;
    A a; 
    B b; 
    C c; 
    D d;
    
    a.show();
    pp 
= &a;    pp->show();

    
// b.show();  // error C2660: 'B::show' : function does not take 0 arguments
    pp = &b;    pp->show();
    
    c.show();
    pp 
= &c;    pp->show();

    d.show();
    pp 
= &d;    pp->show();
    
    C 
*pc= &d;
    pc
->show();

    system(
"pause"); 
}   
输出l果?br>
A: a=145
A: a=145
B: b=145
C: c=999
C: c=145
D:
C: c=145
C: c=999

回顾条款 
虚函数是动态绑定而缺省参数值是静态绑定的.  Z么C++坚持q种有违常规的做法呢Q答案和q行效率有关。如果缺省参数D动态绑定,~译器就必须惛_法ؓ虚函数在q行时确定合适的~省|q将比现在采用的在编译阶D늡定缺省值的机制更慢更复杂。做U选择是想求得速度上的提高和实C的简便,所以大家现在才能感受得到程序运行的高效Q?

所?
a. 静态绑?.vs. 动态绑?
A *pp = new B;
q里 pp 静态绑定是 A* , 而动态绑定却?B*
B *pb = new B;
q里 pb 静态绑定和动态绑定是一L都是 B*

b. ~省值是静态绑定的, 而非动态绑?
所?
d.show() 输出 D:  因ؓshow ?D override

pp = &d;    pp->show();  
pp 被动态绑定到D *, 但是show 的缺省值却是A* ?145, 所以输出的?C: c=145, 而不?99 ( 函数 show 被C loverride ? 

?nbsp;C *pc = &d; pc->show() , pc 静态绑定ؓC*, 而动态绑定ؓ D* , 所以输出的?C: c=999 , 999 ?C* 静态绑定的~省?

c. 所以调用b.show 的时候出C如下的错?
    // b.show();  // error C2660: 'B::show' : function does not take 0 arguments
因ؓ B* 没有静态绑定的函数

l论是 决不要重新定义承而来的缺省参数?nbsp;

ref: 
从这里学了不?) http://bbs.chinaunix.net/viewthread.php?tid=439188 


]]>
觑IE 览器ActiveX 控g创徏q程http://m.shnenglu.com/bigsml/archive/2008/07/30/57550.html泡?/dc:creator>泡?/author>Wed, 30 Jul 2008 11:55:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/07/30/57550.htmlhttp://m.shnenglu.com/bigsml/comments/57550.htmlhttp://m.shnenglu.com/bigsml/archive/2008/07/30/57550.html#Feedback2http://m.shnenglu.com/bigsml/comments/commentRss/57550.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/57550.html1. Activex 控g是怎么安装?br>一个HTML 中嵌入控件的例子

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="400" height="300">
<param name="movie" value="flash/flash.swf">
<param name="quality" value="high">
<embed src="flash/flash.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="400" height="300"></embed>
</object>

当用IE 打开q个面的时? IE 首先Ҏ classid 在注册表?HKEY_CLASS_ROOT)查找其安装信? 如果未找? 则IE Ҏcodebase ȝ是否有对应的控g存在; 如果q是不行, 则会一些控件注册服务器联系(列表?HKLM\Software\Microsoft\Windows\CurrentVersion\Internet Settings\CodeBaseSearchPath 可以扑ֈ ), 一般是 http://activex.microsoft.com/objects/ocget.dll , http://codecs.microsoft.com/isapi/ocget.dll  , 然后服务器会告诉IE 从哪里去下蝲. 

FROM : http://oreilly.com/catalog/malmobcode/chapter/ch11.html


2. ActiveX 控g是如何启动的
创徏一个控件有很多U方?
CoCreateInstance, CoGetInstanceFromFile, CoGetInstanceFromIStorage
CoCreateInstanceEx
CoGetClassObjectFromURL , CoGetClassObject 
CoGetObject, DllGetClassObject {?
基本调用序好像?
(CoGetInstanceFromFile, CoGetInstanceFromIStorage ) -> CoCreateInstance
CoCreateInstanceEx
CoGetClassObjectFromURL -> CoGetClassObject 
其他没有试q?.. :9

IE 创徏控g的时候会调用 CoGetClassObjectFromURL -> CoGetClassObject 的顺序进? 而不是直接调?CoCreateInstance 或?CoCreateInstanceEx) , 但是免不了控件会自己调用 CoCreateInstanceEx, 比如Real 控g在创建的时候会调用Dx 的组件等.



]]>
获取IE (控g)的所有链?包括Frameset, iframe) http://m.shnenglu.com/bigsml/archive/2008/07/30/57548.html泡?/dc:creator>泡?/author>Wed, 30 Jul 2008 11:17:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/07/30/57548.htmlhttp://m.shnenglu.com/bigsml/comments/57548.htmlhttp://m.shnenglu.com/bigsml/archive/2008/07/30/57548.html#Feedback3http://m.shnenglu.com/bigsml/comments/commentRss/57548.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/57548.htmlIE 层 body 节点通过IHTMLElement->get_all Ҏ无法获取iframe 里面的节点列?

CComPtr<IHTMLElement> body;
 
CComPtr
<IDispatch> spDispCollection;
body
->get_all(&spDispCollection);

所以要获取iframe/frame(frameset) 里面的节点列表的? 则需要根据body/doc 扑ֈframes, 然后从frames -> IHTMLWindow2 -> IHTMLDocument2 . 主要?个方? 下面是代码片D?
Ҏ一:
IHTMLDocument2 *pDoc = 览器的Document(IWebBrowser2->IDispatch->IHTMLDocument2); 
IHTMLWindow2 
*pHTMLWnd = NULL; 
IHTMLDocument2 
*pFrameDoc=NULL; 
IHTMLFramesCollection2 
*pFramesCollection=NULL; 
LPDISPATCH lpDispatch; 

long p; 
VARIANT varindex,varresult; 
varresult.vt
=VT_DISPATCH; 
varindex.vt 
= VT_I4; 
if(pDoc!=NULL) 

    HRESULT hr
=pDoc->get_frames(&pFramesCollection); 
    
if(SUCCEEDED(hr)&&pFramesCollection!=NULL) 
    { 
        hr
=pFramesCollection->get_length(&p); 
        
if(SUCCEEDED(hr)) 
            
for(int i=0; i<p; i++
            { 
                varindex.lVal 
= i; 
                
if(pFramesCollection->item(&varindex, &varresult) ==S_OK) 
                { 
                    lpDispatch
=(LPDISPATCH)varresult.ppdispVal; 
                    
if (SUCCEEDED(lpDispatch->QueryInterface(IID_IHTMLWindow2, (LPVOID *)&pHTMLWnd))) 
                    { 
                        
if(SUCCEEDED(pHTMLWnd->get_document( &pFrameDoc))) 
                        { 
                            
//work with the pFrameDoc 
                        } 
                        pHTMLWnd
->Release(); 
                        pHTMLWnd
=NULL; 
                    } 
                } 
            } 
            pFramesCollection
->Release(); 
    } 
    pDoc
->Release(); 
}

Ҏ?
CComQIPtr<IHTMLElement> pElem = ; // 可以递归上面?CComPtr<IDispatch> spDispCollection 来得?
CComBSTR bstrTagName;
pElem
->get_tagName(&bstrTagName);
if ( lstrcmpiW(L"IFRAME", bstrTagName)==0 ||
        lstrcmpiW(L
"FRAME", bstrTagName)==0 )
{
    CComQIPtr
<IHTMLFrameBase2>    _framebase2;
    CComPtr
<IHTMLWindow2>        _framewindow;
    CComPtr
<IHTMLDocument2>        _framedoc;
    
    
if( (_framebase2 = spItem) 
        
&& SUCCEEDED( _framebase2->get_contentWindow(&_framewindow) ) && _framewindow!=NULL 
        
&& SUCCEEDED( _framewindow->get_document(&_framedoc) ) && _framedoc!=NULL )
    {
        
// ?nbsp;_framedoc 节点q行处理
    }
}


iframe 跨域讉K(cross frame)  zz from : http://codecentrix.blogspot.com/2007/10/when-ihtmlwindow2getdocument-returns.html 
׃安全性限? 为防止跨域脚本攻? 当frames 跨域的时? IHTMLWindow2::get_document 调用返?E_ACCESSDENIED .
下面函数 HtmlWindowToHtmlDocument  对于跨域的frame 通过 IHTMLWindow2 -> IID_IWebBrowserApp -> IHTMLWindow2 l过了限?

// Converts a IHTMLWindow2 object to a IHTMLDocument2. Returns NULL in case of failure.
// It takes into account accessing the DOM across frames loaded from different domains.
CComQIPtr<IHTMLDocument2> HtmlWindowToHtmlDocument(CComQIPtr<IHTMLWindow2> spWindow)
{
     ATLASSERT(spWindow 
!= NULL);

     CComQIPtr
<IHTMLDocument2> spDocument;
     HRESULT hRes 
= spWindow->get_document(&spDocument);
    
     
if ((S_OK == hRes) && (spDocument != NULL))
     {
          
// The html document was properly retrieved.
          return spDocument;
     }

     
// hRes could be E_ACCESSDENIED that means a security restriction that
     
// prevents scripting across frames that loads documents from different internet domains.
     CComQIPtr<IWebBrowser2>  spBrws = HtmlWindowToHtmlWebBrowser(spWindow);
     
if (spBrws == NULL)
     {
          
return CComQIPtr<IHTMLDocument2>();
     }

     
// Get the document object from the IWebBrowser2 object.
     CComQIPtr<IDispatch> spDisp;
     hRes 
= spBrws->get_Document(&spDisp);
     spDocument 
= spDisp;

     
return spDocument;
}


// Converts a IHTMLWindow2 object to a IWebBrowser2. Returns NULL in case of failure.
CComQIPtr<IWebBrowser2> HtmlWindowToHtmlWebBrowser(CComQIPtr<IHTMLWindow2> spWindow)
{
     ATLASSERT(spWindow 
!= NULL);

     CComQIPtr
<IServiceProvider>  spServiceProvider = spWindow;
     
if (spServiceProvider == NULL)
     {
          
return CComQIPtr<IWebBrowser2>();
     }

     CComQIPtr
<IWebBrowser2> spWebBrws;
     HRESULT hRes 
= spServiceProvider->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&spWebBrws);
     
if (hRes != S_OK)
     {
          
return CComQIPtr<IWebBrowser2>();
     }

     
return spWebBrws;
}


?
IE(控g/接口)中主要有4个部? Browser, Document, Frame/IFrame, Element , 其对应接口分别是
Browser         -    IWebBrowser2
Document      -    IHTMLDocument2
Frame/IFrame-    IHTMLWindow2
Element         -    IHTMLElement
可以通过下面Ҏ互相获取
browser      -> document        IWebBrowser2::get_Document
document     -> frame           IHTMLDocument2::get_parentWindow
frame        -> document        IHTMLWindow2::get_document
frame        -> parent frame    IHTMLWindow2::get_parent
frame        -> children frames IHTMLWindow2::get_frames
element     -> Frame             IHTMLElement->QI(IHTMLFrameBase2) -> IHTMLFrameBase2->get_contentWindow -> IHTMLWindow2

ref:
在多Frame的网中怎么取出各个Frame的IHTMLDocument2的接口!急用.(高分)
在文?When IHTMLWindow2::get_document returns E_ACCESSDENIED 解决了iframe 跨域讉K的问?



]]>
C/C++ 的预处理变量,??预定义宏http://m.shnenglu.com/bigsml/archive/2008/06/06/52363.html泡?/dc:creator>泡?/author>Fri, 06 Jun 2008 06:10:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/06/06/52363.htmlhttp://m.shnenglu.com/bigsml/comments/52363.htmlhttp://m.shnenglu.com/bigsml/archive/2008/06/06/52363.html#Feedback0http://m.shnenglu.com/bigsml/comments/commentRss/52363.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/52363.html== 预处理指?Preprocessor Directives) ==


== 预处理操作符(Preprocessor Operators) ==
Stringizing operator (#)
Causes the corresponding actual argument to be enclosed in double quotation marks
参数变成字W串 : #x -> "x"

Charizing operator (#@)
Causes the corresponding argument to be enclosed in single quotation marks and to be treated as a character (Microsoft Specific)
参数变成字W变?: #x -> 'x'

Token-pasting operator (##)
Allows tokens used as actual arguments to be concatenated to form other tokens
参数和前面的符L?: token##x -> tokenx


== 预定义宏(Predefined Macros) ==

__FILE__
__LINE__

#define LINE1(x) #x
#define LINE(x) LINE1(x)
#define TODO(msg)   message ( __FILE__ "(" LINE(__LINE__)  "): [TODO] " #msg )
#define NOTE(msg)   message ( __FILE__ "(" LINE(__LINE__)  "): [NOTE] " #msg )



]]>
zz 自定义浏览器控g http://m.shnenglu.com/bigsml/archive/2008/04/18/47547.html泡?/dc:creator>泡?/author>Fri, 18 Apr 2008 14:29:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/04/18/47547.htmlhttp://m.shnenglu.com/bigsml/comments/47547.htmlhttp://m.shnenglu.com/bigsml/archive/2008/04/18/47547.html#Feedback0http://m.shnenglu.com/bigsml/comments/commentRss/47547.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/47547.html同自动化览器(http://blog.joycode.com/jiangsheng/archive/2005/10/20/65489.aspxQ相比,自动化浏览器控g(WebBrowser Control) 在应用程序中更加常用。从Outlook的预览窗格到Maxthonq样的基于IE引擎的浏览器Q从无界面的HTML分析器到Norton Antivirusd的主界面Q浏览器控g在众多领域被用作各种各样的用途。这也得有必要Ҏ具体的用户需求自定义览器控件的行ؓ?/p>

在应用程序中加入览器控?/h1>

集成览器控件的最单的Ҏ是找一个支持ActiveX的集成开发环境,在工L中加入Microsoft Web Browserq个控gQ往表单上拖一个这个控件就可以完成工作。你甚至可以用集成开发环境添加ActiveX的事件处理函数。如果要直接导入ActiveX的话Q徏议用mehrcpp的vbMHWB控gQ?a >http://www.codeproject.com/atl/vbmhwb.aspQ。这个控件在览器控件的基础上进行了扩展Q暴露了很多底层接口?/p>

通常导入ActiveX可以满_部分需?nbsp; Q但是有些类库中也集成了览器控Ӟq且提供了更多的功能Q例如MFC的CHTMLView和CDHtmlDialogQATL的HTML ControlQ以?Net 2.0中的Windows.Forms.WebBrowser。如果用Visual C++来进行非托管~程Q那么徏议用MFC或者ATL的封装类Q或者用vbMHWB控g。托编E中当然首选Windows.Forms.WebBrowser。除非这些类的BUG影响C应用E序的开发,否则使用q些功能更加强大的封装类?/p>

在用浏览器控g及其装cȝ时候要注意一些已知问?/p>

常见d

在集成浏览器控g之后Q可以完成基本的|页览Q但是对于不同的dQ也需要进一步的处理Q例如设|控件的属性、ؓ控gd事g处理、操作HTML文档{等?/p>

修改览器控件的属?

q在集成开发环境中可以很容易地讄Q也可以自己实现容器来设|,但是CHTMLViewq样的封装类没有q个选项Q?a >http://support.microsoft.com/kb/197921Q?/p>

  • 链接目标解析。对于用览器控件来做浏览器的场合来_需要将览器的RegisterAsBrowser属性设|ؓtrue。这使得Internet Explorer在解析HTML链接的target属性指定的目标H口时可以找到这个窗口?
  • 用拖放。对于用浏览器控g来做预览H格的场合来_需要将览器的RegisterAsDropTarget属性设|ؓfalse。这使得H口不接受拖q来的文件和链接?
  • 用消息框。对于用览器控件来做HTML分析器的场合来说Q有旉要屏蔽脚本生的消息框以避免dE序q行。这可以通过讄览器的Silent属性来实现Q或者实现IDocHostShowUI::ShowMessage?

捕获览器控件的事g

集成开发环境中可以也很Ҏ地添加浏览器的事件处理函数。比较常用的事g包括

  • NewWindow2或者NewWindow3事g。默认情况下Q浏览器控g中创建的新窗口会是一个Internet Explorer的窗口。这通常不是预期的行为,对于览器程序来说更是这栗需要处理浏览器的NewWindow2或者NewWindow3Q在Windows XP SP2或者Windows 2003 SP1之后可用Q事件来让新的浏览器H口在应用程序提供的H口中运行?
  • WindowClosing事g。浏览器控g需要处理WindowClosing事g来在览器控件被脚本关闭时关闭浏览器控g的宿ȝ口(http://support.microsoft.com/kb/253219Q?
  • BeforeNavigate2事g。可以在自己的网中加入自定义的协议Q之后在BeforeNavigate2事g中扫描URL来进行网和应用E序之间的交互(http://www.microsoft.com/msj/0100/c/c0100.aspxQ。当Ӟ自定义的|络协议也可以用Asynchronous Pluggable Protocol来处?参见http://support.microsoft.com/kb/303740)QvbMHWB控g实Cq个功能。但是更加常用的是在弹出q告qo器程序中用BeforeNavigate2来判断在NewWindow2事g中创建的H口是否需要关闭?

操作MSHTML文档

通常HTML分析和浏览器自动化程序都需要分析网늚l构Q找到需要操作的元素。这需要对|页的结构进行分析,扑ֈ目标元素的标识方法?一些常用的操作包括Q?

  • 讄HTML元素的属性,例如html、style、value{等。注意有些属性是只读的,甚至是程序无法访问的Q例如input元素在类型ؓ文g时其value属性不可访问)?
  • 分析|页的结构来保存|页数据Q例如拆取Web 一文介l的ҎQ?a >http://www.microsoft.com/china/msdn/Archives/workshop/scrape.aspQ?
  • 处理HTML元素的事件。这需要分析浏览器控g中的MSHTML文档对象Q定位被操作的元素,以及在元素的q接点上挂接自定义的事g处理E序(http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/tutorials/sink.asp)?
  • d/删除HTML元素。注意设|有时设|outHtml属性ƈ不能正确创徏元素Q?a >http://support.microsoft.com/kb/185140Q,一个的Ҏ是用HTMLDocument对象的CreateElememtҎ?
  • 调用HTML元素的方法,q和在脚本中操作HTMLcM。可操作的元?接口可以参考Interfaces and Scripting ObjectsQ?a >http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/ifaces/interface.aspQ,操作Ҏ可以参考Introduction to Dynamic HTMLQ?a >http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/ifaces/interface.aspQ?
  • 以上的功能都可以通过直接在网中加入脚本实现Q?a >http://support.microsoft.com/kb/185128Q,而且脚本也可以通过应用E序实现的扩展接口来和应用程序本w交互。另外,脚本q可以被用来自定义一些事Ӟ例如在需要重载自定义的ShowModalDialog的时候就可以用IDispatchExlwindow对象d一个属性,其gؓ一个自定义的ShowModalDialog函数(http://groups.google.com/group/microsoft.public.inetsdk.programming.webbrowser_ctl/browse_thread/thread/e5eeb4a9111b16af/4bc2709aeb2bb444?lnk=raot)Q也可以用加入脚本的办法来捕L中的错误(http://support.microsoft.com/kb/317024Q?

 在页面包含框架的时候,可能需要跨框架讉KHTML文档。可以通过查询框架元素所支持的IWebBrowser2接口或者IHTMLWindow2接口来访问框架中的文档(http://support.microsoft.com/kb/196340Q,但是也有可能因ؓ安全讄而无法访?http://support.microsoft.com/kb/167796)?/p>

在浏览器控g中显C其它类型的文档Ӟ可以用IWebBrowser2的document属性来讉KActiveX文档Q例如在昄Microsoft WordӞIWebBrowser2的document属性就是Word的文档对象,在显C文件夹的时候,IWebBrowser2的document属性就是文件夹对象{等?/p>

扩展览器的宿主

览器控件在创徏时会查询ActiveX容器的IOleClientSite的实现的如下接口Q?strong>IDocHostUIHandler, IDocHostUIHandler2 and IDocHostShowUI?/p>

虽然在无法自定义ActiveX容器的情况下可以用ICustomDoc::SetUIHandler来挂接IDocHostUIHandler到浏览器控gQ但是这样也会造成内存泄漏Q?a >http://support.microsoft.com/kb/893629Q。一些类库,例如MFC、ATL?Netcd都实CIDocHostUIHandler接口?/p>

除了专门用于览器用途的E序之外Q通常都需要自定义览器控件的上下文菜单。这需要实现IDocHostUIHandler::ShowContextMenu。通常的实现包括完全禁用上下文菜单、完全替换上下文菜单、以及修攚w分上下文菜单。经常被从上下文菜单中移除的菜单包含查看源代码、刷新和属性。一U替代的Ҏ是在容器中过滤右键消息(http://support.microsoft.com/kb/231578Q?/p>

与浏览器相比Q一些Internet Explorer的宿d能在览器控件中q不是默认启用。在某些场合Q默认启用的宿主功能可能q预期。这旉要实现IDocHostUIHandler::GetHostInfo。可以通过实现IDocHostUIHandler::GetHostInfo来自定义的功能包括:

  • 自动完成功能。对于用览器控件来做浏览器的场合来_q个功能是有必要启用的。启用的Ҏ是设|DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE?
  • 如果览器中的链接网址包含非ASCII的字W,那么需要实现IDocHostUIHandler::GetHostInfoQƈ且在q回的DOCHOSTUIINFOl构中设|dwFlags成员的DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8位。这使得|址会在发送之前用UTF-8~码?
  • 3DҎ、滚动条Q禁用文字选择功能和禁用页面上的脚本?
  • 对于使用览器控件来做HTML~辑器的场合来说Q有旉要修攚w认的面样式。这都需要实现IDocHostUIHandler::GetHostInfoQ?a >http://support.microsoft.com/kb/328803Q。注意在有些版本的IE中IDocHostUIHandler::GetHostInfo只在MSHTML被初始化的时候被调用Q所以如果你需要在MSHTML被初始化之后使你的修改生效,你需要浏览到一个Word之类的非HTML Active document文档Q之后再览回来?

在用浏览器控g来做数据录入界面的场合,需要更Ҏ览器控g默认的Tab键处理得用户可以用Tab键切换到容器中的其他控g。这需要实现IDocHostUIHandler::TranslateAccelerator来自定义览器控件的快捷键处理。对于MFCq样用消息钩子来做消息预处理的可自定义容器来_也可以用PreTranslateMessage来过滤F5键盘消息Q而不是实现IDocHostUIHandler::TranslateAccelerator?

在脚本中调用应用E序Ҏ览器控g的扩展,q需要实现IDocHostUIHandler::GetExternal。?Net的WebBrowser控g的话讄ObjectForScripting属性就可以了?/p>

对于用浏览器控g来做HTML分析器的场合来说Q有旉要屏蔽脚本生的消息框。这需要实现IDocHostShowUI::ShowMessageQ或者设|浏览器的Silent属性?/p>

另外Q浏览器也会查询IOleClientSite来获得其它的服务信息Q例?/p>

  • IOleCommandTargetQ查询控件的容器是否提供替代的命令处理,见拙作Hook DHTML Commands一文(http://blog.joycode.com/jiangsheng/archive/2005/07/09/58754.aspxQ?
  • IServiceProvider。此接口被用于查询用户对如下接口的实玎ͼ
    • IInternetSecurityManager Q用户可实现此接口来自定义浏览器控g的安全相关选项Q?a >http://msdn.microsoft.com/workshop/security/szone/overview/impl_secmanager.aspQ?
    • IDownloadMamanger Q用户可实现此接口来自定义浏览器控g的下载过E?
    • IAuthenticateQ用户可实现此接口来自定义一些登录界面(http://support.microsoft.com/kb/329802Q?
    • INewWindowManagerQ用户可实现此接口来重蝲Windows XP SP2和Windows 2003 SP1中新增的弹出H口理器的行ؓ

其他控制

对于用浏览器控g来做HTML分析器的场合来说Q有旉要禁用浏览器的脚本、ActiveX或者图片下载。这可以通过在容器中实现IDispatchQ处理DISPID_AMBIENT_DLCONTROL来做刎ͼhttp://msdn.microsoft.com/library/default.asp?url=/workshop/browser/overview/Overview.aspQ?/p>

看来ȝ览的控制ƈ不能用这U方法来控制Q?a >http://support.microsoft.com/kb/247336Q。不q你可以自己~写一个HTTP层传?BINDF_OFFLINEOPERATION标志 Q?a >http://groups-beta.google.com/group/microsoft.public.inetsdk.programming.mshtml_hosting/msg/76bf4910a289d4b3Q?/p>

在浏览器控g中java程序可能不能正常运行,如果使用Sun JVM1.4之后的版本,可以用SetEnvironmentVariable 来设|JAVA_PLUGIN_WEBCONTROL_ENABLE?来启用Sun JVM?/p>

默认情况下在面载入时会有点d。屏蔽点d的一个方法是在程序运行时修改注册表键Q?a >http://support.microsoft.com/kb/201901Q,另一个方法是浏览器控g隐藏Q在调用Navigate2之后再显C,但是q也需要锁定控件的更新区域QLockWindowUpdateQ以避免闪烁。在IE7中,也可以调?CoInternetSetFeatureEnabled函数Q传递FEATURE_DISABLE_NAVIGATION_SOUNDS来禁用浏览时的声韟?/p>

在需要用代理服务器Ӟ有可能需要在应用E序中用非默认的代理服务器讄。这可以通过调用UrlMkSetSessionOption来实现?br>
Overriding IInternetSecurityManager in a CComControl class
CAxWindow implements IObjectWithSite interface (get it with QueryHost
method). Call SetSite passing your implementation of IServiceProvider.
At this point, AxWin will forward all QueryService calls from hosted
WebBrowser to your implementation.



]]>
ie d监测http://m.shnenglu.com/bigsml/archive/2008/04/18/47528.html泡?/dc:creator>泡?/author>Fri, 18 Apr 2008 11:49:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/04/18/47528.htmlhttp://m.shnenglu.com/bigsml/comments/47528.htmlhttp://m.shnenglu.com/bigsml/archive/2008/04/18/47528.html#Feedback1http://m.shnenglu.com/bigsml/comments/commentRss/47528.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/47528.html对ie 的攻d好几c? 有修改主? 弹出H口, 恶意插g, |页木马{? 其中一些是利用了ie 的脚本的自带功能, 而另外一些要对ie 实施d后才能做? 主要手段有利用第三方软g漏洞, ie 堆喷等, 文章 [ [JavaScript中的堆风水]|[ http://www.team509.com/download/Heap%20Feng%20Shui%20in%20JavaScript_en_cn.htm ] ] 对堆喷射q行了介l? 主要是利用覆盖函数返回地址或者对象的虚函数表来执行shellcode, 主要涉及到ie & pȝ的内存管?
一般shellcode 基本只完成攻d? 具体的对pȝ的后l攻击肯定离不了下蝲执行 exe 文g{动? q且在攻击ie 也会有各U症? 可以Ҏq些基本实现恶意代码.

1. Ҏie 症状
当ie 讉K恶意面的遭受攻L, 光要表现是
a. 内存使用
b. cpu 使用?br>所以实时监这些参数可以基本判断是否有d


2. Ҏ行ؓ
shellcode 如果被执? 那么肯定会进行木马下载执行等步骤. 一般纯shellcode 里面的内容不会很? 所以不可能完成很多复杂的攻?
win32 创徏q程的API调用串是:
WinExec/ShellExecuteA/CreateProcessA->CreateProcessInternalA->CreateProcessInternalW->ZwCreateProcessEx
?br>CreateProcessW->CreateProcessInternalW->ZwCreateProcessEx

win32 要执行下载的API 主要是wsock32.dll ?
recv , recvfrom

所以对上述API q行拦截, 一般可以检到是否有ie 是否被攻? 但是q个只能在攻L功后, shellcode 执行后才能被到

3.
拦截一些操作注册表, 创徏H口{API , 可以做到防止被修改主? 弹出H口{?

 

利用ms 的Detours 可以很容易的实现对系l?API 的hook
http://blog.csdn.net/hu0406/archive/2008/03/05/2150358.aspx
http://blog.csdn.net/hu0406/archive/2008/03/05/2150351.aspx
http://www.moon-soft.com/doc/2288.htm
http://blog.csdn.net/dedodong/archive/2006/10/07/1323925.aspx

[ [JavaScript中的堆风水]|[ http://www.team509.com/download/Heap%20Feng%20Shui%20in%20JavaScript_en_cn.htm ] ] ie 堆喷?

[ [也聊inline-hook]|[ http://blog.tom.com/tigerkings941220/article/9211.html ] ] 介绍?q程自n保护(通过拦截LoadLibraryW)和IE漏洞防护(通过拦截CreateProcessInternalW)

[ [maxthon2(遨游2) mxsafe.dll对网|马的防护以及l过]|[ http://hi.baidu.com/54nop/blog/item/b52cff6e713964d980cb4a9e.html ] ] 讨论了maxthon2 防止|页木马的策? 拦截 ZwCreateProcessEx/ZwCreateProcess, ZwWriteVirtualMemory, LoadLibraryExW, CreateProcessInternalW )以及Ҏ{略, 其实q个只是hook & unhook 的游戏了..

[ [议PE病毒技术]|[ http://blog.vckbase.com/windowssky/archive/2007/04/17.html ] ] 介绍?pe 病毒 & win32 q程加蝲内部

[ [360安全卫士E序员志愿者]|[ http://blog.csdn.net/dedodong/archive/2006/10/07/1323925.aspx ] ] 通过拦截 NtCreateProcessEx/NtCreateProcess 实现?""~写一个程序,在此E序中运行a.exeQƈ使得a.exe认ؓ是由explorer.exeq行它的"""

[ [d恶意软g--清除和保护你的网站的技巧]|[ http://www.googlechinawebmaster.com/labels/badware.html ] ] google 上的Ҏ意Y?badware) 的介l?

[ [StopBadware Blog]|[ http://blogs.stopbadware.org/articles/2007/11 ] ]


 



]]>
Windows Winnet 实现HTTP 文g断点l传下蝲http://m.shnenglu.com/bigsml/archive/2008/04/17/47449.html泡?/dc:creator>泡?/author>Thu, 17 Apr 2008 15:01:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/04/17/47449.htmlhttp://m.shnenglu.com/bigsml/comments/47449.htmlhttp://m.shnenglu.com/bigsml/archive/2008/04/17/47449.html#Feedback0http://m.shnenglu.com/bigsml/comments/commentRss/47449.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/47449.html1. MFC 下蝲文g

?U方?
a)
创徏CInternetSession 对象 -> 调用 CInternetSession::OpenURL 该函数解析URLQ然后打开与URL指定的服务器q接Q同时返回一个只ȝCInternetFile对象 -> CInternetFile::Read d文g -> 析构CInternetSession

b)
创徏CInternetSession 对象 -> 调用 CInternetSession::GetHttpConnection
q回CHttpConnection 对象 -> 调用CHttpConnection::OpenRequest 创徏一个CHttpFile对象 -> CHttpFile::SendRequest 发送连接请?-> CHttpFile::QueryInfo 获取HTTP 信息(比如文g大小, ETAG{? | CInternetFile::Read d文g ->  析构CInternetSession

在上q过E中, 如果出现错误会抛?CInternetException 异常
另外在打开链接? 可以q行如下讄
CInternetSession::SetOption    d或设|?InternetQuery 选项 (如超时或重试ơ数Q?br>CInternetSession::EnableStatusCallback 讄回调函数监视session状?br>CHttpFile::AddRequestHeaders   讄HTTP h?需要在CHttpFile::SendRequest 前调?


2. 实现断点l传
断点l传其实是通过在HTTP h头中讄要下载的文g区间来实? 一个典型的HTTP h头是

  GEThttp://class/download.microtool.de:80/somedata.exe 
  Host:download.microtool.de
  Accept:*/*
  Pragma:no-cache
  Cache-Control:no-cache
  Referer:http://class/download.microtool.de/
  User-Agent:Mozilla/4.04[en](Win95;I;Nav)
  Range:bytes=554554-
 
注意最后一行:Range:bytes=554554-Q格式ؓ:Range: bytes=起始位置 - l止位置Q也是_我们可以通过讄Httph头的讄起始l束位置Q来获取HTTP文g的某一部分?


3. Win32 WinInet API 实现
和MFC 的函数对? 执行下蝲操作大致需要的函数有:

InternetOpen是最先调用的函数Q它q回HINTERNET句柄Q习惯定义ؓhSessionQ即会话句柄, 相当于CInternetSession
InternetConnect使用hSession句柄Q返回的是httpq接句柄Q定义ؓhConnect, 相当?CInternetSession::GetHttpConnection
HttpOpenRequest使用hConnect句柄Q返回的句柄是httph句柄Q定义ؓhRequest, 相当?CHttpConnection::OpenRequest
HttpSendRequest(相当?CHttpFile::SendRequest)、HttpQueryInfo、InternetSetFilePointer和InternetReadFile都用HttpOpenRequestq回的句柄,即hRequest?/p>

CInternetSession::OpenURL 相当于实C InternetConnect & HttpOpenRequest & HttpSendRequest 3个函?

当这几个句柄不再使用Ӟ应该用函数InternetCloseHandle把它关闭Q以释放其占用的资源?


用WinInet开发Internet客户端应用指南(一Q?/a>  http://www.vckbase.com/document/viewdoc/?id=545
用WinInet开发Internet客户端应用指南(二) http://www.vckbase.com/document/viewdoc/?id=546
使用 CInternetSession 装多线E?http 文g下蝲 http://www.vckbase.com/document/viewdoc/?id=1693
Http下蝲的断点箋?/a>       http://sunyan331.spaces.live.com/blog/cns!89B9F8BF2575E281!947.entry
HTTP服务器上断点下蝲文g(里面有很不错的源?      http://www.cnitblog.com/wangk/archive/2007/05/22/5942.html
~写断点l传和多U程下蝲(有源?   http://www.bbbh.org/20060427/2620/
WinInet: implementing resuming feature  http://www.clevercomponents.com/articles/article015/resuming.asp
(很详l的一个代码解?Retrieving a file via. HTTP  http://www.codeproject.com/KB/IP/getwebfile.aspx 



]]>
MSNP协议的通信q程[En] http://m.shnenglu.com/bigsml/archive/2008/03/23/45178.html泡?/dc:creator>泡?/author>Sun, 23 Mar 2008 05:13:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/03/23/45178.htmlhttp://m.shnenglu.com/bigsml/comments/45178.htmlhttp://m.shnenglu.com/bigsml/archive/2008/03/23/45178.html#Feedback0http://m.shnenglu.com/bigsml/comments/commentRss/45178.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/45178.htmlYou have been using MSN for quite some time wondering how it works. Well You need not look any further. This article will not just tell you how MSN works but will also tell you how to make your own version of MSN messenger. You can download a sample application from here MSN Clone .Let's get ready to rumble!!!!

 

We can split up the working of MSN messenger into 2 phases

  • Authentication Phase

  • Instant Messaging Phase

The Authentication Phase involves logging into the MSN messenger server and also (friends) list retrieval in this case.

The Instant Messaging Phase involves sending/accepting requests for an Instant Messaging session and also sending/receiving messages.

 

The MSN messenger protocol is an ASCII based protocol. In other words the commands are in pure English !!!.The first phase involves connecting to an MSN messenger server .In this case we shall connect to the server 64.4.13.58 on port 1863(MSN messenger works through port 1863).

Once the connection is done we need to start the log in process. The first stage in this phase is the versioning stage. In this stage the client (in this case your app) lists/sends the versions that it can support to the server and waits for the server to respond.

VER 0 MSNP7 MSNP6 MSNP5 MSNP4 CVRO

In the MSN messenger protocol a "trial id" is sent along with every command. The trial id starts from 0 and is incremented every time the server responds successfully to the client's commands.

 

The server responds like this

VER 0 MSNP7 MSNP6 MSNP5 MSNP4

The Client and the server have agreed on a version in which they will communicate.

 

Next the client sends a request to the server asking it for the name of the security package it supports for authentication.

INF 1

Unlike Yahoo, Rediff and a few other Messengers MSN does not actually send the password as it is.It encrypts the password while sending it ensuring that your password will not be leaked out easily if somebody monitors your port.

 

The server responds with this

INF 1 MD5

Here MD5 is the name of the security package which the server currently supports.

Next the client sends the userid to the server

 

USR 2  MD5  I  venky_dude@hotmail.com

Here the server does a check whether it contains all the relevant details about the user for authentication .If it does not then it sends the following reply

 XFR 2  NS 64.4.13.55:1863  0

What the server says is that the client should connect to the Notification Server(NS) on 64.4.13.55 on port 1863. We close the current connection and repeat the  steps while being connected to the new server i.e  64.4.13.55

  • (client)   VER 3 MSNP7 MSNP6 MSNP5 MSNP4 CVRO

  • (server) VER 3 MSNP7 MSNP6 MSNP5 MSNP4 

  • (client)   INF  4

  • (server) INF  4  MD5

  • (client)  USR  5  MD5 I venky_dude@hotmail.com

Now the server to which we are connected to has the relevant information about the user trying to log in. The server replies this way

USR 5  MD5  S 989048851.1851137130

 The string which is sent by the server is the " MD5 Hash". It is a hash generated by the server and is used in the authentication process. The client then has to send the password which is encrypted using the MD5 algorithm.In effect the client has to send the unique MD5 equivalent of the MD5 hash i.e 989048851.1851137130 in this case and the password combined .i.e. MD5 equivalent of (hash+pass). In this case it turns out to be 3b7926d277068ec49576a0c40598ff21.

USR 6 MD5 S 3b7926d277068ec49576a0c40598ff21

If the password is right then the server replies with this

USR 6 OK venky_dude@hotmail.com venkat

Here the last word is the nickname/name by which the user is known.

In the new version of the protocol (MSNP7) the server sends additional data like some general information about the user and a authentication code something similar to a cookie which can be used for various other functions.

 

MSG Hotmai Hotmail 362
MIME-Version: 1.0
Content-Type: text/x-msmsgspro file; charset=UT
LoginTime: 1011252477
EmailEnabled: 1
MemberIdHigh: 84736
MemberIdLow: - 1434729391
lang _preference: 103
preferredEmai l: venky_dude@hotmail.com
country: IN
PostalCode:
Gender: M
Kid:0
Age: 22
sid: 517
kv: 2
MSPAuth: 2AAAAAAAADU0p4uxxxJtDJozJSlUTS0i7YpwnC9PUHRv56YKxxxCTWmg$$

Now we are logged into the server but our status is still offline. We need to change our status to online in order to send and receive messages. The client does this in the following way

CHG 7 NLN

The server replies with friends who are online and in various states.

CHG 7 NLN

ILN 7 NLN btxxxe@hotmail.com nick
ILN 7 AWY wmpyxxx@msn.com mike
ILN 7 BSY tehpxxpxx@hotmail.com yeaxxx

MSG Hotmail Hotmail 223
MIME-Version: 1.0
Content-Type: text/x-msmsgsinitialemailnotification; charset=UTF-8

Inbox-Unread: 293
Folders-Unread: 0
Inbox-URL: /cgi-bin/HoTMaiL
Folders-URL: /cgi-bin/folders
Post-URL: http://www.hotmail.com

 

The next command to be sent to the server pertains to the version of the client currently being used.The client send to the server it's version number and also information about the machine like the OS and the build.

CVR 8 0x0409 win 4.10 i386 MSMSGS 4.5.0127 MSMSGS

Here 0x409 win 4.10 i386 specifies that the client is running win98 on a intel microprocessor, and MSMSGS 4.5.0127 MSMSGS here specifies the version and build no of msmsgs.exe (basically the version no of MSN messenger).

The server responds with the url to download the latest version and some other info

CVR 8 4.5.0127 4.5.0127 1.0.0863 http://download.microsoft.com/download/msnmessenger/install/4.5/win98me/en-us/mmssetup.exe http://messenger.microsoft.com

 

It is not necesarry to send the CVR command, the messenger protocol will function properly regardless of this command being sent

 

To get a list of people who are in our friends list we may send this command

LST 9 RL

On sending this command the server will reply by sending the reverse list .The reverse list is basically a list of users who can see you when you are online and send you a message.You could alternatively also request for the forward list by sending LST 9 FL .The forward list contains a list of all users whom the user has added to his/her list.

The server responds this way

LST 9 RL 69 1 19 venky_dude@hotmail.com venkat
LST 9 RL 69 2 19 puxxxxx@hotmail.com PUJA
LST 9 RL 69 3 19 vancxxxxx@hotmail.com ramachandran
LST 9 RL 69 4 19 moxxxxx@hotmail.com chandramouli
LST 9 RL 69 5 19 v_n_xxxxx@hotmail.com Narayanaswamy
LST 9 RL 69 6 19 dexxxxx@hotmail.com Venkatesh
LST 9 RL 69 7 19 lousydxxxxx@hotmail.com deepika%20kalyani%20Vairam                                                  LST 9 RL 69 8 19 hexxxxxr@hotmail.com Hetchar%20Ramachandran
LST 9 RL 69 9 19 ambxxxxx@hotmail.com Aiyer
LST 9 RL 69 10 19 suxxx@hotmail.com Ganesh
LST 9 RL 69 11 19 deexxxxx@hotmail.com Deepak
LST 9 RL 69 12 19 anilxxxxx@hotmail.com anil
LST 9 RL 69 13 19 dixxxxx@hotmail.com <Diamond>
LST 9 RL 69 14 19 nvxxxx@hotmail.com giri
LST 9 RL 69 15 19 shxxx@hotmail.com Hari
LST 9 RL 69 16 19 radhikashuxxxxx@hotmail.com radhika
LST 9 RL 69 17 19 eskaxxxxx@hotmail.com kannan
LST 9 RL 69 18 19 shaxxxxx@hotmail.com Shankar
LST 9 RL 69 19 19 puneetagarxxxxx@hotmail.com puneet

 

 

*Every time a friend comes online the server(NS) sends us the following command

NLN 10NLN deaxxxx@hotmail.com Venkatesh

and when the friend goes offline the server sends us this

FLN 10 FLN deaxxxx@hotmail.com

With the MSNP7 protocol msn has introduced a new challenege authentication mechanism. The MSN server sends t a challenge key which the user has to authenticate succesfully in order for the session to continue.

CHL 0 20881396011366812350

 

The client has to send the md5 equivalent of this string which is formed by appending this hash with the string "Q1P7W2E4J9R8U3S5".So the final string which will be sent to the server will be the md5 equivalent of 20881396011366812350Q1P7W2E4J9R8U3S5

i.e MD5string(20881396011366812350Q1P7W2E4J9R8U3S5 )

So the client response would be something like this

QRY 18 msmsgs@msnmsgr.com 32
0212eaad0876afb8505859ca75d21a78

Here 18 is the trial id .Replace it by the appropriate trial id in your program .

The server will respond in the following way if the authentication is right

QRY 18

We have successfully logged into the MSN Messenger server. The Instant Messaging phase is next.






Instant Messaging in MSN Messenger is session based . The people in between whom the conversation is going to take place have to be in a session mode. We cannot send/receive messages unless we start a chat session with a user. 

There are basically two methods in  which a user can be in a chat session                                                           

  • User sends a chat session request to another user
  • User receives a chat session request from another user

 

User sends a chat session request

 

The client(user) sends a command to the server asking it for the address of the SwitchBoard(SB) server. All instant messaging conversation take place via the switchboard server.

XFR 9 SB

The server(SB) replies back with the ip address of the switchboard server(SB),the port on which to connect and a CKI hash. CKI is a security package and the client has to use the hash to connect to the switchboard server.

 XFR 9 SB 64.4.13.88:1863 CKI 989487642.2070896604     

Now we have to make another  new connection this time to the switchboard server. Our previous connection to the MSN messenger server  must be kept as it is. If we lose connection with that server we would log out.

After we have connected to the switchboard server(SB) we send the following command to the switchboard server.

USR 1 venky_dude@hotmail.com  989487642.2070896604  

If the CKI hash sent by us is right the server(SB) responds back with this

USR 1 OK venky_dude@hotmail.com venkat

After this has been done the user has to "Call" the other user to the chat session. This is done by sending the following command.

CAL 2 deadxxx@hotmail.com 

The server replies back with the a session id which it will pass on to the other user

CAL 2 RINGING 11717653

When the other user replies and is ready for a chat the server(SB) sends us this command

JOI deadlee@hotmail.com Venkatesh

This indicates that the other user has joined in the conversation and we are now ready to send and receive messages.

 

User receives a chat session request

When we are being invited to a chat session by a user the server(NS) send us the following message.

 

RNG 11742066 64.4.13.74:1863 CKI 989495494.750408580 deaxxxx@hotmail.com Venkatesh

Here the server(NS) sends us the session id ,the ip address of the SwitchBoard server to connect to,the port on which to connect to ,the CKI hash and the user trying to start a conversation with us.

Now we have to make another  new connection this time to the switchboard server. Our previous connection to the MSN messenger server  must be kept as it is. If we loose connection with that server we would log out.

We  connect to the switchboard server and send the following command

ANS 1 venky_dude@hotmail.com 989495494.750408580 11742066

Here we send our login name ,the CKI hash that was sent to us and the session Id that was sent to us

The server responds back with 

IRO 1 1 1 deaxxxx@hotmail.com Venkatesh

and

ANS 1 OK

We are now ready to send and receive messages.

 

Before sending/receiving messages let us see how the message is constructed.

When we are sending a message we build the header information  in the following way

MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-MMS-IM-Format: FN=Microsoft%20Sans%20Serif; EF=; CO=0; CS=0; PF=22

While sending a message we send it this way

MSG  2  N 137                                                                                                                                                            MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-MMS-IM-Format: FN=Microsoft%20Sans%20Serif; EF=; CO=0; CS=0; PF=22

hello

Here 2 is the trial id which has to incremented each time we send a message. 137 is the total length of the message i.e length of the header and length of the actual message that we are sending in this case it is 'hello'.

 While receiving the message it is more or less similar

Here is an example of a message received

MSG deaxxxx@hotmail.com Venkatesh 137
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-MMS-IM-Format: FN=Microsoft%20Sans%20Serif; EF=; CO=0; CS=0; PF=22

hello

 

When the other user is typing a message we receive the foll message

MSG deaxxxx@hotmail.com Venkatesh 100
MIME-Version: 1.0
Content-Type: text/x-msmsgscontrol
TypingUser: deaxxxx@hotmail.com

 

I guess now u guys are well on your way to make your own version of  MSN messenger.Post your doubts/comments/message in the Forumn .Do visit my projects page for some cool vb & c++ codes

 I'll keep adding to the protocol ,will try to put in addition functions like add/remove users ,rename user id,file transfer and voice chat, so keep checking back

 

References:

You could take a look at these sites for more information

This is the original protocol published by microsoft.

http://www.tlsecurity.net/Textware/Misc/draft-movva-msn-messenger-protocol-00.txt

This is the MD5 homepage where u can find programs/codes for doing the MD5 encryption

http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html


MSNP10协议分析 01.d [by progsoft]
http://blog.csdn.net/progsoft/archive/2004/08/24/82938.aspx

MSN协议中文释义(Zz)
http://blog.csdn.net/fanccYang/archive/2005/03/16/321198.aspx

MSN Protocol Version 8
http://msnpiki.msnfanatic.com/index.php/Main_Page
介绍了MSNP 的整个协?& 服务?Notification Server (NS)  & Switchboard (SB)  的功?

MSN Messenger Protocol Version 9
http://zoronax.bot2k3.net/
很详l的介绍, 里面q有原始包例?

MSN Messenger Protocol
http://www.hypothetic.org/docs/msn/client/invitation_types.php
MSNP 的详l命令介l?br>
Reverse-engineering MSN Messenger's Video Conversation Formats[Ramiro Polla]
http://www.libing.net.cn/read.php/1031.htm



]]>
IE 异步可插入协议扩?http://m.shnenglu.com/bigsml/archive/2008/03/23/45145.html泡?/dc:creator>泡?/author>Sat, 22 Mar 2008 16:38:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/03/23/45145.htmlhttp://m.shnenglu.com/bigsml/comments/45145.htmlhttp://m.shnenglu.com/bigsml/archive/2008/03/23/45145.html#Feedback1http://m.shnenglu.com/bigsml/comments/commentRss/45145.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/45145.html可插入协议扩展(Asynchronous Pluggable ProtocolsQ主要基于异步的URL Moniker技术?IE的URL Moniker在urlmon.dll 动态库中实现的Q?有两U处理机Ӟ
1. ҎURL 协议调用外部E序处理
比如telnet: or news: or mailto:Q当讉Kq些url的时候会打开相应的程序来处理?br>比如要添加note:协议(Registering an Application to a URL Protocol), 则只要修Ҏ册表
[HKEY_CLASSES_ROOT]
    [note]
        (Default) = "URL:Note Protocol"
        URL Protocol = ""
        [DefaultIcon]
            (Default) = "notepad.exe"
        [shell]
            [open]
                [command]
                    (Default) = "c:\windows\notepad.exe %1"
在IE 中输?note://xxx.txt 的时候会自动用notepad 打开xxx.txt 文g

2. ҎURL 协议调用cd象来处理
可以ҎURL 协议或者MIME type 注册不同的处理对?br>有两U方式:
a) 通过在注册表URL 协议与COM 对象兌
主要在注册表中的
HKEY_CLASSES_ROOT\PROTOCOLS\Handler # URL 协议
HKEY_CLASSES_ROOT\PROTOCOLS\Filter # Mime Filter

b) 通过临时注册cd象将URL 协议与其兌
// 注册
CComPtr<IInternetSession> spSession;
CComPtr<IClassFactory>   spCFHTTP;
HRESULT hr = CoInternetGetSession(0, &spSession, 0);
hr = FilterFactory::CreateInstance(CLSID_HttpProtocol, &spCFHTTP);
hr = spSession->RegisterNameSpace(spCFHTTP, CLSID_NULL, L"http", 0, 0, 0);

// 反注?br>spSession->UnregisterNameSpace(spCFHTTP, L"http");

 

3. FilterFactory 的实现可以参?br>Asynchronous Pluggable Protocol Implementation with ATL
http://www.codeguru.com/cpp/com-tech/atl/misc/article.php/c37/

Internet Explorer下蝲文g的终极过?/a>
http://blog.csdn.net/111222/archive/2002/02/09/7255.aspx

通过Mime filter技术对|页源码q行qoQ监视下载文Ӟ
http://blog.csdn.net/lion_wing/archive/2006/06/27/839134.aspx

HTML代码qo技?/a>
http://blog.csdn.net/lion_wing/articles/534716.aspx

About Asynchronous Pluggable Protocols QMSDNQ?br>
Internet Explorer ~程qͼ九)在自q览器中嵌入Google工具?/a>
http://blog.csdn.net/CathyEagle/archive/2005/12/12/550698.aspx

?000分,高手q来动手试试Q如何提取AJAX里的HTML内容Q?br>http://topic.csdn.net/t/20061214/12/5230161.html
q里主要通过监视IE 的下载从而保存Google Map 的地图数据文?  通过监视http & text/html & application/javascript 的内Ҏ获取囄文gURL ?信息.. :)




]]>
const和指针组合的变化http://m.shnenglu.com/bigsml/archive/2008/02/27/43326.html泡?/dc:creator>泡?/author>Wed, 27 Feb 2008 03:03:00 GMThttp://m.shnenglu.com/bigsml/archive/2008/02/27/43326.htmlhttp://m.shnenglu.com/bigsml/comments/43326.htmlhttp://m.shnenglu.com/bigsml/archive/2008/02/27/43326.html#Feedback0http://m.shnenglu.com/bigsml/comments/commentRss/43326.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/43326.htmla. char const* p     *p不能变,p能变Q不需要初始化
b. const char* p     同a
c. char* const p     *p能变Qp不能变,需要初始化
d. const char* const p  *p不能变,p不能变,需要初始化
d. const char const* p  *p不能变,p能变Q不需要初始化
e. const char const* const p  错误
f. char const* const p  同d



]]>
如何用Tree Control 的节?/title><link>http://m.shnenglu.com/bigsml/archive/2008/01/14/41146.html</link><dc:creator>泡?/dc:creator><author>泡?/author><pubDate>Mon, 14 Jan 2008 11:16:00 GMT</pubDate><guid>http://m.shnenglu.com/bigsml/archive/2008/01/14/41146.html</guid><wfw:comment>http://m.shnenglu.com/bigsml/comments/41146.html</wfw:comment><comments>http://m.shnenglu.com/bigsml/archive/2008/01/14/41146.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://m.shnenglu.com/bigsml/comments/commentRss/41146.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/bigsml/services/trackbacks/41146.html</trackback:ping><description><![CDATA[<p>Tree Control : how to disable an item </p> <p>Tree Control 不支持节点的用, 但是可以通过自绘实现, 主要如下:<br><br>1. 标记节点是否用. 可以?SetItemData & GetItemData 来设|?amp;获取节点数据<br><br>2. 在禁用的节点? 要过滤一些对节点操作, 如expanding, selecting, drag & drop {?<br>TVN_SELCHANGING  节点选中改变?br>TVN_ITEMEXPANDING 节点展开?br>TVN_BEGINDRAG  节点开始被拖拉<br>TVN_BEGINLABELEDIT 节点被编?/p> <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: #008000">//</span><span style="COLOR: #008000">Preventing selection: (handle TVN_SELCHANGING)</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> CYourDialog::OnSelchangingTree(NMHDR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> pNMHDR, LRESULT</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> pResult) <br>{<br>  NM_TREEVIEW</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> pNMTreeView </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (NM_TREEVIEW</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">) pNMHDR;<br>  </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(((CItemStruct </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">) m_tree.GetItemData(pNMTreeView</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">iNewItem))</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">m_bDisabled)<br>  {<br>    </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pResult </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 讄 *pResult=1 表示TVN_SELCHANGING q个操作不能l箋</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br>  }<br>  </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pResult </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> <p><br>3. 对禁用节点进行自? 用图?颜色禁用节点和其他节点q行区分 <br>a) 直接?WM_PAINT 中进行自?(或对Tree Control的绘囄果进行修?<br> 可以参? <a target=_blank>如何在树型控件中使用背景位图</a></p> <p>b) 相应 WM_OWERDRAW 事g <br> 可以参? <a target=_blank>Outlook风格的单列用不同的颜色昄新邮件数</a></p> <p><br>参?<br><a target=_blank>MFC Tree Control: How to disable an item?</a> <br><a target=_blank>Setting color and font attribute for individual items</a><br></p> <img src ="http://m.shnenglu.com/bigsml/aggbug/41146.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/bigsml/" target="_blank">泡?/a> 2008-01-14 19:16 <a href="http://m.shnenglu.com/bigsml/archive/2008/01/14/41146.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM cd厂有必要存在?/title><link>http://m.shnenglu.com/bigsml/archive/2007/11/18/36907.html</link><dc:creator>泡?/dc:creator><author>泡?/author><pubDate>Sun, 18 Nov 2007 14:53:00 GMT</pubDate><guid>http://m.shnenglu.com/bigsml/archive/2007/11/18/36907.html</guid><wfw:comment>http://m.shnenglu.com/bigsml/comments/36907.html</wfw:comment><comments>http://m.shnenglu.com/bigsml/archive/2007/11/18/36907.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://m.shnenglu.com/bigsml/comments/commentRss/36907.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/bigsml/services/trackbacks/36907.html</trackback:ping><description><![CDATA[<p>1. IClassFactory 的用?/p> <p>?<a >http://www.80diy.com/home/20041120/19/3572410.html</a> 看到几段关于COM 的类厂的? </p> <p>"""<br>cd用来抽象lg的createq程Q客户不需要知道组件的详细情况Q也不需要知道类厂的详细情况Q只要知道CoCreateInstance可以创徏lg卛_。而CoCreateInstance内部调用DllGetClassObject来生成该lg的类厂,׃cd有组件的作者撰写,所以对lgcd谓知根知底,q厂来生成lg完全行得通,q样客户和组件就q一步划分,客户只能查询该组件是否支持某借口Q而对lg的其他情况一无所知,q样的划分可以ɾlg和客户间的耦合更小?br>"""</p> <p>"""<br>lg如果某接口的全部方法都实现了,q该组件支持某接口Qcomq没有规定组件和接口之间是虚函数l承的关p,只是在c++中以q种Ҏ来实现最好而已?nbsp;  <br>IClassFactory说穿了就是专门构造组件的c,q样做是Z抽象Q因为客h有必要知道组件是什么,如果由客L接构造组Ӟ客户势必要知道组件的信息Qcom失M它的意义了,所以,规定了一个类厂(支持IClassFactory接口Q,每个lg的类厂都很清楚ƈ且也只清楚该lg的信息,而客户只需要调用com库函数CoCreateInstance可以了?nbsp;  <br>下面是流E图Q?nbsp;  <br>  CoCreateInstance -> CoGetClassObject -> DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component<br>"""</p> <p>q且?<a >http://www.codeproject.com/com/comintro2.asp</a> 也看到几D话</p> <p>"""<br>每次实现lg对象cȝ时候,都要写一个旁c负责创建第一个组件对象类的实例。这个旁cd叫这个组件对象类的类工厂Qclass factoryQ,其唯一目的是创建COM对象。之所以要一个类工厂Q是因ؓ语言无关的缘故。COM本nq不创徏对象Q因为它不是独立于语a的也不是独立于实现的?<br>当某个客L惌创徏一个COM对象ӞCOM库就从COM服务器请求类工厂。然后类工厂创徏COM对象q将它返回客L。它们的通讯机制由函数DllGetClassObject()来提供?br>"""</p> <p>?lt;COM 技术内q?gt; ? 对类厂的引入也有描述. <br>主要?<br>a. 在面向对象系l中, 对象创徏是非帔R要的, 因ؓ要用它必须先创建它. 所以尽可能灉|的创建对?component)<br>b. 在CoCreateInstance 创徏对象q程? 传给一共CLSID, 然后创徏成相应组? q返回所h的指? 其弊端在于无法提供给客户一U控制对象创E的Ҏ. (问题关键不在初始? 而是控制创徏对象q程)<br>c. IClassFactory2 成批的调用接? </p> <p><br>2. <br>参考CoCreateInstance 的实现过E? <br>CoCreateInstance -> CoGetClassObject -[pȝ|lg代码]-> DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component</p> <p>因ؓ DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component 都是lg所来实现的, 而系l调?CoCreateInstance 所提供的参? 和通过自己使用IClassFactory 来创建Component 的参数是没有变化? 所以如果省?ClassFactory 应该也可? </p> <p>CoCreateInstance -> CoGetClassObject -[pȝ|lg代码]-> DllGetClassObject -> new Component </p> <p>DllGetClassObject 完全可以完成<COM 技术内q说?gt; a. 灉|创徏对象, b. 控制创徏q程, c. IClassFactory2 , 而且q样子的实现也与语言无关.  <br>所以感觉没有必要一定要用到IClassFactory q个接口</p> <p><br>3. <br>因此在实现的时? 完全可以q样子的实现lg<br>CCoClass : public IA, public IB, public IClassFactory <br>{<br>......<br>}</p> <p>DllGetClassObject()<br>{<br>new CCoClass<br>}</p> <p>而不需要额外的用一个类单独的去实现IClassFactory . 好像ATL 默认的就是这么干? 提供了一个CComCoClass<CCoClass, &CLSID_CCoClass)  实现c? </p> <p>q个是我的对COM 的IClassFactory 的理? 感觉没必要多一个这个东? <br><br>不知道大家是如何看待q个东西?) </p> <p><br> </p> <img src ="http://m.shnenglu.com/bigsml/aggbug/36907.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/bigsml/" target="_blank">泡?/a> 2007-11-18 22:53 <a href="http://m.shnenglu.com/bigsml/archive/2007/11/18/36907.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>H口的子cd与超cdhttp://m.shnenglu.com/bigsml/archive/2007/08/24/30780.html泡?/dc:creator>泡?/author>Fri, 24 Aug 2007 10:58:00 GMThttp://m.shnenglu.com/bigsml/archive/2007/08/24/30780.htmlhttp://m.shnenglu.com/bigsml/comments/30780.htmlhttp://m.shnenglu.com/bigsml/archive/2007/08/24/30780.html#Feedback3http://m.shnenglu.com/bigsml/comments/commentRss/30780.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/30780.html1. 子类?
改变一个已l存在的H口实例的性质Q消息处理与其他实例属性?/strong>
在SDK~程范畴内,子类化就是改变一个窗口实例的H口函数Q通过GetWindowLong()和SetWindowLong()Q,子类化所要做的就是ؓ某窗口实例编写新的窗口函数。其操作是在实例U别上进行的?br>在MFC中子cd的情冉|所不同Q所有MFCH口有相同的H口函数Q由该窗口函数根据窗口句柄查扄口实例,在把消息映射到该H口c(classQ得消息处理函数上。ؓ了利用MFC的消息映机Ӟ不宜改变H口函数Q名Q,MFC也把子类化封装在函数SubclassWindowQ)中。但子类化的本质没有变:在实例别媄响窗口的消息及其处理。例Q?br>Class  B Qpublic A
{
  ……
}
A  a;
B  b;
HWND ha=a.GetSafeHwnd();
b.SubclassWindow(ha); #当然A 和B 不一定是l承关系?br>注意Q在被子cd的窗口销毁之前,必须执行H口的反子类化:
b.UnSubclassWindow();


2 类?br>H口类化是在窗口类——WNDCLASS或WNDCLASSEXQ非MFCcL念)U别q行的改变窗口类特征?/strong>?br>使用q程Q首先获得一个已存在的窗口类Q然后设|窗口类Q最后注册该H口cR?br>例:
WNDCLASSEX  wc;
wc.cbSize=sizeof(wc); //Windows用来q行版本查的Q与H口特征无关
GetClassInfoEx(hinst,”XXXXXX”,&wc);
 // hinst—定义窗口类XXXXXX的模块的句柄Q如为系l定义的H口c(如:EDIT、BUTTONQ则hinst=NULL.?
wc.lpszClassName = “YYYYYYY”;//必须改变H口cȝ名字
wc.hbrBackGround = CreateSolidBrush(RGB(0,0.0));//改变背景?
wc.lpfnWndProc = NewWndProc;//改变H口函数
……
RegisterClassEx(&wc);// 注册新窗口类
//使用H口c?
……
::CreateWindow(_T(“YYYYYYYY”,……)Q?

故超cd只能改变自己创徏的窗口的特征Q而不能用于由Windows创徏的窗口(如对话框上的按钮׃能进行超cdQ?。而子cd是实例别上的,只要能获得窗口的实例Q就可对其子cdQ这是唯一的子cd对于类化的优势。另外,凡是子类化可实现的,类化都可实玎ͼ不过类化用h较麻烦?


3. ȝ

Q?Q?子类化修改窗口过E函?  类化修改窗口类(新的H口cd)
Q?Q?子类化是在窗口实例别上的,类化是在窗口类QWNDCLASSQ别上的?
Q?Q?类化可以完成比子类化更复杂的功能,在SDK范畴上,可以认ؓ子类化是类化的子集?
Q?Q?子类化只能改变窗口创建后的性质Q对于窗口创建期间无能ؓ?无法截获ON_CREATE 事g)Q而超cd可以实现Q超cd不能用于Windows创徏的窗口,子类化可以?nbsp;


4. 其他
?D为实(2)Q介lWindows的窗口、消息、子cd和超cd q里有一个例?.
可以得出l论
a) 子类化的classname 是不会变化的, 而超cd使用新注册classname
b) 子类?& 类?描述的是一个动?和实现方法没什么关p?.... 主要是子cd是SubclassWindow, SubclassDlgItem, 而超cd是RegisterClassEx(&newwindowclass)
c) 感觉具体没有必要区分q些, 实现功能p? 呵呵




]]>
Some DirectShow Samples Break in Visual Studio 2005http://m.shnenglu.com/bigsml/archive/2007/06/26/26978.html泡?/dc:creator>泡?/author>Tue, 26 Jun 2007 03:07:00 GMThttp://m.shnenglu.com/bigsml/archive/2007/06/26/26978.htmlhttp://m.shnenglu.com/bigsml/comments/26978.htmlhttp://m.shnenglu.com/bigsml/archive/2007/06/26/26978.html#Feedback2http://m.shnenglu.com/bigsml/comments/commentRss/26978.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/26978.htmlzt: http://blogs.msdn.com/mikewasson/archive/2005/05/23/some-directshow-samples-break-in-visual-studio-2005.aspx

DirectX 9.0 ?VS 2005 之间存在冲突, 主要因ؓVS 2005 的语法比VC6 & VS2003 更加严格, 所以一些DirectX 自带的代码需要更改以后才能编译通过. 本来惌己改? 不过在网上发C有h已经做了q个:)


[Note: This post applies to the Platform SDK for Windows Server 2003 SP1 and Server 2003 R2. These issues were fixed in the Windows SDK for Vista.]  

Some of the DirectShow samples break if you install Visual Studio 2005 Beta 2. Most of the errors that I found fall into three categories:

  • C4430: Missing type specifier. To conform with C++, undeclared types do not default to int. All types must be declared. Fix: Declare the type, or suppress the warning with the "/wd4430" flag.
  • C4996: ' xxxx' was declared deprecated. You may be including an older version of strsafe.h from the DirectX SDK or the Platform SDK. You should include the version installed with Visual Studio. (But it's probably harmless to ignore this warning.) 
  • C2065: 'xxx': undeclared identifier. To conform with C++, the scope of a variable declared inside a "for" loop is restricted to the loop. Fixes: (a) Move the declaration outside the for loop. (b) Redeclare the variable in multiple scopes, if you don't need it to persist outside the loop. (c) Set the /Zc:forScope flag. (You can find this under Project, Properties, Configuration Properties, C/C++, Language, Force Conformance In For Loop Scope. Set to "No".)

Here are the specific fixes that I made. Warning: I have not thoroughly tested these, and I only tried them under the "Windows XP 32-bit Debug" environment in Platform SDK. You should use your own judgment before making any of these fixes.

  • BaseClasses\ctlutil.h (278)  
        (LONG) operator=(LONG);
  • BaseClasses\wxdebug.cpp (564)
        static DWORD g_dwLastRefresh = 0;
  • BaseClasses\winutil.cpp (2092)
       UINT Count;
       for (Count = 0;Count < Result;Count++) {
  •  BaseClasses\outputq.cpp (635)
       long iDone = 0;
       for (iDone = 0;
  • Capture\AmCap\amcap.cpp (691)
        for(int i = 0; i < NUMELMS(gcap.rgpmAudioMenu); i++)
  • Capture\AmCap\amcap (2795)
        for(int i = 0; i < NUMELMS(gcap.rgpmAudioMenu); i++)
  • DMODemo\dsutil.cpp (686)
        DWORD i = 0;
        for( i=0; i<m_dwNumBuffers; i++ )
  • dmoimpl.h (622)   [In the Platform SDK headers]
        for (DWORD dw = 0; dw < NUMBEROFOUTPUTS; dw++) {
  • DMO\GargleDMO\MedParamBase\param.cpp (91)
        for (DWORD dwIndex = 0; dwIndex < cParams; dwIndex++)
  • DMO\GargleDMO\MedParamBase\param.cpp (309)
        CCurveItem *pCurve = NULL;
        for (pCurve = pCurveHead;
  • DMO\GargleDMO\gargle.cpp (145)
        for (DWORD i = 0; i < cOutputStreams && SUCCEEDED(hr); ++i)
  • Filters\Dump\dump.cpp (426)
        for (int Loop = 0;Loop < (DataLength % BYTES_PER_LINE);Loop++)
  • Filters\Gargle\gargle.cpp (212)
        static int m_nInstanceCount; // total instances
  • Filters\RGBFilters\RateSource\ratesource.cpp (382)
        for( int y = 0 ; y < DEFAULT_HEIGHT ; y++ )
  • Filters\RGBFilters\RateSource\ratesource.cpp (387)
        for( int y = 0 ; y < DEFAULT_WIDTH ; y++ )
  • VMR\VMRXclBasic and VMR\Ticker: LNK1181: cannot open input file 'dxguid.lib'. This was an error in the makefile. Change to read:
        DXLIB="$(DXSDK_DIR)\Lib\x86"  (currently says "x32")
  • VMR\VMRXcl and VMR\VMRMulti: C1083: Cannot open include file: 'd3dxmath.h': No such file or directory. This is an old DX header that is no longer included in DX or in Visual Studio. Unfortunately the only fix is to download an older version of the DirectX SDK.
  • VMR9\MultiVMR9\GamePlayer\character.cpp (383)
        DWORD i = 0;
        for (i = 0; i < pMeshContainer->NumInfl; ++i)
  • VMR9\MultiVMR9\DLL\MixerControl.h (28)
        static const DWORD MultiVMR9Mixer_DefaultFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
  • VMR9\VMRAllocator: error LNK2019: unresolved external symbol "wchar_t * __stdcall _com_util::ConvertStringToBSTR(char const *)" (etc).  Add this to the makefile:
        LINK32_LIBS = \
        comsuppw.lib \
        shell32.lib \

 



]]>
利用IE 实现Web 面截图http://m.shnenglu.com/bigsml/archive/2007/06/10/25983.html泡?/dc:creator>泡?/author>Sun, 10 Jun 2007 10:55:00 GMThttp://m.shnenglu.com/bigsml/archive/2007/06/10/25983.htmlhttp://m.shnenglu.com/bigsml/comments/25983.htmlhttp://m.shnenglu.com/bigsml/archive/2007/06/10/25983.html#Feedback2http://m.shnenglu.com/bigsml/comments/commentRss/25983.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/25983.html1. 目的

   在Codeproject 中看到有人做q个,  E微做了下修? 做成了命令行? 使用Ҏ?nbsp;
   iesnap.exe url filename
      用以抓取 URL 对于的Web, q且Web 的截图保存在Filename ?
      url : 要截囄|址
      filename: 截图保存文g?br>       
2. 思\
   
 主要使用WebBrowser Control ?MSHTML 来完?
 a. 创徏WebBrowser control
 b. 从WebBrowser Control 获取 IWebBrowser2 接口, ?IWebBrowser2::Navigate2 来访问URL
 c. 获得IHTMLElementRender (WebBrowser -> IHTMLDocument2 -> IHTMLElement -> IHTMLElementRender), 使用该接口的DrawToDC 来获取URL 对应的页面截囑ֆ?
 d. 用GDI ?Image 来保存截囑ֈFilename

3. 
   可以看看原文以得到更好的解答   
   我看的那个文? Capture an HTML document as an image
   另外一C# 的文? Image Capture Whole Web Page using C#


4. 问题
       
 a. DocumentComplete 事g会在URL 对应面的每个元素下载完毕的时候都会发? 所?( q不知道哪个事g是整个页面下载完毕的事g:/
 b. 现在是通过MFC 来创建WebBrowser Control ? 不知道怎么在Win32 Application 中创个控?
 c. 不知道如何得到整个页面的大小, 现在只能保存面截图的一部分:(
   q个已经知道怎么做了. 
   IHTMLElement2 ?scrollWidth & scrollHeight 加上 scrollLeft & scrollTop 来实? 但是不知道ؓ什? put_scrollTop & put_scrollLeft q些函数好像不对, 只能截获C部分面截图.:( 不知道ؓ什?br>   


 代码可以在这里下? http://m.shnenglu.com/Files/bigsml/iesnapshot.zip



]]>
YC 览?/title><link>http://m.shnenglu.com/bigsml/archive/2007/04/25/22808.html</link><dc:creator>泡?/dc:creator><author>泡?/author><pubDate>Wed, 25 Apr 2007 09:07:00 GMT</pubDate><guid>http://m.shnenglu.com/bigsml/archive/2007/04/25/22808.html</guid><wfw:comment>http://m.shnenglu.com/bigsml/comments/22808.html</wfw:comment><comments>http://m.shnenglu.com/bigsml/archive/2007/04/25/22808.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://m.shnenglu.com/bigsml/comments/commentRss/22808.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/bigsml/services/trackbacks/22808.html</trackback:ping><description><![CDATA[<p>q款览?UC为Yang C/C++ Compiler & Internet Browser或者YC~译型浏览器..<br><br>最开始是在程序员看到相关的文章的, 开始以为是在吹..但是今天用他的程序的时? 感觉真的很nb..<br><br>"""<br>记者在杨晓兵处观摩了该产品的演C?发现它是由如下五个部分组成:HTML解析器;XML解析器(目前完成一部分Q;javascript脚本解释?C/C++脚本解释器;C/C++~译器;文本及二q制~辑?其中最令h瞩目的功?自然是他所内嵌的C/C++实时~译功能?q样使得C/C++的运行效果看上去cM动态语a,它不仅得HTML支持脚本化的标准C/C++语言,而且使得C/C++ 能够与象JacaScriptq样的动态语a可以互相调用.杨晓兵说“q将是Y件开发方式的革新.通过q个实时~译功能,每个软g可以同时分割成若q模?怺之间可以独立q行.”该编译器,与主的C/C++~译器相?YC++在功能进行了一些删减和改良,比如L了标准C/C++的函数重载、运符重蝲、模板等,而改良的方向,主要侧重增加与网开发环境(HTML4.0、CSS2.JavaScriptQ的互相支持和调?令h颇感意外的是,该品包括编译器、HTML解析器等在内的五个模块的所有代?都与由杨晓兵独自一个h用C语言开发完?从未借鉴参考Q何其他源代码.杨晓兵解释说主要是ؓ了便于调试和控制.q是相当大的工作?整整׃他六q时?从演C的q行效果来看,q款׃人手工完成的作品,~译速度竟然比VC++q要快一?据透露是源自其许多法的优?如专门ؓ变量参数作了可供快速查扄字典表等.<br>"""<br><br><br>在用的时? 发现整个览器没有用一个Windows 控g, 所有的控g都是qGDI U来l制成的... 包括菜单, 输入? 按钮, 树Ş控g{等{?br><br>Orz... 一?br><br>可以在这里下载试? 解压~?个压~包p?<br><a href="http://m.shnenglu.com/Files/bigsml/setyc.part01.rar">/Files/bigsml/setyc.part01.rar</a><br><a href="http://m.shnenglu.com/Files/bigsml/setyc.part02.rar">/Files/bigsml/setyc.part02.rar</a><br><a href="http://m.shnenglu.com/Files/bigsml/setyc.part03.rar">/Files/bigsml/setyc.part03.rar</a></p> <img src ="http://m.shnenglu.com/bigsml/aggbug/22808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/bigsml/" target="_blank">泡?/a> 2007-04-25 17:07 <a href="http://m.shnenglu.com/bigsml/archive/2007/04/25/22808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用BoundsChecker内存泄?(zz) http://m.shnenglu.com/bigsml/archive/2006/10/19/13860.html泡?/dc:creator>泡?/author>Thu, 19 Oct 2006 05:45:00 GMThttp://m.shnenglu.com/bigsml/archive/2006/10/19/13860.htmlhttp://m.shnenglu.com/bigsml/comments/13860.htmlhttp://m.shnenglu.com/bigsml/archive/2006/10/19/13860.html#Feedback2http://m.shnenglu.com/bigsml/comments/commentRss/13860.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/13860.html
  q里我们以malloc函数ZQ截获其他的函数Ҏ与此cM?br />
  需要被截获的函数可能在DLL中,也可能在E序的代码里。比如,如果静态连lC-Runtime LibraryQ那么malloc函数的代码会被连l到E序里。ؓ了截获住对这cd数的调用QBoundsChecker会动态修改这些函数的指o?br />
  以下两段汇编代码Q一D|有BoundsChecker介入Q另一D则有BoundsChecker的介入:
126: _CRTIMP void * __cdecl malloc (
127: size_t nSize
128: )
129: {

00403C10 push ebp
00403C11 mov ebp,esp
130return _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);
00403C13 push 
0
00403C15 push 
0
00403C17 push 
1
00403C19 mov eax,[__newmode (0042376c)]
00403C1E push eax
00403C1F mov ecx,dword ptr [nSize]
00403C22 push ecx
00403C23 call _nh_malloc_dbg (00403c80)
00403C28 add esp,14h
131: }
以下q一D代码有BoundsChecker介入Q?br />
126: _CRTIMP void * __cdecl malloc (
127: size_t nSize
128: )
129: {

00403C10 jmp 01F41EC8
00403C15 push 
0
00403C17 push 
1
00403C19 mov eax,[__newmode (0042376c)]
00403C1E push eax
00403C1F mov ecx,dword ptr [nSize]
00403C22 push ecx
00403C23 call _nh_malloc_dbg (00403c80)
00403C28 add esp,14h
131: }

  当BoundsChecker介入后,函数malloc的前三条汇编指o被替换成一条jmp指oQ原来的三条指o被搬到地址01F41EC8处了。当E序q入malloc后先jmp?1F41EC8Q执行原来的三条指oQ然后就是BoundsChecker的天下了。大致上它会先记录函数的q回地址Q函数的q回地址在stack上,所以很Ҏ修改Q,然后把返回地址指向属于BoundsChecker的代码,接着跛_malloc函数原来的指令,也就是在00403c15的地斏V当malloc函数l束的时候,׃q回地址被修改,它会q回到BoundsChecker的代码中Q此时BoundsChecker会记录由malloc分配的内存的指针Q然后再跌{到到原来的返回地址厅R?br />
  如果内存分配/释放函数在DLL中,BoundsChecker则采用另一U方法来截获对这些函数的调用。BoundsChecker通过修改E序的DLL Import Table让table中的函数地址指向自己的地址Q以辑ֈ截获的目的?br />
  截获住这些分配和释放函数QBoundsCheckerp记录被分配的内存或资源的生命周期。接下来的问题是如何与源代码相关Q也是说当BoundsChecker到内存泄漏Q它如何报告q块内存块是哪段代码分配的。答案是调试信息QDebug InformationQ。当我们~译一个Debug版的E序Ӟ~译器会把源代码和二q制代码之间的对应关p记录下来,攑ֈ一个单独的文g?.pdb)或者直接连l进目标E序Q通过直接d调试信息p得到分配某块内存的源代码在哪个文Ӟ哪一行上。用Code Injection和Debug InformationQBoundsChecker不但能记录呼叫分配函数的源代码的位置Q而且q能记录分配时的Call StackQ以及Call Stack上的函数的源代码位置。这在用像MFCq样的类库时非常有用Q以下我用一个例子来说明Q?br />
void ShowXItemMenu()
{
 ?br /> CMenu menu;

 menu.CreatePopupMenu();
 
//add menu items.
 menu.TrackPropupMenu();
 ?br />}

void ShowYItemMenu( )
{
 ?br /> CMenu menu;
 menu.CreatePopupMenu();
 
//add menu items.
 menu.TrackPropupMenu();
 menu.Detach();
//this will cause HMENU leak
 ?br />}

BOOL CMenu::CreatePopupMenu()
{
 ?br /> hMenu 
= CreatePopupMenu();
 ?br />}
当调用ShowYItemMenu()Ӟ我们故意造成HMENU的泄漏。但是,对于BoundsChecker来说被泄漏的HMENU是在class CMenu::CreatePopupMenu()中分配的。假讄你的E序有许多地方用了CMenu的CreatePopupMenu()函数Q如CMenu::CreatePopupMenu()造成的,你依然无法确认问题的根结到底在哪里,在ShowXItemMenu()中还是在ShowYItemMenu()中,或者还有其它的地方也用了CreatePopupMenu()Q有了Call Stack的信息,问题容易了。BoundsChecker会如下报告泄漏的HMENU的信息:
Function
File
Line

CMenu::CreatePopupMenu
E:\
8168\vc98\mfc\mfc\include\afxwin1.inl
1009

ShowYItemMenu
E:\testmemleak\mytest.cpp
100
  
q里省略了其他的函数调用

如此Q我们很Ҏ扑ֈ发生问题的函数是ShowYItemMenu()。当使用MFC之类的类库编E时Q大部分的API调用都被装在类库的class里,有了Call Stack信息Q我们就可以非常Ҏ的追t到真正发生泄漏的代码?br />
  记录Call Stack信息会ɽE序的运行变得非常慢Q因此默认情况下BoundsChecker不会记录Call Stack信息。可以按照以下的步骤打开记录Call Stack信息的选项开养I

  1. 打开菜单QBoundsChecker|Setting?

  2. 在Error Detection中Q在Error Detection Scheme的List中选择Custom

  3. 在Category的Combox中选择 Pointer and leak error check

  4. 钩上Report Call Stack复选框

  5. 点击Ok

  ZCode InjectionQBoundsCheckerq提供了API Parameter的校验功能,memory over run{功能。这些功能对于程序的开发都非常有益。由于这些内容不属于本文的主题,所以不在此详述了?br />
  管BoundsChecker的功能如此强大,但是面对隐式内存泄漏仍然昑־苍白无力。所以接下来我们看看如何用Performance Monitor内存泄漏?br />
  使用Performance Monitor内存泄?br />
  NT的内核在设计q程中已l加入了pȝ监视功能Q比如CPU的用率Q内存的使用情况QI/O操作的频J度{都作ؓ一个个CounterQ应用程序可以通过dq些Counter了解整个pȝ的或者某个进E的q行状况。Performance Monitor是q样一个应用程序?br />
  Z内存泄漏,我们一般可以监视Process对象的Handle CountQVirutal Bytes 和Working Set三个Counter。Handle Count记录了进E当前打开的HANDLE的个敎ͼ监视q个Counter有助于我们发现程序是否有Handle泄漏QVirtual Bytes记录了该q程当前在虚地址I间上用的虚拟内存的大,NT的内存分配采用了两步走的ҎQ首先,在虚地址I间上保留一D늩_q时操作pȝq没有分配物理内存,只是保留了一D地址。然后,再提交这D늩_q时操作pȝ才会分配物理内存。所以,Virtual Bytes一般d于程序的Working Set。监视Virutal Bytes可以帮助我们发现一些系l底层的问题; Working Set记录了操作系lؓq程已提交的内存的总量Q这个值和E序甌的内存总量存在密切的关p,如果E序存在内存的泄漏这个g持箋增加Q但是Virtual Bytes却是跌式增加的?br />
  监视q些Counter可以让我们了解进E用内存的情况Q如果发生了泄漏Q即使是隐式内存泄漏Q这些Counter的g会持l增加。但是,我们知道有问题却不知道哪里有问题Q所以一般用Performance Monitor来验证是否有内存泄漏Q而用BoundsChecker来找到和解决?br />
  当Performance Monitor昄有内存泄漏,而BoundsChecker却无法检到Q这时有两种可能Q第一U,发生了偶发性内存泄漏。这时你要确保用Performance Monitor和用BoundsCheckerӞE序的运行环境和操作Ҏ是一致的。第二种Q发生了隐式的内存泄漏。这时你要重新审查程序的设计Q然后仔l研IPerformance Monitor记录的Counter的值的变化图,分析其中的变化和E序q行逻辑的关p,扑ֈ一些可能的原因。这是一个痛苦的q程Q充满了假设、猜惟뀁验证、失败,但这也是一个积累经验的l好Z?br />
  ȝ

  内存泄漏是个大而复杂的问题Q即使是Java?Netq样有Gabarge Collection机制的环境,也存在着泄漏的可能,比如隐式内存泄漏。由于篇q和能力的限Ӟ本文只能对这个主题做一个粗的研究。其他的问题Q比如多模块下的泄漏,如何在程序运行时对内存用情况进行分析等{,都是可以深入研究的题目。如果您有什么想法,或发C某些错误Q欢q和我交?




]]>
C语言中可变参数的用法 http://m.shnenglu.com/bigsml/archive/2006/10/19/13859.html泡?/dc:creator>泡?/author>Thu, 19 Oct 2006 04:55:00 GMThttp://m.shnenglu.com/bigsml/archive/2006/10/19/13859.htmlhttp://m.shnenglu.com/bigsml/comments/13859.htmlhttp://m.shnenglu.com/bigsml/archive/2006/10/19/13859.html#Feedback1http://m.shnenglu.com/bigsml/comments/commentRss/13859.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/13859.html
* 1. 可变参数的宏

一般在调试打印Debug 信息的时? 需要可变参数的? 从C99开始可以ɾ~译器标准支持可变参数宏(variadic macros), 另外GCC 也支持可变参数宏, 但是两种在细节上可能存在区别.

1. __VA_ARGS__

__VA_ARGS__ ?..." 传递给??br />#define debug(format, ...) fprintf(stderr, fmt, __VA_ARGS__)

在GCC中也支持q类表示, 但是在G++ 中不支持q个表示.

2. GCC 的复杂宏

GCC使用一U不同的语法从而可以你可以给可变参数一个名字,如同其它参数一栗?br />#define debug(format, args...) fprintf (stderr, format, args)

q和上面丄那个定义的宏例子是完全一LQ但是这么写可读性更强ƈ且更Ҏq行描述?br />
3. ##__VA_ARGS__

上面两个定义的宏, 如果出现debug("A Message") 的时? ׃宏展开后有个多余的逗号, 所以将D~译错误. Z解决q个问题QCPP使用一个特D的?#’操作?br />
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
q里Q如果可变参数被忽略或ؓI,?#’操作将佉K处理器(preprocessorQ去除掉它前面的那个逗号。如果你在宏调用Ӟ实提供了一些可变参敎ͼGNU CPP也会工作正常Q它会把q些可变参数攑ֈ逗号的后面?br />
4. 其他Ҏ

一U流行的技巧是用一个单独的用括弧括h的的 "参数" 定义和调用宏, 参数在宏扩展的时候成为类?printf() 那样的函数的整个参数列表?
#define DEBUG(args) (printf("DEBUG: "), printf(args))


* 2. 可变参数的函?

写可变参数的C函数要在E序中用C下这些宏:
void va_start( va_list arg_ptr, prev_param )
type va_arg( va_list arg_ptr, type )
void va_end( va_list arg_ptr )

va在这里是variable-argument(可变参数)的意?q些宏定义在stdarg.h?下面我们写一个简单的可变参数的函?该函数至有一个整数参?W二个参C是整?是可选的.函数只是打印q两个参数的?
void simple_va_fun(int i, ...)
{
    va_list arg_ptr;
    int j=0;
    
    va_start(arg_ptr, i);
    j=va_arg(arg_ptr, int);
    va_end(arg_ptr);
    printf("%d %d\n", i, j);
    return;
}

在程序中可以q样调用:
simple_va_fun(100);
simple_va_fun(100,200);

从这个函数的实现可以看到,使用可变参数应该有以下步?
1)首先在函数里定义一个va_list型的变量,q里是arg_ptr,q个变量是指向参数的指针.
2)然后用va_start宏初始化变量arg_ptr,q个宏的W二个参数是W一个可变参数的前一个参?是一个固定的参数.
3)然后用va_argq回可变的参?q赋值给整数j. va_arg的第二个参数是你要返回的参数的类?q里是int?
4)最后用va_end宏结束可变参数的获取.然后你就可以在函数里使用W二个参C.如果函数有多个可变参数的,依次调用va_arg获取各个参数.

如果我们用下面三U方法调用的?都是合法?但结果却不一?
1)simple_va_fun(100);
l果?100 -123456789(会变的?
2)simple_va_fun(100,200);
l果?100 200
3)simple_va_fun(100,200,300);
l果?100 200

我们看到W一U调用有错误,W二U调用正?W三U调用尽结果正?但和我们函数最初的设计有冲H?下面一节我们探讨出现这些结果的原因和可变参数在~译器中是如何处理的.
* 3. 可变参数函数原理

va_start,va_arg,va_end是在stdarg.h中被定义成宏?׃gq_的不?~译器的不同,所以定义的宏也有所不同,下面以VC++中stdarg.h里x86q_的宏定义摘录如下:

typedef char * va_list;
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )

定义_INTSIZEOF(n)主要是ؓ了内存对?C语言的函数是从右向左压入堆栈?设数据进栈方向ؓ从高地址向低地址发展,即首先压入的数据在高地址). 下图是函数的参数在堆栈中的分布位|?

低地址    |-----------------------------|<-- &v
        |Wn-1个参?最后一个固定参?|
        |-----------------------------|<--va_start后ap指向
        |Wn个参?W一个可变参? |
        |-----------------------------|
        |....... |
        |-----------------------------|
        |函数q回地址 |
高地址  |-----------------------------|

1. va_list 被定义ؓchar *
2. va_start 地址ap定义?&v+_INTSIZEOF(v),?amp;v是固定参数在堆栈的地址,所以va_start(ap, v)以后,ap指向W一个可变参数在堆栈的地址
3. va_arg 取得cdt的可变参数?以int型ؓ?va_arg取int型的q回?
   j= ( *(int*)((ap += _INTSIZEOF(int))-_INTSIZEOF(int)) );
4. va_end 使ap不再指向堆栈,而是跟NULL一?q样~译器不会ؓva_end产生代码.

在不同的操作pȝ和硬件^台的定义有些不同,但原理却是相似的.


* 4. 结

对于可变参数的函?因ؓva_start, va_arg, va_end{定义成?所以它昑־很愚?可变参数的类型和个数需要在该函Cq序代码控?另外,~译器对可变参数的函数的原型查不够严?对编E查错不?
所以我们写一个可变函数的C函数?有利也有?所以在不必要的场合,无需用到可变参数.如果在C++?我们应该利用C++的多态性来实现可变参数的功?量避免用C语言的方式来实现.


* 5. 附一些代?br />
#define debug(format, ...) fprintf(stderr, fmt, __VA_ARGS__)
#define debug(format, args...) fprintf (stderr, format, args)
#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

// 使用va... 实现
void debug(const char *fmt, ...)
{
    int nBuf;
    char szBuffer[1024];
    va_list args;

    va_start(args, fmt);
    nBuf = vsprintf(szBuffer, fmt, args) ;
    assert(nBuf >= 0);

    printf("QDOGC ERROR:%s\n",szBuffer);
    va_end(args);
}



]]>
通过例子学习 CPPUnit http://m.shnenglu.com/bigsml/archive/2006/10/18/13836.html泡?/dc:creator>泡?/author>Wed, 18 Oct 2006 12:59:00 GMThttp://m.shnenglu.com/bigsml/archive/2006/10/18/13836.htmlhttp://m.shnenglu.com/bigsml/comments/13836.htmlhttp://m.shnenglu.com/bigsml/archive/2006/10/18/13836.html#Feedback0http://m.shnenglu.com/bigsml/comments/commentRss/13836.htmlhttp://m.shnenglu.com/bigsml/services/trackbacks/13836.html
class SimpleCalcTest : public CPPUNIT_NS::TestFixture
{
    CPPUNIT_TEST_SUITE( SimpleCalcTest );
    CPPUNIT_TEST( testAdd );
    CPPUNIT_TEST( testSub );
    CPPUNIT_TEST( testMul);
    CPPUNIT_TEST( testDiv );
    CPPUNIT_TEST_SUITE_END();

private :
    SimpleCalculator 
* sc;

public:
    
virtual void setUp()
    {
        sc 
= new SimpleCalculator();
    }
    
virtual void tearDown()
    {
        delete sc;
    }

    
void testAdd(){
        CPPUNIT_ASSERT_EQUAL( sc
->add(5,6), 11);
    }

    
void testSub(){
        CPPUNIT_ASSERT_EQUAL( sc
->sub(5,6), -1 );
    }

    
void testMul(){
        CPPUNIT_ASSERT_EQUAL( sc
->mul(5,6), 30 );
    }

    
void testDiv(){
        CPPUNIT_ASSERT_EQUAL( sc
->div(12,6), 2 );
    }
};

// 把这个TestSuite注册到名字ؓ"alltest"的TestSuite? 如果没有定义会自动定?br />// 也可以CPPUNIT_TEST_SUITE_REGISTRATION( MathTest );注册到全局的一个未命名的TestSuite?
CPPUNIT_TEST_SUITE_REGISTRATION( SimpleCalcTest, "alltest" );

int main()
{
    CPPUNIT_NS::TestResult r;
    CPPUNIT_NS::TestResultCollector result;
    r.addListener( 
&result );
    
    
// 从注册的TestSuite中获取特定的TestSuite, 没有参数获取全局的未命名的TestSuite.
    CPPUNIT_NS::TestFactoryRegistry::getRegistry("alltest").makeTest()->run( &r );
    CPPUNIT_NS::TextOutputter 
out&result, std::cout );
    
out.write();
    
return 0;
}

从上面的代码可以看到, 使用CPPUnit 主要是两个步?
1. 创徏TestSuite
首先从CPPUNIT_NS::TestFixture 生成一个子c? 然后用宏 CPPUNIT_TEST_SUITE, CPPUNIT_TEST, CPPUNIT_TEST_SUITE_END 来定义要试的各个小单元, q且实现CPPUNIT_TEST 中定义的cd? 在每个类函数中?CPPUNIT_ASSERT, CPPUNIT_ASSERT_MESSAGE, CPPUNIT_FAIL, CPPUNIT_ASSERT_EQUAL, CPPUNIT_ASSERT_EQUAL_MESSAGE, CPPUNIT_ASSERT_DOUBLES_EQUAL {来对结果进行断a.

然后通过?CPPUNIT_TEST_SUITE_REGISTRATION 测试类注册到TestSuite?

2. Main
在mainE序中对TestSuite q行试.


CPPUnit的更详细的资料可以查?
IBM ?便利的开发工?CppUnit 快速用指?/a>  比较详细的介l了CppUnit
VCKBase?
CppUnit试框架入门 详细的介l了VC6下MFC Dialog下的CPPUnit的?br />CSDN ?如何使用CppUnit做单元测?/a> 介绍了VC6的MFC 下的CPPUnit的? 和VCKBase的实现稍微有点差?br />Meng Yan ( 孟岩 ) 的文?CPPUnit Lite 对CPPUnit的用和宏进行了单的分析





]]>
žžþþƷ| þùŷպƷ| 99þѹۺϾƷ| þAVӰ| Ʒþþþþù˽ | þþþƷ| ޾ҹþþþþ| þþ޾Ʒһ| ޹Ʒ˾þ| þۺϾþۺϾɫ| þۺϳDž| þþƷ2020| պþӰԺ| պ뾫Ʒþþò| þþ91Ʒһ| þĻƵ| þþƷAVɫ| Ʒþþþ| þۺŷ| AV˾þԭ| Ʒþþþþø | avɫۺϾþavɫۺ| ƷۺϾþĻ| ŷպƷþþþ | Ʒþþþþһ | ŷղþ99| þۺϺݺɫۺ| ŮHҳþþ| ҹƷþþþþþ| ޾Ʒþ| ޹Ʒþһ | רþ| ޹Ʒþþþþ| þùƷһ| þþƷҹɫA| ƷþþþӰ| þþƷ޾Ʒɫ| 㽶þۺӰ| þAVĻ| þˬƬav| þֻоƷҳ|